You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/10/05 00:01:20 UTC
[camel-karavan] branch main updated: FIx #930
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 083466d2 FIx #930
083466d2 is described below
commit 083466d2a46d34bd02ce5a14ab44251028124d8a
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Oct 4 20:01:10 2023 -0400
FIx #930
---
.../designer/kamelet/KameletAnnotationsPanel.tsx | 3 +-
karavan-designer/src/designer/karavan.css | 1 +
.../route/property/ComponentParameterField.tsx | 4 +-
.../designer/route/property/DslPropertyField.tsx | 12 +-
.../designer/kamelet/KameletAnnotationsPanel.tsx | 3 +-
.../kamelet/KameletDefinitionPropertyCard.tsx | 125 +++++++++++-
.../designer/kamelet/KameletDefinitionsPanel.tsx | 59 +++++-
.../designer/kamelet/KameletDependenciesCard.tsx | 113 +++++++++++
.../src/designer/kamelet/KameletProperties.tsx | 209 +--------------------
.../src/designer/kamelet/KameletTypesOutCard.tsx | 113 +++++++++++
karavan-space/src/designer/kamelet/kamelet.css | 1 +
karavan-space/src/designer/karavan.css | 1 +
.../route/property/ComponentParameterField.tsx | 4 +-
.../designer/route/property/DslPropertyField.tsx | 12 +-
.../designer/kamelet/KameletAnnotationsPanel.tsx | 3 +-
.../src/main/webui/src/designer/karavan.css | 1 +
.../route/property/ComponentParameterField.tsx | 4 +-
.../designer/route/property/DslPropertyField.tsx | 12 +-
18 files changed, 434 insertions(+), 246 deletions(-)
diff --git a/karavan-designer/src/designer/kamelet/KameletAnnotationsPanel.tsx b/karavan-designer/src/designer/kamelet/KameletAnnotationsPanel.tsx
index 076aec40..b1a6b324 100644
--- a/karavan-designer/src/designer/kamelet/KameletAnnotationsPanel.tsx
+++ b/karavan-designer/src/designer/kamelet/KameletAnnotationsPanel.tsx
@@ -75,8 +75,7 @@ export function KameletAnnotationsPanel() {
return (
<GridItem span={span}>
<FormGroup label={label} fieldId={key} isRequired>
- {/* eslint-disable-next-line react/jsx-no-undef */}
- <ToggleGroup aria-label={key}>
+ <ToggleGroup aria-label={key} id={key} name={key}>
{values.map(value =>
<ToggleGroupItem
key={value}
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index fb04c267..31aa866b 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -343,6 +343,7 @@
flex-direction: column;
justify-content: space-between;
margin-bottom: 20px;
+ padding-bottom: 30px;
}
.karavan .pf-v5-c-drawer__splitter {
diff --git a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
index 23f8228a..d8adbd08 100644
--- a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
@@ -37,7 +37,7 @@ import "@patternfly/patternfly/patternfly.css";
import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
import {ToDefinition} from "karavan-core/lib/model/CamelDefinition";
import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
@@ -49,7 +49,7 @@ import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {usePropertiesHook} from "../usePropertiesHook";
-import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
+import {useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
const prefix = "parameters";
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index b07e8beb..70651b21 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
@@ -88,7 +88,7 @@ export function DslPropertyField(props: Props) {
const [integration] = useIntegrationStore((state) => [state.integration], shallow)
const [dark] = useDesignerStore((s) => [s.dark], shallow)
- const [isShowAdvanced, setIsShowAdvanced] = useState<Map<string, boolean>>(new Map<string, boolean>());
+ const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
const [arrayValues, setArrayValues] = useState<Map<string, string>>(new Map<string, string>());
const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
const [showEditor, setShowEditor] = useState<boolean>(false);
@@ -654,19 +654,23 @@ export function DslPropertyField(props: Props) {
</div>
)
}
-
function getExpandableComponentParameters(properties: ComponentProperty[], label: string) {
const element = props.element;
+
return (
<ExpandableSection
toggleText={label}
onToggle={(_event, isExpanded) => {
setIsShowAdvanced(prevState => {
- prevState.set(label, !prevState.get(label));
+ if (isExpanded && !isShowAdvanced.includes(label)) {
+ prevState = [...prevState, label]
+ } else {
+ prevState = prevState.filter(s => s!== label);
+ }
return prevState;
})
}}
- isExpanded={isShowAdvanced.has(label) && isShowAdvanced.get(label)}>
+ isExpanded={isShowAdvanced.includes(label)}>
<div className="parameters">
{properties.map(kp =>
<ComponentParameterField
diff --git a/karavan-space/src/designer/kamelet/KameletAnnotationsPanel.tsx b/karavan-space/src/designer/kamelet/KameletAnnotationsPanel.tsx
index 076aec40..b1a6b324 100644
--- a/karavan-space/src/designer/kamelet/KameletAnnotationsPanel.tsx
+++ b/karavan-space/src/designer/kamelet/KameletAnnotationsPanel.tsx
@@ -75,8 +75,7 @@ export function KameletAnnotationsPanel() {
return (
<GridItem span={span}>
<FormGroup label={label} fieldId={key} isRequired>
- {/* eslint-disable-next-line react/jsx-no-undef */}
- <ToggleGroup aria-label={key}>
+ <ToggleGroup aria-label={key} id={key} name={key}>
{values.map(value =>
<ToggleGroupItem
key={value}
diff --git a/karavan-space/src/designer/kamelet/KameletDefinitionPropertyCard.tsx b/karavan-space/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
index d8933df4..cf42ef6c 100644
--- a/karavan-space/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
+++ b/karavan-space/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
@@ -19,10 +19,18 @@ import {
Button,
Card,
CardBody,
- CardTitle, Flex, FlexItem,
- FormGroup, FormSelect, FormSelectOption,
+ CardTitle,
+ Flex,
+ FlexItem,
+ FormGroup,
+ FormSelect,
+ FormSelectOption,
Grid,
- GridItem, Label, Modal, Switch,
+ GridItem,
+ Label,
+ LabelGroup,
+ Modal,
+ Switch,
TextInput,
} from '@patternfly/react-core';
import '../karavan.css';
@@ -30,6 +38,8 @@ import './kamelet.css';
import {useIntegrationStore} from "../DesignerStore";
import {shallow} from "zustand/shallow";
import {DefinitionProperty} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
interface Props {
index: number
@@ -45,7 +55,7 @@ export function KameletDefinitionPropertyCard(props: Props) {
const key = props.propKey;
const required = integration.spec.definition?.required || [];
- function setPropertyValue(field: string, value: string) {
+ function setPropertyValue(field: string, value: any) {
if (integration.spec.definition?.properties) {
(integration.spec.definition?.properties as any)[key][field] = value;
setIntegration(integration, true);
@@ -83,8 +93,9 @@ export function KameletDefinitionPropertyCard(props: Props) {
aria-label="FormSelect Input"
ouiaId="BasicFormSelect"
>
- {['string', 'number', 'boolean'].map((option, index) => (
- <FormSelectOption key={option} isDisabled={false} id={key + field} name={key + field} value={option} label={option} />
+ {['string', 'number', 'integer', 'boolean'].map((option, index) => (
+ <FormSelectOption key={option} isDisabled={false} id={key + field} name={key + field}
+ value={option} label={option}/>
))}
</FormSelect>
</FormGroup>
@@ -92,9 +103,106 @@ export function KameletDefinitionPropertyCard(props: Props) {
)
}
+ function sortEnum(source: string, dest: string) {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties[key]) {
+ const enums: string [] = i.spec.definition.properties[key].enum;
+ console.log(enums)
+ if (enums && Array.isArray(enums)) {
+ console.log("isArray")
+ const from = enums.findIndex(e => source);
+ const to = enums.findIndex(e => dest);
+ if (from > -1 && to > -1) {
+ console.log("exchange");
+ [enums[from], enums[to]] = [enums[to], enums[from]];
+ i.spec.definition.properties[key].enum = enums;
+ console.log("i.spec.definition.properties[key].enum", i.spec.definition.properties[key].enum);
+ setIntegration(i, true);
+ }
+ }
+ }
+ }
+
+ function addEnum() {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties[key]) {
+ let enums: string [] = i.spec.definition.properties[key].enum;
+ if (enums && Array.isArray(enums)) {
+ enums.push("enum")
+ } else {
+ enums = ['enum'];
+ }
+ i.spec.definition.properties[key].enum = enums;
+ setIntegration(i, true);
+ }
+ }
+
+ function deleteEnum(val: string) {
+ const enumVal = getPropertyValue('enum');
+ const i = CamelUtil.cloneIntegration(integration);
+ if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
+ const enums: string[] = [...enumVal];
+ setPropertyValue('enum', enums.filter(e => e !== val));
+ }
+ }
+
+ function renameEnum(index: number, newVal: string) {
+ const enumVal = getPropertyValue('enum');
+ const i = CamelUtil.cloneIntegration(integration);
+ if (enumVal && Array.isArray(enumVal) && i.spec.definition) {
+ const enums: string[] = [...enumVal];
+ enums[index] = newVal;
+ setPropertyValue('enum', enums);
+ }
+ }
+
+ function getPropertyEnumField(field: string, label: string, isRequired: boolean, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ const enumVal = getPropertyValue(field);
+ return (
+ <GridItem span={span}>
+ <FormGroup fieldId={key + field} isRequired={isRequired}>
+ <LabelGroup
+ categoryName={label}
+ numLabels={enumVal?.length || 0}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<AddIcon/>} onClick={event => addEnum()}>
+ Add
+ </Button>
+ }
+ >
+ {enumVal && enumVal.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteEnum(val)}
+ onEditCancel={(_event, prevText) => {}}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameEnum(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameEnum(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameEnum(index, newText)
+ } else {
+ renameEnum(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </GridItem>
+ )
+ }
+
function renameProperty(newKey: string) {
const oldKey = key;
- newKey = newKey.replace(/[\W_]+/g,'');
+ newKey = newKey.replace(/[\W_]+/g, '');
if (oldKey !== newKey) {
if (integration.spec.definition?.properties) {
const o = (integration.spec.definition?.properties as any)
@@ -138,7 +246,6 @@ export function KameletDefinitionPropertyCard(props: Props) {
}
function setRequired(checked: boolean) {
- console.log(required, key)
const newRequired = [...required];
if (checked && !newRequired.includes(key)) {
newRequired.push(key);
@@ -146,7 +253,6 @@ export function KameletDefinitionPropertyCard(props: Props) {
const index = newRequired.findIndex(r => r === key);
newRequired.splice(index, 1);
}
- // console.log(newRequired)
if (integration.spec.definition?.required) {
integration.spec.definition.required.length = 0;
integration.spec.definition.required.push(...newRequired)
@@ -212,6 +318,7 @@ export function KameletDefinitionPropertyCard(props: Props) {
{getPropertyField("format", "Format", false, 3)}
{getPropertyField("example", "Example", false, 6)}
{getPropertyField("default", "Default", false, 3)}
+ {getPropertyValue('type') === 'string' && getPropertyEnumField("enum", "Enum", true, 12)}
{/*{getPropertyField("x-descriptors", "Descriptors", false, 12)}*/}
</Grid>
</CardBody>
diff --git a/karavan-space/src/designer/kamelet/KameletDefinitionsPanel.tsx b/karavan-space/src/designer/kamelet/KameletDefinitionsPanel.tsx
index 009a54ac..0d3f04a4 100644
--- a/karavan-space/src/designer/kamelet/KameletDefinitionsPanel.tsx
+++ b/karavan-space/src/designer/kamelet/KameletDefinitionsPanel.tsx
@@ -19,11 +19,13 @@ import {
Button,
Card,
CardBody,
- CardTitle, Flex, FlexItem,
+ CardTitle,
+ Flex,
+ FlexItem,
Form,
FormGroup,
Grid,
- GridItem,
+ GridItem, TextArea,
TextInput,
} from '@patternfly/react-core';
import '../karavan.css';
@@ -32,6 +34,9 @@ import {useIntegrationStore} from "../DesignerStore";
import {shallow} from "zustand/shallow";
import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
import {KameletDefinitionPropertyCard} from "./KameletDefinitionPropertyCard";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {DefinitionProperty} from "karavan-core/lib/model/IntegrationDefinition";
+import {KameletDependenciesCard} from "./KameletDependenciesCard";
export function KameletDefinitionsPanel() {
@@ -53,7 +58,7 @@ export function KameletDefinitionsPanel() {
}
}
- function getElement(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ function getElementTextInput(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
return (
<GridItem span={span}>
<FormGroup label={label} fieldId={key} isRequired>
@@ -65,7 +70,43 @@ export function KameletDefinitionsPanel() {
)
}
+ function getElementTextArea(key: string, label: string, span: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12) {
+ return (
+ <GridItem span={span}>
+ <FormGroup label={label} fieldId={key} isRequired>
+ <TextArea type="text" id={key} name={key} autoResize
+ onChange={(_, value) => setValue(key, value)}
+ value={getValue(key)}/>
+ </FormGroup>
+ </GridItem>
+ )
+ }
+
const properties = integration.spec.definition?.properties ? Object.keys(integration.spec.definition?.properties) : [];
+
+ function addNewProperty() {
+ const i = CamelUtil.cloneIntegration(integration);
+ if (i.spec.definition && integration.spec.definition?.properties) {
+ const propertyName = generatePropertyName();
+ i.spec.definition.properties = Object.assign({[propertyName]: new DefinitionProperty()}, integration.spec.definition.properties);
+ setIntegration(i, true);
+ }
+ }
+
+ function generatePropertyName(count: number = 0): string {
+ const prefix = 'property';
+ const propName = 'property' + count;
+ if (integration.spec.definition?.properties) {
+ const keys = Object.keys(integration.spec.definition?.properties);
+ if (keys.includes(propName)) {
+ return generatePropertyName(count + 1);
+ } else {
+ return propName;
+ }
+ }
+ return prefix;
+ }
+
return (
<>
<Card isCompact ouiaId="DefinitionsCard">
@@ -73,9 +114,9 @@ export function KameletDefinitionsPanel() {
<CardBody>
<Form>
<Grid hasGutter>
- {getElement('title', 'Title', 4)}
- {getElement('description', 'Description', 6)}
- {getElement('type', 'Type', 2)}
+ {getElementTextInput('title', 'Title', 3)}
+ {getElementTextArea('description', 'Description', 9)}
+ {/*{getElementTextInput('type', 'Type', 2)}*/}
</Grid>
</Form>
</CardBody>
@@ -86,7 +127,9 @@ export function KameletDefinitionsPanel() {
<Flex>
<FlexItem>Properties</FlexItem>
<FlexItem align={{default: "alignRight"}}>
- <Button variant={"link"} icon={<AddIcon/>}>Add property</Button>
+ <Button variant={"link"} icon={<AddIcon/>} onClick={event => addNewProperty()}>
+ Add property
+ </Button>
</FlexItem>
</Flex>
</CardTitle>
@@ -102,6 +145,8 @@ export function KameletDefinitionsPanel() {
</Form>
</CardBody>
</Card>
+ <div style={{height: "20px"}}/>
+ <KameletDependenciesCard/>
</>
)
diff --git a/karavan-space/src/designer/kamelet/KameletDependenciesCard.tsx b/karavan-space/src/designer/kamelet/KameletDependenciesCard.tsx
new file mode 100644
index 00000000..893c897b
--- /dev/null
+++ b/karavan-space/src/designer/kamelet/KameletDependenciesCard.tsx
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Card,
+ CardBody,
+ CardTitle,
+ FormGroup, FormHelperText, HelperText, HelperTextItem,
+ Label,
+ LabelGroup,
+} from '@patternfly/react-core';
+import '../karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+
+export function KameletDependenciesCard() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ const dependencies: string[] = [...(integration.spec.dependencies || [])];
+
+
+ function setDependencies(deps: string[]) {
+ const i = CamelUtil.cloneIntegration(integration);
+ i.spec.dependencies = deps;
+ setIntegration(i, true);
+ }
+
+ function addDepencency() {
+ dependencies.push("dependency")
+ setDependencies(dependencies);
+ }
+
+ function deleteDependency(val: string) {
+ setDependencies(dependencies.filter(e => e !== val));
+ }
+
+ function renameDependency(index: number, newVal: string) {
+ dependencies[index] = newVal;
+ setDependencies(dependencies);
+ }
+
+ return (
+ <Card isClickable isCompact isFlat ouiaId="PropertyCard" className="property-card">
+ <CardTitle>
+ Dependencies
+ </CardTitle>
+ <CardBody>
+ <FormHelperText>
+ <HelperText>
+ <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
+ </HelperText>
+ </FormHelperText>
+ </CardBody>
+ <CardBody>
+ <FormGroup fieldId={'dependencies'}>
+ <LabelGroup
+ // categoryName={"Dependencies"}
+ numLabels={dependencies.length}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<AddIcon/>} onClick={event => addDepencency()}>
+ Add
+ </Button>
+ }
+ >
+ {dependencies.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteDependency(val)}
+ onEditCancel={(_event, prevText) => {}}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameDependency(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameDependency(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameDependency(index, newText)
+ } else {
+ renameDependency(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </CardBody>
+ </Card>
+ )
+}
diff --git a/karavan-space/src/designer/kamelet/KameletProperties.tsx b/karavan-space/src/designer/kamelet/KameletProperties.tsx
index fc8f188f..e5a8cfc5 100644
--- a/karavan-space/src/designer/kamelet/KameletProperties.tsx
+++ b/karavan-space/src/designer/kamelet/KameletProperties.tsx
@@ -14,11 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import React, {useEffect, useState} from 'react';
+import React from 'react';
import {
Form,
- FormGroup,
- TextInput, Button, Title, Tooltip, Popover, InputGroup, InputGroupItem,
} from '@patternfly/react-core';
import '../karavan.css';
import "@patternfly/patternfly/patternfly.css";
@@ -26,21 +24,6 @@ import {
RegistryBeanDefinition,
} from "karavan-core/lib/model/CamelDefinition";
import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {SensitiveKeys} from "karavan-core/lib/model/CamelMetadata";
-import {v4 as uuidv4} from "uuid";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
-import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
-import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'
-import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
-import {InfrastructureSelector} from "../route/property/InfrastructureSelector";
-import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
-import {InfrastructureAPI} from "../utils/InfrastructureAPI";
-import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
-import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
-import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
-import {useDesignerStore} from "../DesignerStore";
-import {shallow} from "zustand/shallow";
import {IntegrationHeader} from "../utils/IntegrationHeader";
@@ -53,197 +36,11 @@ interface Props {
export function KameletProperties (props: Props) {
- const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow);
- const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false);
- const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined);
- const [infrastructureSelectorUuid, setInfrastructureSelectorUuid] = useState<string | undefined>(undefined);
- const [properties, setProperties] = useState<Map<string, [string, string, boolean]>>(new Map<string, [string, string, boolean]>());
-
- useEffect(()=> {
- setProperties(preparePropertiesMap((selectedStep as RegistryBeanDefinition)?.properties))
- }, [selectedStep?.uuid])
-
- function preparePropertiesMap (properties: any): Map<string, [string, string, boolean]> {
- const result = new Map<string, [string, string, boolean]>();
- if (properties) {
- Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k, properties[k], false]));
- }
- return result;
- }
-
- function onBeanPropertyUpdate () {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep);
- const beanProperties: any = {};
- properties.forEach((p: any) => beanProperties[p[0]] = p[1]);
- bean.properties = beanProperties;
- props.onChange(bean);
- }
- }
-
- function beanFieldChanged (fieldId: string, value: string) {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep);
- (bean as any)[fieldId] = value;
- props.onChange(bean);
- }
- }
-
- function propertyChanged (uuid: string, key: string, value: string, showPassword: boolean) {
- setProperties(prevState => {
- prevState.set(uuid, [key, value, showPassword]);
- return prevState;
- });
- onBeanPropertyUpdate();
- }
-
- function propertyDeleted (uuid: string) {
- setProperties(prevState => {
- prevState.delete(uuid);
- return prevState;
- })
- onBeanPropertyUpdate();
- }
-
- function selectInfrastructure (value: string) {
- const propertyId = infrastructureSelectorProperty;
- const uuid = infrastructureSelectorUuid;
- if (propertyId && uuid){
- if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
- propertyChanged(uuid, propertyId, value, false);
- setInfrastructureSelector(false);
- setInfrastructureSelectorProperty(undefined);
- }
- }
-
- function openInfrastructureSelector (uuid: string, propertyName: string) {
- setInfrastructureSelector(true);
- setInfrastructureSelectorProperty(propertyName);
- setInfrastructureSelectorUuid(uuid);
- }
-
- function closeInfrastructureSelector () {
- setInfrastructureSelector(false);
- }
-
- function getInfrastructureSelectorModal() {
- return (
- <InfrastructureSelector
- dark={false}
- isOpen={infrastructureSelector}
- onClose={() => closeInfrastructureSelector()}
- onSelect={selectInfrastructure}/>)
- }
-
- function cloneBean () {
- if (selectedStep) {
- const bean = CamelUtil.cloneBean(selectedStep);
- bean.uuid = uuidv4();
- props.onClone(bean);
- }
- }
-
- function getLabelIcon (displayName: string, description: string) {
- return (
- <Popover
- position={"left"}
- headerContent={displayName}
- bodyContent={description}
- footerContent={
- <div>
- <b>Required</b>
- </div>
- }>
- <button type="button" aria-label="More info" onClick={e => {
- e.preventDefault();
- e.stopPropagation();
- }} className="pf-v5-c-form__group-label-help">
- <HelpIcon />
- </button>
- </Popover>
- )
- }
- function getBeanForm() {
- const bean = (selectedStep as RegistryBeanDefinition);
- return (
- <>
- <div className="headers">
- <div className="top">
- <Title headingLevel="h1" size="md">Bean</Title>
- <Tooltip content="Clone bean" position="bottom">
- <Button variant="link" onClick={() => cloneBean()} icon={<CloneIcon/>}/>
- </Tooltip>
- </div>
- </div>
- <FormGroup label="Name" fieldId="name" isRequired labelIcon={getLabelIcon("Name", "Bean name used as a reference ex: myBean")}>
- <TextInput className="text-field" isRequired type="text" id="name" name="name" value={bean?.name}
- onChange={(_, value)=> beanFieldChanged("name", value)}/>
- </FormGroup>
- <FormGroup label="Type" fieldId="type" isRequired labelIcon={getLabelIcon("Type", "Bean class Canonical Name ex: org.demo.MyBean")}>
- <TextInput className="text-field" isRequired type="text" id="type" name="type" value={bean?.type}
- onChange={(_, value) => beanFieldChanged("type", value)}/>
- </FormGroup>
- <FormGroup label="Properties" fieldId="properties" className="bean-properties">
- {Array.from(properties.entries()).map((v, index, array) => {
- const i = v[0];
- const key = v[1][0];
- const value = v[1][1];
- const showPassword = v[1][2];
- const isSecret = key !== undefined && SensitiveKeys.includes(key.toLowerCase());
- const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
- const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
- return (
- <div key={"key-" + i} className="bean-property">
- <TextInput placeholder="Bean Field Name" className="text-field" isRequired type="text" id={"key-" + i}
- name={"key-" + i} value={key}
- onChange={(_, beanFieldName) => {
- propertyChanged(i, beanFieldName, value, showPassword)
- }}/>
- <InputGroup>
- {inInfrastructure &&
- <Tooltip position="bottom-end" content="Select value from Infrastructure">
- <Button variant="control" onClick={e => openInfrastructureSelector(i, key)}>
- {icon}
- </Button>
- </Tooltip>}
- <InputGroupItem isFill>
- <TextInput
- placeholder="Bean Field Value"
- type={isSecret && !showPassword ? "password" : "text"}
- className="text-field"
- isRequired
- id={"value-" + i}
- name={"value-" + i}
- value={value}
- onChange={(_, value) => {
- propertyChanged(i, key, value, showPassword)
- }}/>
- </InputGroupItem>
- {isSecret && <Tooltip position="bottom-end" content={showPassword ? "Hide" : "Show"}>
- <Button variant="control" onClick={e => propertyChanged(i, key, value, !showPassword)}>
- {showPassword ? <ShowIcon/> : <HideIcon/>}
- </Button>
- </Tooltip>}
- </InputGroup>
- <Button variant="link" className="delete-button" onClick={e => propertyDeleted(i)}><DeleteIcon/></Button>
- </div>
- )
- })}
- <Button variant="link" className="add-button" onClick={e => propertyChanged(uuidv4(), '', '', false)}>
- <AddIcon/>Add property</Button>
- </FormGroup>
- </>
- )
- }
-
- const bean = (selectedStep as RegistryBeanDefinition);
return (
- <div className='properties' key={bean ? bean.uuid : 'integration'}>
+ <div className='properties' key={'integration'}>
<Form autoComplete="off" onSubmit={event => event.preventDefault()}>
- {bean === undefined && <IntegrationHeader/>}
- {bean !== undefined && getBeanForm()}
+ <IntegrationHeader/>
</Form>
- {getInfrastructureSelectorModal()}
</div>
)
}
diff --git a/karavan-space/src/designer/kamelet/KameletTypesOutCard.tsx b/karavan-space/src/designer/kamelet/KameletTypesOutCard.tsx
new file mode 100644
index 00000000..76b590ee
--- /dev/null
+++ b/karavan-space/src/designer/kamelet/KameletTypesOutCard.tsx
@@ -0,0 +1,113 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+ Button,
+ Card,
+ CardBody,
+ CardTitle,
+ FormGroup, FormHelperText, HelperText, HelperTextItem,
+ Label,
+ LabelGroup,
+} from '@patternfly/react-core';
+import '../karavan.css';
+import './kamelet.css';
+import {useIntegrationStore} from "../DesignerStore";
+import {shallow} from "zustand/shallow";
+import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+
+export function KameletTypesOutCard() {
+
+ const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+
+ const dependencies: string[] = [...(integration.spec.dependencies || [])];
+
+
+ function setDependencies(deps: string[]) {
+ const i = CamelUtil.cloneIntegration(integration);
+ i.spec.dependencies = deps;
+ setIntegration(i, true);
+ }
+
+ function addDepencency() {
+ dependencies.push("dependency")
+ setDependencies(dependencies);
+ }
+
+ function deleteDependency(val: string) {
+ setDependencies(dependencies.filter(e => e !== val));
+ }
+
+ function renameDependency(index: number, newVal: string) {
+ dependencies[index] = newVal;
+ setDependencies(dependencies);
+ }
+
+ return (
+ <Card isClickable isCompact isFlat ouiaId="PropertyCard" className="property-card">
+ <CardTitle>
+ Dependencies
+ </CardTitle>
+ <CardBody>
+ <FormHelperText>
+ <HelperText>
+ <HelperTextItem>Dependencies required, ex: camel:component or mvn:groupId:artifactId:version</HelperTextItem>
+ </HelperText>
+ </FormHelperText>
+ </CardBody>
+ <CardBody>
+ <FormGroup fieldId={'dependencies'}>
+ <LabelGroup
+ // categoryName={"Dependencies"}
+ numLabels={dependencies.length}
+ isEditable
+ addLabelControl={
+ <Button variant="link" icon={<AddIcon/>} onClick={event => addDepencency()}>
+ Add
+ </Button>
+ }
+ >
+ {dependencies.map((val: string, index: number) => (
+ <Label
+ key={val}
+ id={val}
+ color="grey"
+ isEditable
+ onClose={() => deleteDependency(val)}
+ onEditCancel={(_event, prevText) => {}}
+ onEditComplete={(event, newText) => {
+ if (event.type === 'mousedown') {
+ renameDependency(index, val)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Tab') {
+ renameDependency(index, newText)
+ } else if (event.type === 'keydown' && (event as KeyboardEvent).key === 'Enter') {
+ renameDependency(index, newText)
+ } else {
+ renameDependency(index, val)
+ }
+ }}
+ >
+ {val}
+ </Label>
+ ))}
+ </LabelGroup>
+ </FormGroup>
+ </CardBody>
+ </Card>
+ )
+}
diff --git a/karavan-space/src/designer/kamelet/kamelet.css b/karavan-space/src/designer/kamelet/kamelet.css
index bbdf28a9..c72acad2 100644
--- a/karavan-space/src/designer/kamelet/kamelet.css
+++ b/karavan-space/src/designer/kamelet/kamelet.css
@@ -23,6 +23,7 @@
padding-bottom: 106px;
}
+.karavan .kamelet-designer .pf-v5-c-drawer__content,
.karavan .kamelet-designer .main {
background-color: var(--pf-v5-global--BackgroundColor--light-300);
}
diff --git a/karavan-space/src/designer/karavan.css b/karavan-space/src/designer/karavan.css
index fb04c267..31aa866b 100644
--- a/karavan-space/src/designer/karavan.css
+++ b/karavan-space/src/designer/karavan.css
@@ -343,6 +343,7 @@
flex-direction: column;
justify-content: space-between;
margin-bottom: 20px;
+ padding-bottom: 30px;
}
.karavan .pf-v5-c-drawer__splitter {
diff --git a/karavan-space/src/designer/route/property/ComponentParameterField.tsx b/karavan-space/src/designer/route/property/ComponentParameterField.tsx
index 23f8228a..d8adbd08 100644
--- a/karavan-space/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-space/src/designer/route/property/ComponentParameterField.tsx
@@ -37,7 +37,7 @@ import "@patternfly/patternfly/patternfly.css";
import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
import {ToDefinition} from "karavan-core/lib/model/CamelDefinition";
import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
@@ -49,7 +49,7 @@ import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {usePropertiesHook} from "../usePropertiesHook";
-import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
+import {useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
const prefix = "parameters";
diff --git a/karavan-space/src/designer/route/property/DslPropertyField.tsx b/karavan-space/src/designer/route/property/DslPropertyField.tsx
index b07e8beb..70651b21 100644
--- a/karavan-space/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-space/src/designer/route/property/DslPropertyField.tsx
@@ -88,7 +88,7 @@ export function DslPropertyField(props: Props) {
const [integration] = useIntegrationStore((state) => [state.integration], shallow)
const [dark] = useDesignerStore((s) => [s.dark], shallow)
- const [isShowAdvanced, setIsShowAdvanced] = useState<Map<string, boolean>>(new Map<string, boolean>());
+ const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
const [arrayValues, setArrayValues] = useState<Map<string, string>>(new Map<string, string>());
const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
const [showEditor, setShowEditor] = useState<boolean>(false);
@@ -654,19 +654,23 @@ export function DslPropertyField(props: Props) {
</div>
)
}
-
function getExpandableComponentParameters(properties: ComponentProperty[], label: string) {
const element = props.element;
+
return (
<ExpandableSection
toggleText={label}
onToggle={(_event, isExpanded) => {
setIsShowAdvanced(prevState => {
- prevState.set(label, !prevState.get(label));
+ if (isExpanded && !isShowAdvanced.includes(label)) {
+ prevState = [...prevState, label]
+ } else {
+ prevState = prevState.filter(s => s!== label);
+ }
return prevState;
})
}}
- isExpanded={isShowAdvanced.has(label) && isShowAdvanced.get(label)}>
+ isExpanded={isShowAdvanced.includes(label)}>
<div className="parameters">
{properties.map(kp =>
<ComponentParameterField
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletAnnotationsPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletAnnotationsPanel.tsx
index 076aec40..b1a6b324 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletAnnotationsPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletAnnotationsPanel.tsx
@@ -75,8 +75,7 @@ export function KameletAnnotationsPanel() {
return (
<GridItem span={span}>
<FormGroup label={label} fieldId={key} isRequired>
- {/* eslint-disable-next-line react/jsx-no-undef */}
- <ToggleGroup aria-label={key}>
+ <ToggleGroup aria-label={key} id={key} name={key}>
{values.map(value =>
<ToggleGroupItem
key={value}
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
index fb04c267..31aa866b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/karavan.css
@@ -343,6 +343,7 @@
flex-direction: column;
justify-content: space-between;
margin-bottom: 20px;
+ padding-bottom: 30px;
}
.karavan .pf-v5-c-drawer__splitter {
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
index 23f8228a..d8adbd08 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
@@ -37,7 +37,7 @@ import "@patternfly/patternfly/patternfly.css";
import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
import {ToDefinition} from "karavan-core/lib/model/CamelDefinition";
import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
@@ -49,7 +49,7 @@ import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
import {usePropertiesHook} from "../usePropertiesHook";
-import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
+import {useIntegrationStore} from "../../DesignerStore";
import {shallow} from "zustand/shallow";
const prefix = "parameters";
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
index b07e8beb..70651b21 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
@@ -88,7 +88,7 @@ export function DslPropertyField(props: Props) {
const [integration] = useIntegrationStore((state) => [state.integration], shallow)
const [dark] = useDesignerStore((s) => [s.dark], shallow)
- const [isShowAdvanced, setIsShowAdvanced] = useState<Map<string, boolean>>(new Map<string, boolean>());
+ const [isShowAdvanced, setIsShowAdvanced] = useState<string[]>([]);
const [arrayValues, setArrayValues] = useState<Map<string, string>>(new Map<string, string>());
const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
const [showEditor, setShowEditor] = useState<boolean>(false);
@@ -654,19 +654,23 @@ export function DslPropertyField(props: Props) {
</div>
)
}
-
function getExpandableComponentParameters(properties: ComponentProperty[], label: string) {
const element = props.element;
+
return (
<ExpandableSection
toggleText={label}
onToggle={(_event, isExpanded) => {
setIsShowAdvanced(prevState => {
- prevState.set(label, !prevState.get(label));
+ if (isExpanded && !isShowAdvanced.includes(label)) {
+ prevState = [...prevState, label]
+ } else {
+ prevState = prevState.filter(s => s!== label);
+ }
return prevState;
})
}}
- isExpanded={isShowAdvanced.has(label) && isShowAdvanced.get(label)}>
+ isExpanded={isShowAdvanced.includes(label)}>
<div className="parameters">
{properties.map(kp =>
<ComponentParameterField