This is an automated email from the ASF dual-hosted git repository. marat pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
commit 621685f6edc3b4b7227c95704c8c15deeeed32e2 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Tue Feb 20 17:54:13 2024 -0500 Less diagramm rendering on properties changes for #731 --- karavan-designer/public/example/demo.camel.yaml | 130 ++++++++++----------- karavan-designer/src/App.tsx | 2 +- .../property/property/ComponentPropertyField.tsx | 94 +++++++++++---- .../property/property/DslPropertyField.tsx | 90 +++++++++----- 4 files changed, 200 insertions(+), 116 deletions(-) diff --git a/karavan-designer/public/example/demo.camel.yaml b/karavan-designer/public/example/demo.camel.yaml index 28340ccf..f568f58b 100644 --- a/karavan-designer/public/example/demo.camel.yaml +++ b/karavan-designer/public/example/demo.camel.yaml @@ -1,68 +1,68 @@ -- route: - id: route-a947 - nodePrefixId: route-a32 - from: - id: from-c489 - description: Receive Data - uri: kamelet:aws-ddb-streams-source - steps: - - setHeader: - id: setBody-4434 - expression: - simple: - id: simple-abd8 - expression: dddddd - - filter: - id: filter-929b - expression: - simple: - id: simple-d932 - expression: Hello - steps: - - bean: - id: bean-120b - ref: xxx - - log: - id: log-d86e - message: ${body}!!! - - to: - id: to-9f7d - description: Send notification - uri: kafka - - to: - id: to-53a3 - description: Send payments - uri: amqp -- route: - id: route-8609 - nodePrefixId: route-ae2 - from: - id: from-6aee - uri: timer - steps: - - to: - id: to-2df4 - uri: direct - parameters: - name: second_direct - - to: - id: to-e017 - uri: direct - parameters: - name: second_direct -- route: - id: first-firect - from: - id: from-f155 - uri: direct - parameters: - name: first-firect - steps: - - to: - id: to-5c86 - uri: direct - parameters: - name: second_direct +#- route: +# id: route-a947 +# nodePrefixId: route-a32 +# from: +# id: from-c489 +# description: Receive Data +# uri: kamelet:aws-ddb-streams-source +# steps: +# - setHeader: +# id: setBody-4434 +# expression: +# simple: +# id: simple-abd8 +# expression: dddddd +# - filter: +# id: filter-929b +# expression: +# simple: +# id: simple-d932 +# expression: Hello +# steps: +# - bean: +# id: bean-120b +# ref: xxx +# - log: +# id: log-d86e +# message: ${body}!!! +# - to: +# id: to-9f7d +# description: Send notification +# uri: kafka +# - to: +# id: to-53a3 +# description: Send payments +# uri: amqp +#- route: +# id: route-8609 +# nodePrefixId: route-ae2 +# from: +# id: from-6aee +# uri: timer +# steps: +# - to: +# id: to-2df4 +# uri: direct +# parameters: +# name: second_direct +# - to: +# id: to-e017 +# uri: direct +# parameters: +# name: second_direct +#- route: +# id: first-firect +# from: +# id: from-f155 +# uri: direct +# parameters: +# name: first-firect +# steps: +# - to: +# id: to-5c86 +# uri: direct +# parameters: +# name: second_direct - route: id: second_direct from: diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx index 331aa343..03046460 100644 --- a/karavan-designer/src/App.tsx +++ b/karavan-designer/src/App.tsx @@ -114,7 +114,7 @@ export function App() { }); function save(filename: string, yaml: string, propertyOnly: boolean) { - // console.log(yaml); + console.log(yaml); } function getSpinner() { diff --git a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx index 3798c4e4..3f13cb1e 100644 --- a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx +++ b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {useRef, useState} from 'react'; +import React, {useEffect, useRef, useState} from 'react'; import { FormGroup, TextInput, @@ -80,11 +80,27 @@ export function ComponentPropertyField(props: Props) { const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false); const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined); const [id, setId] = useState<string>(prefix + "-" + props.property.name); - + const [textValue, setTextValue] = useState<any>(); const ref = useRef<any>(null); + const [checkChanges, setCheckChanges] = useState<boolean>(false); + + useEffect(()=> setTextValue(value), []) + useEffect(()=> { + if (checkChanges) { + const interval = setInterval(() => { + if (props.value !== textValue) { + parametersChanged(property.name, textValue); + } + }, 3000); + return () => { + clearInterval(interval) + } + } + }, [checkChanges, textValue]) function parametersChanged(parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) { + setCheckChanges(false); onParametersChange(parameter, value, pathParameter, newRoute); setSelectStatus(new Map<string, boolean>([[parameter, false]])) } @@ -221,7 +237,7 @@ export function ComponentPropertyField(props: Props) { onSelect={selectInfrastructure}/>) } - function getStringInput(property: ComponentProperty, value: any) { + function getStringInput(property: ComponentProperty) { const inInfrastructure = InfrastructureAPI.infrastructure !== 'local'; const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name); const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? KubernetesIcon("infra-button") : <DockerIcon/> @@ -237,8 +253,14 @@ export function ComponentPropertyField(props: Props) { <TextInput className="text-field" isRequired ref={ref} type={property.secret && !showPassword ? "password" : "text"} id={id} name={id} - value={value !== undefined ? value : property.defaultValue} - onChange={(e, value) => parametersChanged(property.name, value, property.kind === 'path')}/>} + value={textValue !== undefined ? textValue : property.defaultValue} + onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} + /> + } <InputGroupItem> <Tooltip position="bottom-end" content={"Show Editor"}> <Button variant="control" onClick={e => setShowEditor(!showEditor)}> @@ -257,6 +279,7 @@ export function ComponentPropertyField(props: Props) { onSave={(fieldId, value1) => { parametersChanged(property.name, value1, property.kind === 'path') setShowEditor(false); + setCheckChanges(false); }}/> </InputGroupItem>} {property.secret && @@ -267,12 +290,16 @@ export function ComponentPropertyField(props: Props) { </Tooltip> } <InputGroupItem> - <PropertyPlaceholderDropdown property={property} value={value} onComponentPropertyChange={onParametersChange}/> + <PropertyPlaceholderDropdown property={property} value={value} onComponentPropertyChange={(parameter, v) => { + onParametersChange(parameter, v); + setTextValue(v); + setCheckChanges(false); + }}/> </InputGroupItem> </InputGroup> } - function getSpecialStringInput(property: ComponentProperty, value: any) { + function getSpecialStringInput(property: ComponentProperty) { return ( <InputGroup> <InputGroupItem isFill> @@ -280,14 +307,21 @@ export function ComponentPropertyField(props: Props) { className="text-field" isRequired type={(property.secret ? "password" : "text")} id={id} name={id} - value={value !== undefined ? value : property.defaultValue} + value={textValue !== undefined ? textValue : property.defaultValue} + onBlur={_ => parametersChanged(property.name, textValue, property.kind === 'path')} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} customIcon={<Text component={TextVariants.p}>{property.type}</Text>} - onChange={(_, value) => { - parametersChanged(property.name, value, property.kind === 'path') - }}/> + /> </InputGroupItem> <InputGroupItem> - <PropertyPlaceholderDropdown property={property} value={value} onComponentPropertyChange={onParametersChange}/> + <PropertyPlaceholderDropdown property={property} value={textValue} onComponentPropertyChange={(_, v) => { + setTextValue(v); + onParametersChange(property.name, v) + setCheckChanges(true); + }}/> </InputGroupItem> </InputGroup> ) @@ -318,21 +352,25 @@ export function ComponentPropertyField(props: Props) { ) } - function getSwitch(property: ComponentProperty, value: any) { - const isValueBoolean = (value === true || value === false); - const isDisabled = value !== undefined && !isValueBoolean; - const isChecked = value !== undefined ? Boolean(value) : (property.defaultValue !== undefined && ['true', true].includes(property.defaultValue)) + function getSwitch(property: ComponentProperty) { + const isValueBoolean = (textValue?.toString() === 'true' || textValue?.toString() === 'false'); + const isDisabled = textValue?.toString().includes("{") || textValue?.toString().includes("}") + const isChecked = textValue !== undefined ? Boolean(textValue) : (property.defaultValue !== undefined && ['true', true].includes(property.defaultValue)) return ( <TextInputGroup className="input-group"> <InputGroupItem> <Switch id={id} name={id} - value={value?.toString()} isDisabled={isDisabled} className="switch-placeholder" aria-label={id} isChecked={isChecked} - onChange={(e, checked) => parametersChanged(property.name, checked)}/> + value={textValue?.toString()} + onChange={(_, v) => { + setTextValue(v); + parametersChanged(property.name, v); + setCheckChanges(true); + }}/> </InputGroupItem> <InputGroupItem isFill> <TextInput @@ -340,12 +378,20 @@ export function ComponentPropertyField(props: Props) { name={property.name + "-placeholder"} type="text" aria-label="placeholder" - value={!isValueBoolean ? value?.toString() : undefined} - onChange={(_, v) => parametersChanged(property.name, v)} + value={!isValueBoolean ? textValue?.toString() : undefined} + onBlur={_ => onParametersChange(property.name, textValue)} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} /> </InputGroupItem> <InputGroupItem> - <PropertyPlaceholderDropdown property={property} value={value} onComponentPropertyChange={onParametersChange}/> + <PropertyPlaceholderDropdown property={property} value={value} onDslPropertyChange={(_, v) => { + setTextValue(v); + onParametersChange(property.name, v); + setCheckChanges(false); + }}/> </InputGroupItem> </TextInputGroup> ) @@ -377,15 +423,15 @@ export function ComponentPropertyField(props: Props) { }> {canBeInternalUri(property) && getInternalUriSelect(property, value)} {property.type === 'string' && property.enum === undefined && !canBeInternalUri(property) - && getStringInput(property, value)} + && getStringInput(property)} {['duration', 'integer', 'int', 'number'].includes(property.type) && property.enum === undefined && !canBeInternalUri(property) - && getSpecialStringInput(property, value)} + && getSpecialStringInput(property)} {['object'].includes(property.type) && !property.enum && getSelectBean(property, value)} {['string', 'object'].includes(property.type) && property.enum && getSelect(property, value)} {property.type === 'boolean' - && getSwitch(property, value)} + && getSwitch(property)} {getInfrastructureSelectorModal()} </FormGroup> ) diff --git a/karavan-designer/src/designer/property/property/DslPropertyField.tsx b/karavan-designer/src/designer/property/property/DslPropertyField.tsx index 923b0e26..95bc3504 100644 --- a/karavan-designer/src/designer/property/property/DslPropertyField.tsx +++ b/karavan-designer/src/designer/property/property/DslPropertyField.tsx @@ -14,7 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {useRef, useState} from 'react'; +import React, {useEffect, useRef, useState} from 'react'; import { FormGroup, TextInput, @@ -99,9 +99,25 @@ export function DslPropertyField(props: Props) { const [showEditor, setShowEditor] = useState<boolean>(false); const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false); const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined); - const [customCode, setCustomCode] = useState<string | undefined>(undefined); - + const [customCode, setCustomCode] = useState<string>(''); + const [textValue, setTextValue] = useState<any>(); const ref = useRef<any>(null); + const [checkChanges, setCheckChanges] = useState<boolean>(false); + + useEffect(()=> setTextValue(value), []) + + useEffect(()=> { + if (checkChanges) { + const interval = setInterval(() => { + if (props.value !== textValue) { + propertyChanged(property.name, textValue); + } + }, 3000); + return () => { + clearInterval(interval) + } + } + }, [checkChanges, textValue]) function openSelect(propertyName: string, isExpanded: boolean) { setSelectStatus(new Map<string, boolean>([[propertyName, isExpanded]])) @@ -116,6 +132,7 @@ 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; } @@ -224,14 +241,14 @@ export function DslPropertyField(props: Props) { onSelect={selectInfrastructure}/>) } - function getStringInput(property: PropertyMeta, value: any) { + function getStringInput(property: PropertyMeta) { const inInfrastructure = InfrastructureAPI.infrastructure !== 'local'; const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name); const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? KubernetesIcon("infra-button") : <DockerIcon/> const isNumber = ['integer', 'number', 'duration'].includes(property.type); const uriReadOnly = isUriReadOnly(property); const showEditorButton = !uriReadOnly && !isNumber && !property.secret && !['id', 'description'].includes(property.name); - return (<InputGroup> + return <InputGroup> {inInfrastructure && !showEditor && !noInfraSelectorButton && <InputGroupItem> <Tooltip position="bottom-end" @@ -246,12 +263,16 @@ export function DslPropertyField(props: Props) { <InputGroupItem isFill> <TextInput ref={ref} className="text-field" isRequired - type={(property.secret ? "password" : "text")} + type={property.secret ? "password" : "text"} id={property.name} name={property.name} - value={value?.toString()} + value={textValue?.toString()} customIcon={property.type !== 'string' ? <Text component={TextVariants.p}>{property.type}</Text> : undefined} - onChange={(_, v) => - propertyChanged(property.name, v)} + onBlur={_ => propertyChanged(property.name, textValue)} + onFocus={_ => setCheckChanges(true)} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} readOnlyVariant={uriReadOnly? "default" : undefined}/> </InputGroupItem> } @@ -275,14 +296,14 @@ export function DslPropertyField(props: Props) { setShowEditor(false); }}/> </InputGroupItem>} - </InputGroup>) + </InputGroup> } function showCode(name: string, javaType: string) { const {property} = props; InfrastructureAPI.onGetCustomCode?.(name, property.javaType).then(value => { if (value === undefined) { - const code = TemplateApi.generateCode(property.javaType, name); + const code = TemplateApi.generateCode(property.javaType, name) || ''; setCustomCode(code); setShowEditor(true); } else { @@ -343,8 +364,13 @@ export function DslPropertyField(props: Props) { id={property.name} name={property.name} height={"100px"} - value={value?.toString()} - onChange={(_, v) => propertyChanged(property.name, v)}/> + value={textValue?.toString()} + onBlur={_ => propertyChanged(property.name, textValue)} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} + /> </InputGroupItem> <InputGroupItem> <Tooltip position="bottom-end" content={"Show Editor"}> @@ -391,13 +417,13 @@ export function DslPropertyField(props: Props) { ) } - function getBooleanInput(property: PropertyMeta, value: any) { - const isValueBoolean = (value === true || value === false); - const isDisabled = value !== undefined && !isValueBoolean; + function getBooleanInput(property: PropertyMeta) { + const isValueBoolean = (textValue?.toString() === 'true' || textValue?.toString() === 'false'); + const isDisabled = textValue?.toString().includes("{") || textValue?.toString().includes("}") let isChecked = false; - if (value !== undefined && isValueBoolean) { - isChecked = Boolean(value); - } else if ((value === undefined || value.toString().length > 0) && property.defaultValue !== undefined) { + if (textValue !== undefined && isValueBoolean) { + isChecked = Boolean(textValue); + } else if ((textValue === undefined || textValue.toString().length > 0) && property.defaultValue !== undefined) { isChecked = property.defaultValue === 'true'; } return ( @@ -408,10 +434,14 @@ export function DslPropertyField(props: Props) { id={property.name + "-switch"} name={property.name + "-switch"} className="switch-placeholder" - value={value?.toString()} + value={textValue?.toString()} aria-label={property.name} isChecked={isChecked} - onChange={(_, v) => propertyChanged(property.name, v)}/> + onChange={(_, v) => { + setTextValue(v); + propertyChanged(property.name, v); + setCheckChanges(false); + }}/> </InputGroupItem> <InputGroupItem isFill> <TextInput @@ -419,12 +449,20 @@ export function DslPropertyField(props: Props) { name={property.name + "-placeholder"} type="text" aria-label="placeholder" - value={!isValueBoolean ? value?.toString() : undefined} - onChange={(_, v) => propertyChanged(property.name, v)} + value={!isValueBoolean ? textValue?.toString() : undefined} + onBlur={_ => propertyChanged(property.name, textValue)} + onChange={(_, v) => { + setTextValue(v); + setCheckChanges(true); + }} /> </InputGroupItem> <InputGroupItem> - <PropertyPlaceholderDropdown property={property} value={value} onDslPropertyChange={propertyChanged}/> + <PropertyPlaceholderDropdown property={property} value={value} onDslPropertyChange={(_, v, newRoute) => { + setTextValue(v); + propertyChanged(property.name, v, newRoute); + setCheckChanges(false); + }}/> </InputGroupItem> </TextInputGroup> ) @@ -830,13 +868,13 @@ export function DslPropertyField(props: Props) { && !canBeInternalUri(property, element) && !canBeMediaType(property, element) && !javaTypeGenerated(property) - && getStringInput(property, value)} + && getStringInput(property)} {['string'].includes(property.type) && property.name.endsWith("Ref") && !property.isArray && !property.enumVals && getSelectBean(property, value)} {isMultiValueField(property) && getMultiValueField(property, value)} {property.type === 'boolean' - && getBooleanInput(property, value)} + && getBooleanInput(property)} {property.enumVals && getSelect(property, value)} {isKamelet && property.name === 'parameters' && getKameletParameters()}