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/02 22:57:50 UTC
[camel-karavan] branch main updated: Kamelets Dependencies UI #315
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 76a18789 Kamelets Dependencies UI #315
76a18789 is described below
commit 76a187896d4ca8e66726fb2dcd67f456a22b9626
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Mon Oct 2 18:57:40 2023 -0400
Kamelets Dependencies UI #315
---
.../kamelet/KameletDefinitionPropertyCard.tsx | 2 +-
.../designer/kamelet/KameletDefinitionsPanel.tsx | 26 ++-
.../designer/kamelet/KameletDependenciesCard.tsx | 113 +++++++++++
.../src/designer/kamelet/KameletProperties.tsx | 209 +--------------------
4 files changed, 137 insertions(+), 213 deletions(-)
diff --git a/karavan-designer/src/designer/kamelet/KameletDefinitionPropertyCard.tsx b/karavan-designer/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
index 47c85e18..cf42ef6c 100644
--- a/karavan-designer/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
+++ b/karavan-designer/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
@@ -175,7 +175,7 @@ export function KameletDefinitionPropertyCard(props: Props) {
<Label
key={val}
id={val}
- color="blue"
+ color="grey"
isEditable
onClose={() => deleteEnum(val)}
onEditCancel={(_event, prevText) => {}}
diff --git a/karavan-designer/src/designer/kamelet/KameletDefinitionsPanel.tsx b/karavan-designer/src/designer/kamelet/KameletDefinitionsPanel.tsx
index 0eb3f521..0d3f04a4 100644
--- a/karavan-designer/src/designer/kamelet/KameletDefinitionsPanel.tsx
+++ b/karavan-designer/src/designer/kamelet/KameletDefinitionsPanel.tsx
@@ -25,7 +25,7 @@ import {
Form,
FormGroup,
Grid,
- GridItem,
+ GridItem, TextArea,
TextInput,
} from '@patternfly/react-core';
import '../karavan.css';
@@ -36,7 +36,7 @@ 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 {Simulate} from "react-dom/test-utils";
+import {KameletDependenciesCard} from "./KameletDependenciesCard";
export function KameletDefinitionsPanel() {
@@ -58,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>
@@ -70,6 +70,18 @@ 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() {
@@ -102,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>
@@ -133,6 +145,8 @@ export function KameletDefinitionsPanel() {
</Form>
</CardBody>
</Card>
+ <div style={{height: "20px"}}/>
+ <KameletDependenciesCard/>
</>
)
diff --git a/karavan-designer/src/designer/kamelet/KameletDependenciesCard.tsx b/karavan-designer/src/designer/kamelet/KameletDependenciesCard.tsx
new file mode 100644
index 00000000..893c897b
--- /dev/null
+++ b/karavan-designer/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-designer/src/designer/kamelet/KameletProperties.tsx b/karavan-designer/src/designer/kamelet/KameletProperties.tsx
index fc8f188f..e5a8cfc5 100644
--- a/karavan-designer/src/designer/kamelet/KameletProperties.tsx
+++ b/karavan-designer/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>
)
}