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/04 19:19:26 UTC

[camel-karavan] branch main updated (76a18789 -> f5192aea)

This is an automated email from the ASF dual-hosted git repository.

marat pushed a change to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git


    from 76a18789 Kamelets Dependencies UI #315
     new cdde30d4 Kamelets Dependencies UI #315
     new f5192aea Fix #927

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../src/core/model/IntegrationDefinition.ts        |  21 ++-
 karavan-core/test/kamelet.spec.ts                  |   3 +-
 .../public/example/aws-s3-source.kamelet.yaml      | 190 +++++++++++++++++++
 ...ependenciesCard.tsx => KameletTypesOutCard.tsx} |   2 +-
 karavan-vscode/icons/dark/rocket.svg               |  69 -------
 karavan-vscode/icons/dark/wand.svg                 |  85 ---------
 karavan-vscode/icons/light/rocket.svg              |   1 -
 karavan-vscode/icons/light/wand.svg                |   1 -
 karavan-vscode/package.json                        |  10 +-
 .../src/main/resources/application.properties      |   2 +-
 .../kamelet/KameletDefinitionPropertyCard.tsx      | 125 +++++++++++-
 .../designer/kamelet/KameletDefinitionsPanel.tsx   |  59 +++++-
 .../designer/kamelet/KameletDependenciesCard.tsx   |   0
 .../src/designer/kamelet/KameletProperties.tsx     | 209 +--------------------
 .../src/designer/kamelet/KameletTypesOutCard.tsx   |   2 +-
 .../main/webui/src/designer/kamelet/kamelet.css    |   1 +
 16 files changed, 388 insertions(+), 392 deletions(-)
 create mode 100644 karavan-designer/public/example/aws-s3-source.kamelet.yaml
 copy karavan-designer/src/designer/kamelet/{KameletDependenciesCard.tsx => KameletTypesOutCard.tsx} (99%)
 delete mode 100644 karavan-vscode/icons/dark/rocket.svg
 delete mode 100644 karavan-vscode/icons/dark/wand.svg
 delete mode 100644 karavan-vscode/icons/light/rocket.svg
 delete mode 100644 karavan-vscode/icons/light/wand.svg
 copy {karavan-designer => karavan-web/karavan-app/src/main/webui}/src/designer/kamelet/KameletDependenciesCard.tsx (100%)
 copy karavan-designer/src/designer/kamelet/KameletDependenciesCard.tsx => karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletTypesOutCard.tsx (99%)


[camel-karavan] 01/02: Kamelets Dependencies UI #315

Posted by ma...@apache.org.
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 cdde30d412b7aed8477f5902167cda3ef744da2e
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Oct 3 20:06:52 2023 -0400

    Kamelets Dependencies UI #315
---
 .../src/core/model/IntegrationDefinition.ts        |  21 ++-
 karavan-core/test/kamelet.spec.ts                  |   3 +-
 .../public/example/aws-s3-source.kamelet.yaml      | 190 +++++++++++++++++++
 .../src/designer/kamelet/KameletTypesOutCard.tsx   | 113 +++++++++++
 .../src/main/resources/application.properties      |   2 +-
 .../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 +++++++++++
 .../main/webui/src/designer/kamelet/kamelet.css    |   1 +
 11 files changed, 723 insertions(+), 226 deletions(-)

diff --git a/karavan-core/src/core/model/IntegrationDefinition.ts b/karavan-core/src/core/model/IntegrationDefinition.ts
index 974f8e5e..fb1c11f3 100644
--- a/karavan-core/src/core/model/IntegrationDefinition.ts
+++ b/karavan-core/src/core/model/IntegrationDefinition.ts
@@ -32,6 +32,23 @@ export class DefinitionProperty {
     }
 }
 
+export class MediaType {
+    mediaType: string = '';
+
+    public constructor(init?: Partial<MediaType>) {
+        Object.assign(this, init);
+    }
+}
+
+export class Types {
+    in?: MediaType = new MediaType();
+    out?: MediaType = new MediaType();
+
+    public constructor(init?: Partial<Types>) {
+        Object.assign(this, init);
+    }
+}
+
 export class Definition {
     title: string = '';
     description: string = '';
@@ -46,7 +63,7 @@ export class Definition {
 
 export class Spec {
     definition?: Definition;
-    types?: any;
+    types?: Types;
     flows?: any[] = [];
     template?: any;
     dependencies?: string[];
@@ -107,7 +124,7 @@ export class Integration {
         if (type === 'kamelet') {
             i.metadata.annotations = new MetadataAnnotations({})
             i.spec.definition = new Definition({})
-            i.spec.types = {}
+            i.spec.types = new Types();
         }
 
         return i;
diff --git a/karavan-core/test/kamelet.spec.ts b/karavan-core/test/kamelet.spec.ts
index 65e94987..750d9295 100644
--- a/karavan-core/test/kamelet.spec.ts
+++ b/karavan-core/test/kamelet.spec.ts
@@ -28,7 +28,6 @@ describe('Kamelet <=> YAML', () => {
     it('Yaml to Kamelet', () => {
         const yaml = fs.readFileSync('test/postgresql-source.kamelet.yaml',{encoding:'utf8', flag:'r'});
         const i = CamelDefinitionYaml.yamlToIntegration("postgresql-source.kamelet.yaml", yaml);
-        // console.log(i)
     });
 
     it('Kamelet to YAML with beans', () => {
@@ -44,6 +43,8 @@ describe('Kamelet <=> YAML', () => {
         i.spec.flows?.push(b);
         const a = new MetadataAnnotations({"camel.apache.org/kamelet.group" : "hello world"})
         i.metadata.annotations = a
+
+        // console.log(CamelDefinitionYaml.integrationToYaml(i))
     });
 
     it('Kamelet to YAML without beans', () => {
diff --git a/karavan-designer/public/example/aws-s3-source.kamelet.yaml b/karavan-designer/public/example/aws-s3-source.kamelet.yaml
new file mode 100644
index 00000000..e20d11d7
--- /dev/null
+++ b/karavan-designer/public/example/aws-s3-source.kamelet.yaml
@@ -0,0 +1,190 @@
+apiVersion: camel.apache.org/v1
+kind: Kamelet
+metadata:
+  name: aws-s3-source
+  annotations:
+    camel.apache.org/kamelet.support.level: "Stable"
+    camel.apache.org/catalog.version: "4.1.0-SNAPSHOT"
+    camel.apache.org/kamelet.icon: "data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIGlkPSJMYXllcl8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHg9IjAiIHk9IjAiIHZpZXdCb3g9IjAgMCAyNDguMiAzMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxzdHlsZT4uc3QyOHtmaWxsOiM4YzMxMjN9LnN0Mjl7ZmlsbDojZTA1MjQzfTwvc3R5bGU+PHBhdGggY2xhc3M9InN0MjgiIGQ9Ik0yMCA1Mi4xTDAgNjJ2MTc1LjVsMjAgOS45LjEtLjFWNTIuMmwtLjEtLjEiLz48cGF0aCBjbGFzcz0ic3QyOSIgZD0iTTEyNyAyMjJMMjAgMjQ3LjVWNTIuMUwxMjcgNzd2MTQ1Ii8+PHBhdGggY2xhc3M9InN0MjgiIG [...]
+    camel.apache.org/provider: "Apache Software Foundation"
+    camel.apache.org/kamelet.group: "AWS S3"
+    camel.apache.org/kamelet.namespace: "AWS"
+  labels:
+    camel.apache.org/kamelet.type: "source"
+spec:
+  definition:
+    title: "AWS S3 Source"
+    description: |-
+      Receive data from an Amazon S3 Bucket.
+
+      The basic authentication method for the S3 service is to specify an access key and a secret key. These parameters are optional because the Kamelet provides a default credentials provider.
+      
+      If you use the default credentials provider, the S3 client loads the credentials through this provider and doesn't use the basic authentication method.
+
+      Two headers will be duplicated with different names for clarity at sink level, CamelAwsS3Key will be duplicated into aws.s3.key and CamelAwsS3BucketName will be duplicated in aws.s3.bucket.name
+    required:
+      - bucketNameOrArn
+      - region
+    type: object
+    properties:
+      bucketNameOrArn:
+        title: Bucket Name
+        description: The S3 Bucket name or Amazon Resource Name (ARN).
+        type: string
+      deleteAfterRead:
+        title: Auto-delete Objects
+        description: Specifies to delete objects after consuming them.
+        type: boolean
+        x-descriptors:
+          - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+        default: true
+      accessKey:
+        title: Access Key
+        description: The access key obtained from AWS.
+        type: string
+        format: password
+        x-descriptors:
+          - urn:alm:descriptor:com.tectonic.ui:password
+          - urn:camel:group:credentials
+      secretKey:
+        title: Secret Key
+        description: The secret key obtained from AWS.
+        type: string
+        format: password
+        x-descriptors:
+          - urn:alm:descriptor:com.tectonic.ui:password
+          - urn:camel:group:credentials
+      region:
+        title: AWS Region
+        description: The AWS region to access.
+        type: string
+        enum: ["ap-south-1", "eu-south-1", "us-gov-east-1", "me-central-1", "ca-central-1", "eu-central-1", "us-iso-west-1", "us-west-1", "us-west-2", "af-south-1", "eu-north-1", "eu-west-3", "eu-west-2", "eu-west-1", "ap-northeast-3", "ap-northeast-2", "ap-northeast-1", "me-south-1", "sa-east-1", "ap-east-1", "cn-north-1", "us-gov-west-1", "ap-southeast-1", "ap-southeast-2", "us-iso-east-1", "ap-southeast-3", "us-east-1", "us-east-2", "cn-northwest-1", "us-isob-east-1", "aws-global", "a [...]
+      autoCreateBucket:
+        title: Autocreate Bucket
+        description: Specifies to automatically create the S3 bucket.
+        type: boolean
+        x-descriptors:
+          - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+        default: false
+      prefix:
+        title: Prefix
+        description: The AWS S3 bucket prefix to consider while searching.
+        type: string
+        example: 'folder/'
+      ignoreBody:
+        title: Ignore Body
+        description: If true, the S3 Object body is ignored. Setting this to true overrides any behavior defined by the `includeBody` option. If false, the S3 object is put in the body.
+        type: boolean
+        x-descriptors:
+          - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+        default: false
+      useDefaultCredentialsProvider:
+        title: Default Credentials Provider
+        description: If true, the S3 client loads credentials through a default credentials provider. If false, it uses the basic authentication method (access key and secret key).
+        type: boolean
+        x-descriptors:
+          - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+        default: false
+      uriEndpointOverride:
+        title: Overwrite Endpoint URI
+        description: The overriding endpoint URI. To use this option, you must also select the `overrideEndpoint` option.
+        type: string
+      overrideEndpoint:
+        title: Endpoint Overwrite
+        description: Select this option to override the endpoint URI. To use this option, you must also provide a URI for the `uriEndpointOverride` option.
+        type: boolean
+        x-descriptors:
+          - 'urn:alm:descriptor:com.tectonic.ui:checkbox'
+        default: false
+      delay:
+        title: Delay
+        description: The number of milliseconds before the next poll of the selected bucket.
+        type: integer
+        default: 500
+  dataTypes:
+    out:
+      default: binary
+      headers:
+        CamelAwsS3BucketName:
+          title: S3 Bucket Name
+          description: The bucket name which has been used to retrieve objects
+          type: string
+        CamelAwsS3Key:
+          title: S3 Key
+          description: The key under which the retrieved object is stored
+          type: string
+        CamelAwsS3ContentType:
+          title: Content Type
+          description: The content type of the retrieved object.
+          default: application/octet-stream
+          type: string
+        CamelAwsS3ETag:
+          title: ETag Value
+          description: |-
+            The hex encoded 128-bit MD5 digest of the associated object according to RFC 1864. 
+            This data is used as an integrity check to verify that the data received by the caller is the same data that was sent by Amazon S3.
+          type: string
+      types:
+        binary:
+          format: "application-octet-stream"
+          description: Default binary representation of the S3 object retrieved from the bucket.
+          mediaType: application/octet-stream
+        cloudevents:
+          format: "aws2-s3:application-cloudevents"
+          description: |-
+            Output data type represents AWS S3 get object response as CloudEvent V1. The data type sets Camel specific CloudEvent headers on the exchange with
+            respective data from the S3 bucket and its derived object.
+          headers:
+            CamelCloudEventID:
+              title: CloudEvent ID
+              description: The Camel exchange id set as event id
+              type: string
+            CamelCloudEventType:
+              title: CloudEvent Type
+              description: The event type
+              default: "org.apache.camel.event.aws.s3.getObject"
+              type: string
+            CamelCloudEventSource:
+              title: CloudEvent Source
+              description: The event source. By default, the S3 bucket name with prefix "aws.s3.bucket.".
+              type: string
+            CamelCloudEventSubject:
+              title: CloudEvent Subject
+              description: The event subject. Usually the S3 key.
+              type: string
+            CamelCloudEventTime:
+              title: CloudEvent Time
+              description: The exchange creation timestamp as event time.
+              type: string
+  dependencies:
+    - "camel:core"
+    - "camel:aws2-s3"
+    - "mvn:org.apache.camel.kamelets:camel-kamelets-utils:4.1.0-SNAPSHOT"
+    - "camel:kamelet"
+  template:
+    beans:
+      - name: renameHeaders
+        type: "#class:org.apache.camel.kamelets.utils.headers.DuplicateNamingHeaders"
+        properties:
+          prefix: 'CamelAwsS3'
+          renamingPrefix: 'aws.s3.'
+          mode: 'filtering'
+          selectedHeaders: 'CamelAwsS3Key,CamelAwsS3BucketName'
+    from:
+      uri: "aws2-s3:{{bucketNameOrArn}}"
+      parameters:
+        autoCreateBucket: "{{autoCreateBucket}}"
+        secretKey: "{{?secretKey}}"
+        accessKey: "{{?accessKey}}"
+        region: "{{region}}"
+        ignoreBody: "{{ignoreBody}}"
+        deleteAfterRead: "{{deleteAfterRead}}"
+        prefix: "{{?prefix}}"
+        useDefaultCredentialsProvider: "{{useDefaultCredentialsProvider}}"
+        uriEndpointOverride: "{{?uriEndpointOverride}}"
+        overrideEndpoint: "{{overrideEndpoint}}"
+        delay: "{{delay}}"
+      steps:
+        - process:
+            ref: "{{renameHeaders}}"
+        - to: "kamelet:sink"
\ No newline at end of file
diff --git a/karavan-designer/src/designer/kamelet/KameletTypesOutCard.tsx b/karavan-designer/src/designer/kamelet/KameletTypesOutCard.tsx
new file mode 100644
index 00000000..76b590ee
--- /dev/null
+++ b/karavan-designer/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-web/karavan-app/src/main/resources/application.properties b/karavan-web/karavan-app/src/main/resources/application.properties
index 67990ecb..13a50355 100644
--- a/karavan-web/karavan-app/src/main/resources/application.properties
+++ b/karavan-web/karavan-app/src/main/resources/application.properties
@@ -121,7 +121,7 @@ quarkus.quinoa.enable-spa-routing=true
 quarkus.http.enable-compression=true
 quarkus.log.level=INFO
 quarkus.banner.enabled=false
-quarkus.package.type=uber-jar
+quarkus.package.type=fast-jar
 quarkus.docker.dockerfile-jvm-path=src/main/docker/Dockerfile.jdk
 #quarkus.docker.dockerfile-jvm-path=src/main/docker/Dockerfile.minimal
 quarkus.container-image.builder=docker
diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionPropertyCard.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
index d8933df4..cf42ef6c 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionPropertyCard.tsx
+++ b/karavan-web/karavan-app/src/main/webui/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-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionsPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionsPanel.tsx
index 009a54ac..0d3f04a4 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDefinitionsPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/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-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDependenciesCard.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletDependenciesCard.tsx
new file mode 100644
index 00000000..893c897b
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/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-web/karavan-app/src/main/webui/src/designer/kamelet/KameletProperties.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletProperties.tsx
index fc8f188f..e5a8cfc5 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletProperties.tsx
+++ b/karavan-web/karavan-app/src/main/webui/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-web/karavan-app/src/main/webui/src/designer/kamelet/KameletTypesOutCard.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/KameletTypesOutCard.tsx
new file mode 100644
index 00000000..76b590ee
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/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-web/karavan-app/src/main/webui/src/designer/kamelet/kamelet.css b/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/kamelet.css
index bbdf28a9..c72acad2 100644
--- a/karavan-web/karavan-app/src/main/webui/src/designer/kamelet/kamelet.css
+++ b/karavan-web/karavan-app/src/main/webui/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);
 }


[camel-karavan] 02/02: Fix #927

Posted by ma...@apache.org.
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 f5192aea56db6a6736c9e1352af93b435d9c7a62
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Oct 4 15:19:12 2023 -0400

    Fix #927
---
 karavan-vscode/icons/dark/rocket.svg  | 69 ----------------------------
 karavan-vscode/icons/dark/wand.svg    | 85 -----------------------------------
 karavan-vscode/icons/light/rocket.svg |  1 -
 karavan-vscode/icons/light/wand.svg   |  1 -
 karavan-vscode/package.json           | 10 +----
 5 files changed, 2 insertions(+), 164 deletions(-)

diff --git a/karavan-vscode/icons/dark/rocket.svg b/karavan-vscode/icons/dark/rocket.svg
deleted file mode 100644
index c2d6a737..00000000
--- a/karavan-vscode/icons/dark/rocket.svg
+++ /dev/null
@@ -1,69 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   width="32px"
-   height="32px"
-   viewBox="0 0 32 32"
-   id="icon"
-   version="1.1"
-   sodipodi:docname="rocket-svgrepo-com.svg"
-   inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:dc="http://purl.org/dc/elements/1.1/">
-  <sodipodi:namedview
-     id="namedview836"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     showgrid="false"
-     inkscape:zoom="22.46875"
-     inkscape:cx="0.89012517"
-     inkscape:cy="16.534075"
-     inkscape:window-width="2049"
-     inkscape:window-height="969"
-     inkscape:window-x="78"
-     inkscape:window-y="25"
-     inkscape:window-maximized="0"
-     inkscape:current-layer="icon" />
-  <defs
-     id="defs826">
-    <style
-       id="style824">.cls-1{fill:none;}</style>
-  </defs>
-  <title
-     id="title828">rocket</title>
-  <rect
-     x="6.34"
-     y="19"
-     width="11.31"
-     height="2"
-     transform="translate(-10.63 14.34) rotate(-45)"
-     id="rect830"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <path
-     d="M17,30a1,1,0,0,1-.37-.07,1,1,0,0,1-.62-.79l-1-7,2-.28.75,5.27L21,24.52V17a1,1,0,0,1,.29-.71l4.07-4.07A8.94,8.94,0,0,0,28,5.86V4H26.14a8.94,8.94,0,0,0-6.36,2.64l-4.07,4.07A1,1,0,0,1,15,11H7.48L4.87,14.26l5.27.75-.28,2-7-1a1,1,0,0,1-.79-.62,1,1,0,0,1,.15-1l4-5A1,1,0,0,1,7,9h7.59l3.77-3.78A10.92,10.92,0,0,1,26.14,2H28a2,2,0,0,1,2,2V5.86a10.92,10.92,0,0,1-3.22,7.78L23,17.41V25a1,1,0,0,1-.38.78l-5,4A1,1,0,0,1,17,30Z"
-     id="path832"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <rect
-     id="_Transparent_Rectangle_"
-     data-name="&lt;Transparent Rectangle&gt;"
-     class="cls-1"
-     width="32"
-     height="32" />
-  <metadata
-     id="metadata918">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:title>rocket</dc:title>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-</svg>
diff --git a/karavan-vscode/icons/dark/wand.svg b/karavan-vscode/icons/dark/wand.svg
deleted file mode 100644
index 699be396..00000000
--- a/karavan-vscode/icons/dark/wand.svg
+++ /dev/null
@@ -1,85 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<svg
-   width="32px"
-   height="32px"
-   viewBox="0 0 32 32"
-   id="icon"
-   version="1.1"
-   sodipodi:docname="wand.svg"
-   inkscape:version="1.1.2 (b8e25be8, 2022-02-05)"
-   xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
-   xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
-   xmlns="http://www.w3.org/2000/svg"
-   xmlns:svg="http://www.w3.org/2000/svg"
-   xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
-   xmlns:cc="http://creativecommons.org/ns#"
-   xmlns:dc="http://purl.org/dc/elements/1.1/">
-  <sodipodi:namedview
-     id="namedview840"
-     pagecolor="#ffffff"
-     bordercolor="#666666"
-     borderopacity="1.0"
-     inkscape:pageshadow="2"
-     inkscape:pageopacity="0.0"
-     inkscape:pagecheckerboard="0"
-     showgrid="false"
-     inkscape:zoom="22.46875"
-     inkscape:cx="9.8581363"
-     inkscape:cy="16.534075"
-     inkscape:window-width="2077"
-     inkscape:window-height="969"
-     inkscape:window-x="74"
-     inkscape:window-y="25"
-     inkscape:window-maximized="0"
-     inkscape:current-layer="icon" />
-  <defs
-     id="defs826">
-    <style
-       id="style824">.cls-1{fill:none;}</style>
-  </defs>
-  <title
-     id="title828">magic-wand</title>
-  <path
-     d="M29.4141,24,12,6.5859a2.0476,2.0476,0,0,0-2.8281,0l-2.586,2.586a2.0021,2.0021,0,0,0,0,2.8281L23.999,29.4141a2.0024,2.0024,0,0,0,2.8281,0l2.587-2.5865a1.9993,1.9993,0,0,0,0-2.8281ZM8,10.5859,10.5859,8l5,5-2.5866,2.5869-5-5ZM25.4131,28l-11-10.999L17,14.4141l11,11Z"
-     id="path830"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <rect
-     x="2.5858"
-     y="14.5858"
-     width="2.8284"
-     height="2.8284"
-     transform="translate(-10.1421 7.5147) rotate(-45)"
-     id="rect832"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <rect
-     x="14.5858"
-     y="2.5858"
-     width="2.8284"
-     height="2.8284"
-     transform="translate(1.8579 12.4853) rotate(-45)"
-     id="rect834"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <rect
-     x="2.5858"
-     y="2.5858"
-     width="2.8284"
-     height="2.8284"
-     transform="translate(-1.6569 4) rotate(-45)"
-     id="rect836"
-     style="fill:#c5c5c5;fill-opacity:1" />
-  <rect
-     id="_Transparent_Rectangle_"
-     data-name="&lt;Transparent Rectangle&gt;"
-     class="cls-1"
-     width="32"
-     height="32" />
-  <metadata
-     id="metadata922">
-    <rdf:RDF>
-      <cc:Work
-         rdf:about="">
-        <dc:title>magic-wand</dc:title>
-      </cc:Work>
-    </rdf:RDF>
-  </metadata>
-</svg>
diff --git a/karavan-vscode/icons/light/rocket.svg b/karavan-vscode/icons/light/rocket.svg
deleted file mode 100644
index 2d3b0221..00000000
--- a/karavan-vscode/icons/light/rocket.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="32px" height="32px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:none;}</style></defs><title>rocket</title><rect x="6.34" y="19" width="11.31" height="2" transform="translate(-10.63 14.34) rotate(-45)"/><path d="M17,30a1,1,0,0,1-.37-.07,1,1,0,0,1-.62-.79l-1-7,2-.28.75,5.27L21,24.52V17a1,1,0,0,1,.29-.71l4.07-4.07A8.94,8.94,0,0,0,28,5.86V4H26.14a8.94,8.94,0,0,0-6.36,2.64l-4.07,4.07A1,1,0,0,1,15,11H7.48L4.87,14.26l5.27.75-.28,2-7-1a1, [...]
\ No newline at end of file
diff --git a/karavan-vscode/icons/light/wand.svg b/karavan-vscode/icons/light/wand.svg
deleted file mode 100644
index 2afc8394..00000000
--- a/karavan-vscode/icons/light/wand.svg
+++ /dev/null
@@ -1 +0,0 @@
-<svg width="32px" height="32px" viewBox="0 0 32 32" id="icon" xmlns="http://www.w3.org/2000/svg"><defs><style>.cls-1{fill:none;}</style></defs><title>magic-wand--filled</title><path d="M29.4141,24,12,6.5859a2.0476,2.0476,0,0,0-2.8281,0l-2.586,2.586a2.0021,2.0021,0,0,0,0,2.8281L23.999,29.4141a2.0024,2.0024,0,0,0,2.8281,0l2.587-2.5865a1.9993,1.9993,0,0,0,0-2.8281ZM8,10.5859,10.5859,8l5,5-2.5866,2.5869-5-5Z"/><rect x="2.5858" y="14.5858" width="2.8284" height="2.8284" transform="translate(- [...]
\ No newline at end of file
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 7dbe0d7c..a9d8cfa8 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -470,10 +470,7 @@
       {
         "command": "karavan.open",
         "title": "Karavan: Open",
-        "icon": {
-          "light": "./icons/light/wand.svg",
-          "dark": "./icons/dark/wand.svg"
-        }
+        "icon": "$(wand)"
       },
       {
         "command": "karavan.open-file",
@@ -482,10 +479,7 @@
       {
         "command": "karavan.run-project-jbang",
         "title": "Karavan: JBang run",
-        "icon": {
-          "light": "./icons/light/rocket.svg",
-          "dark": "./icons/dark/rocket.svg"
-        }
+        "icon": "$(rocket)"
       },
       {
         "command": "karavan.run-project-runtime",