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 7a62be7  Saas feature32 (#423)
7a62be7 is described below

commit 7a62be79beae316a1e07d6f91b792bff18adef61
Author: Marat Gubaidullin <marat.gubaidul...@gmail.com>
AuthorDate: Mon Jul 25 17:38:38 2022 -0400

    Saas feature32 (#423)
    
    * Vs code sync
    
    * Selectors Improvement
---
 .../org/apache/camel/karavan/api/GitResource.java  |   5 -
 .../camel/karavan/api/KubernetesResource.java      |  22 +-
 .../apache/camel/karavan/api/OpenApiResource.java  |  91 -------
 .../camel/karavan/service/GeneratorService.java    |   3 +-
 .../camel/karavan/service/KubernetesService.java   |  24 ++
 karavan-builder/openshift/karavan-acl.yaml         |  23 ++
 .../openshift/karavan-quarkus-task.yaml            |   3 -
 karavan-demo/postman/docs/README.md                |   6 +-
 .../openshift-manifests/instances/amq-broker.yaml  |   2 -
 .../openshift-manifests/instances/amq-streams.yaml |   1 -
 .../instances/kustomization.yaml                   |   1 -
 .../openshift-manifests/instances/postgresql.yaml  |   2 -
 .../postman/openshift-manifests/kustomization.yaml |   8 -
 .../operators/kustomization.yaml                   |   1 -
 .../openshift-manifests/operators/namespace.yaml   |   7 -
 .../operators/operator-group.yaml                  |   4 +-
 karavan-designer/src/designer/karavan.css          |   1 +
 .../src/designer/route/DslSelector.tsx             |  73 ++++--
 .../src/designer/route/RouteDesigner.tsx           |  54 ++--
 .../designer/route/property/DslPropertyField.tsx   |  12 +-
 .../route/property/KameletPropertyField.tsx        |  12 +-
 .../designer/route/property/KubernetesSelector.tsx | 282 ++++++++++++---------
 karavan-vscode/webview/builder/BuilderPage.tsx     |  16 ++
 karavan-vscode/webview/builder/FileSelector.tsx    |  16 ++
 karavan-vscode/webview/builder/ProfileSelector.tsx |  16 ++
 karavan-vscode/webview/builder/PropertiesTable.tsx |  18 +-
 .../webview/components/ComponentCard.tsx           |  17 +-
 .../webview/components/ComponentModal.tsx          |  16 ++
 .../webview/components/ComponentsPage.tsx          |  16 ++
 karavan-vscode/webview/eip/EipCard.tsx             |  16 ++
 karavan-vscode/webview/eip/EipModal.tsx            |  16 ++
 karavan-vscode/webview/eip/EipPage.tsx             |  16 ++
 karavan-vscode/webview/kamelets/KameletCard.tsx    |  16 ++
 karavan-vscode/webview/kamelets/KameletModal.tsx   |  16 ++
 karavan-vscode/webview/kamelets/KameletsPage.tsx   |  16 ++
 35 files changed, 540 insertions(+), 308 deletions(-)

diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/GitResource.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/GitResource.java
index 1907537..713d09b 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/GitResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/GitResource.java
@@ -16,7 +16,6 @@
  */
 package org.apache.camel.karavan.api;
 
-import io.vertx.core.Vertx;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.model.ProjectFile;
 import org.apache.camel.karavan.service.GitService;
@@ -37,10 +36,6 @@ public class GitResource {
 
     @Inject
     InfinispanService infinispanService;
-
-    @Inject
-    Vertx vertx;
-
     @Inject
     GitService gitService;
 
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index 1a0476f..5654cf5 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -16,6 +16,10 @@
  */
 package org.apache.camel.karavan.api;
 
+import io.smallrye.mutiny.Multi;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
+import io.vertx.mutiny.core.eventbus.Message;
 import org.apache.camel.karavan.model.KaravanConfiguration;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
@@ -33,12 +37,14 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.List;
 import java.util.Optional;
 
 @Path("/kubernetes")
 public class KubernetesResource {
 
+    @Inject
+    EventBus eventBus;
+
     @Inject
     InfinispanService infinispanService;
 
@@ -184,4 +190,18 @@ public class KubernetesResource {
         }
         return Response.noContent().build();
     }
+
+    // TODO: implement log watch
+    @GET
+    @Path("/container/log/watch/{environment}/{name}")
+    @Produces(MediaType.SERVER_SENT_EVENTS)
+    public Multi<String> getContainerLogWatch(@HeaderParam("username") String 
username, @PathParam("environment") String environment, @PathParam("name") 
String name){
+        LOGGER.info("Start sourcing");
+        Optional<KaravanConfiguration.Environment> env = 
configuration.environments().stream().filter(e -> 
e.name().equals(environment)).findFirst();
+        if (env.isPresent()) {
+//            eventBus.publish(podName + "-" + namespace, new 
String(is.readNBytes(i)));
+//            kubernetesService.startContainerLogWatch(name, 
env.get().namespace());
+        }
+        return eventBus.<String>consumer(name + "-" + 
env.get().namespace()).toMulti().map(Message::body);
+    }
 }
\ No newline at end of file
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/OpenApiResource.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/OpenApiResource.java
deleted file mode 100644
index 2dd93d4..0000000
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/OpenApiResource.java
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * 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.
- */
-package org.apache.camel.karavan.api;
-
-import org.apache.camel.karavan.service.GeneratorService;
-import org.apache.camel.karavan.service.GitService;
-import org.eclipse.jgit.api.errors.GitAPIException;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-
-import javax.inject.Inject;
-import javax.ws.rs.*;
-import javax.ws.rs.core.MediaType;
-import java.io.IOException;
-import java.util.Map;
-import java.util.stream.Collectors;
-
-@Path("/openapi")
-public class OpenApiResource {
-
-    private static final String GITOPS_MODE = "gitops";
-    private static final String SERVERLESS_MODE = "serverless";
-
-    @ConfigProperty(name = "karavan.mode", defaultValue = "local")
-    String mode;
-
-//    @Inject
-//    FileSystemService fileSystemService;
-
-    @Inject
-    GeneratorService generatorService;
-
-    @Inject
-    GitService gitService;
-
-//    @GET
-//    @Produces(MediaType.APPLICATION_JSON)
-//    public Map<String, String> getList(@HeaderParam("username") String 
username) throws GitAPIException {
-//        if (mode.endsWith(GITOPS_MODE)) {
-//            String dir = gitService.pullIntegrations(username);
-//            return 
fileSystemService.getOpenApiList(dir).stream().collect(Collectors.toMap(s -> s, 
s-> ""));
-//        } else {
-//            return 
fileSystemService.getOpenApiList().stream().collect(Collectors.toMap(s -> s, 
s-> ""));
-//        }
-//    }
-//
-//    @GET
-//    @Produces(MediaType.TEXT_PLAIN)
-//    @Path("/{name}")
-//    public String getJson(@HeaderParam("username") String username, 
@PathParam("name") String name) throws GitAPIException {
-//        switch (mode){
-//            case GITOPS_MODE:
-//                String dir = gitService.pullIntegrations(username);
-//                return fileSystemService.getFile(dir, name);
-//            default:
-//                return fileSystemService.getIntegrationsFile(name);
-//        }
-//    }
-//
-//    @POST
-//    @Produces(MediaType.TEXT_PLAIN)
-//    @Consumes(MediaType.TEXT_PLAIN)
-//    @Path("/{name}/{generateRest}/{generateRoutes}/{integrationName}")
-//    public String save(@HeaderParam("username") String username,
-//                       @PathParam("name") String name,
-//                       @PathParam("integrationName") String integrationName,
-//                       @PathParam("generateRest") boolean generateRest,
-//                       @PathParam("generateRoutes") boolean generateRoutes,
-//                       String json) throws Exception {
-//        fileSystemService.saveIntegrationsFile(name, json);
-//        if (generateRest) {
-//            String yaml = generatorService.generate(json, generateRoutes);
-//            fileSystemService.saveIntegrationsFile(integrationName, yaml);
-//            return yaml;
-//        }
-//        return json;
-//    }
-}
\ No newline at end of file
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
index ffcae12..c8227f2 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
@@ -71,11 +71,12 @@ public class GeneratorService {
         s.append("camel.health.enabled=true").append(System.lineSeparator());
         
s.append("camel.health.exposure-level=full").append(System.lineSeparator());
 
+        
s.append("quarkus.kubernetes-client.trust-certs=true").append(System.lineSeparator());
         
s.append("quarkus.container-image.group=").append(imageGroup).append(System.lineSeparator());
         
s.append("quarkus.container-image.name=").append(project.getProjectId()).append(System.lineSeparator());
         
s.append("quarkus.openshift.route.expose=false").append(System.lineSeparator());
         
s.append("quarkus.openshift.part-of=").append(project.getProjectId()).append(System.lineSeparator());
-        
s.append("quarkus.kubernetes-client.trust-certs=true").append(System.lineSeparator());
+        
s.append("quarkus.openshift.replicas=1").append(System.lineSeparator());
         return s.toString();
     }
 }
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 4e76a63..efa64f5 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -22,6 +22,7 @@ import io.fabric8.kubernetes.api.model.Pod;
 import io.fabric8.kubernetes.api.model.Secret;
 import io.fabric8.kubernetes.client.DefaultKubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClient;
+import io.fabric8.kubernetes.client.dsl.LogWatch;
 import io.fabric8.openshift.api.model.DeploymentConfig;
 import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
@@ -34,6 +35,8 @@ import io.fabric8.tekton.pipeline.v1beta1.PipelineRunBuilder;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpec;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpecBuilder;
 import io.fabric8.tekton.pipeline.v1beta1.WorkspaceBindingBuilder;
+import io.vertx.core.json.JsonObject;
+import io.vertx.mutiny.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.DeploymentStatus;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.PodStatus;
@@ -43,6 +46,9 @@ import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.inject.Produces;
+import javax.inject.Inject;
+import java.io.IOException;
+import java.io.InputStream;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
@@ -53,6 +59,9 @@ import java.util.stream.Collectors;
 @ApplicationScoped
 public class KubernetesService {
 
+    @Inject
+    EventBus eventBus;
+
     @ConfigProperty(name = "kubernetes.namespace", defaultValue = "localhost")
     String currentNamespace;
 
@@ -116,6 +125,21 @@ public class KubernetesService {
         return logText;
     }
 
+
+    // TODO: implement log watch
+    public void startContainerLogWatch(String podName, String namespace) {
+        LogWatch logWatch = 
kubernetesClient().pods().inNamespace(namespace).withName(podName).watchLog();
+        InputStream is = logWatch.getOutput();
+        Integer i;
+        try {
+            while ((i = is.available()) != null) {
+                eventBus.publish(podName + "-" + namespace, new 
String(is.readNBytes(i)));
+            }
+        } catch (IOException e){
+            LOGGER.error(e);
+        }
+    }
+
     public List<PipelineRunLog> getPipelineRunLog(String pipelineRuneName, 
String namespace) {
         List<PipelineRunLog> result = new ArrayList<>(1);
         PipelineRun pipelineRun = getPipelineRun(pipelineRuneName, namespace);
diff --git a/karavan-builder/openshift/karavan-acl.yaml 
b/karavan-builder/openshift/karavan-acl.yaml
index eb86382..ec92c7f 100644
--- a/karavan-builder/openshift/karavan-acl.yaml
+++ b/karavan-builder/openshift/karavan-acl.yaml
@@ -77,4 +77,27 @@ roleRef:
 subjects:
   - kind: ServiceAccount
     name: karavan
+    namespace: karavan
+---
+# Pipeline shoulf have access to create rolebindings
+kind: Role
+apiVersion: rbac.authorization.k8s.io/v1
+metadata:
+  name: karavan-pipeline-rolebindings
+rules:
+  - apiGroups: ["", "rbac.authorization.k8s.io"]
+    resources: ["rolebindings"]
+    verbs: ["*"]
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: RoleBinding
+metadata:
+  name: karavan-pipeline-rolebindings
+roleRef:
+  kind: Role
+  apiGroup: rbac.authorization.k8s.io
+  name: karavan-pipeline-rolebindings
+subjects:
+  - kind: ServiceAccount
+    name: pipeline
     namespace: karavan
\ No newline at end of file
diff --git a/karavan-builder/openshift/karavan-quarkus-task.yaml 
b/karavan-builder/openshift/karavan-quarkus-task.yaml
index 1acfe14..f58101f 100644
--- a/karavan-builder/openshift/karavan-quarkus-task.yaml
+++ b/karavan-builder/openshift/karavan-quarkus-task.yaml
@@ -12,9 +12,6 @@ spec:
           #!/usr/bin/env bash
           CHECKOUT_DIR="/scripts"
 
-          ls -la $(workspaces.m2-cache.path)
-          ls -la $(workspaces.jbang-cache.path)
-
           if  [[ $GIT_REPOSITORY == https* ]] ;
           then
               replacer=https://$GIT_PASSWORD@
diff --git a/karavan-demo/postman/docs/README.md 
b/karavan-demo/postman/docs/README.md
index 7b4bb6d..fc9b2b6 100644
--- a/karavan-demo/postman/docs/README.md
+++ b/karavan-demo/postman/docs/README.md
@@ -58,7 +58,7 @@ Send message to `payments` queue
 
 
 ### Install AMQ and AMQ Streams Operators
-Also creates `postman` namespace required for the demo
+Also creates `karavan` namespace required for the demo
 ```
 cd ../openshift-manifests
 oc login --token=... --server=...
@@ -69,7 +69,7 @@ Check that operators are succesfully installed
 
 ### Create AMQ, Kafka and Postgres demo instances 
 ```
-oc apply -k instances
+oc apply -k instances -n karavan
 ```
 
 ### Package, build and deploy project
@@ -86,7 +86,7 @@ oc apply -k instances
 ```
 appsurl=$(oc get ingresses.config.openshift.io cluster  -o template --template 
'{{.spec.domain}}')
 
-curl -X POST -H "Content-Type: application/json" --data 
'{"id":"1","address":"666 Sin Street, Holy City"}' 
http://postman-postman.$appsurl/parcels
+curl -X POST -H "Content-Type: application/json" --data 
'{"id":"1","address":"666 Sin Street, Holy City"}' 
http://postman-karavan.$appsurl/parcels
 ```
 ### Publish payment
 Open AMQ7 Broker Management 
diff --git a/karavan-demo/postman/openshift-manifests/instances/amq-broker.yaml 
b/karavan-demo/postman/openshift-manifests/instances/amq-broker.yaml
index e83b987..7d307bb 100644
--- a/karavan-demo/postman/openshift-manifests/instances/amq-broker.yaml
+++ b/karavan-demo/postman/openshift-manifests/instances/amq-broker.yaml
@@ -3,7 +3,6 @@ kind: ActiveMQArtemis
 metadata:
   name: amq
   application: amq
-  namespace: postman
 spec:
   acceptors:
     - port: 61616
@@ -39,7 +38,6 @@ kind: Route
 apiVersion: route.openshift.io/v1
 metadata:
   name: console
-  namespace: amq
 spec:
   to:
     kind: Service
diff --git 
a/karavan-demo/postman/openshift-manifests/instances/amq-streams.yaml 
b/karavan-demo/postman/openshift-manifests/instances/amq-streams.yaml
index bd1ba85..be6dda8 100644
--- a/karavan-demo/postman/openshift-manifests/instances/amq-streams.yaml
+++ b/karavan-demo/postman/openshift-manifests/instances/amq-streams.yaml
@@ -2,7 +2,6 @@ kind: Kafka
 apiVersion: kafka.strimzi.io/v1beta2
 metadata:
   name: kafka
-  namespace: postman
 spec:
   kafka:
     version: 3.1.0
diff --git 
a/karavan-demo/postman/openshift-manifests/instances/kustomization.yaml 
b/karavan-demo/postman/openshift-manifests/instances/kustomization.yaml
index e0c09bd..70b1557 100644
--- a/karavan-demo/postman/openshift-manifests/instances/kustomization.yaml
+++ b/karavan-demo/postman/openshift-manifests/instances/kustomization.yaml
@@ -1,6 +1,5 @@
 apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
-namespace: postman
 resources:
 - postgresql.yaml
 - amq-broker.yaml
diff --git a/karavan-demo/postman/openshift-manifests/instances/postgresql.yaml 
b/karavan-demo/postman/openshift-manifests/instances/postgresql.yaml
index fe33b72..caed382 100644
--- a/karavan-demo/postman/openshift-manifests/instances/postgresql.yaml
+++ b/karavan-demo/postman/openshift-manifests/instances/postgresql.yaml
@@ -9,7 +9,6 @@ metadata:
     app.openshift.io/runtime: postgres
     deploymentconfig: postgres
   name: postgres
-  namespace: postman
   annotations:
     argocd.argoproj.io/sync-options: Validate=false
 spec:
@@ -154,7 +153,6 @@ metadata:
     app.kubernetes.io/instance: postgres
     app.kubernetes.io/part-of: postgres
   name: postgres
-  namespace: postman
 spec:
   ports:
   - name: postgresql
diff --git a/karavan-demo/postman/openshift-manifests/kustomization.yaml 
b/karavan-demo/postman/openshift-manifests/kustomization.yaml
deleted file mode 100644
index e011f60..0000000
--- a/karavan-demo/postman/openshift-manifests/kustomization.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: kustomize.config.k8s.io/v1beta1
-kind: Kustomization
-resources:
-  - namespace.yaml
-  - ./operators
-  # - ../postgres
-  - ./amq
-  - ./amq-streams
diff --git 
a/karavan-demo/postman/openshift-manifests/operators/kustomization.yaml 
b/karavan-demo/postman/openshift-manifests/operators/kustomization.yaml
index 01a6fbb..28eb264 100644
--- a/karavan-demo/postman/openshift-manifests/operators/kustomization.yaml
+++ b/karavan-demo/postman/openshift-manifests/operators/kustomization.yaml
@@ -2,7 +2,6 @@ apiVersion: kustomize.config.k8s.io/v1beta1
 kind: Kustomization
 
 resources:
-  - namespace.yaml 
   - operator-group.yaml
   - amq-operator.yaml
   - amq-streams-operator.yaml
diff --git a/karavan-demo/postman/openshift-manifests/operators/namespace.yaml 
b/karavan-demo/postman/openshift-manifests/operators/namespace.yaml
deleted file mode 100644
index 6a1655c..0000000
--- a/karavan-demo/postman/openshift-manifests/operators/namespace.yaml
+++ /dev/null
@@ -1,7 +0,0 @@
-apiVersion: v1
-kind: Namespace
-metadata:
-  annotations:
-    openshift.io/description: postman
-    openshift.io/display-name: postman
-  name: postman
diff --git 
a/karavan-demo/postman/openshift-manifests/operators/operator-group.yaml 
b/karavan-demo/postman/openshift-manifests/operators/operator-group.yaml
index 09b869c..fbbcc6c 100644
--- a/karavan-demo/postman/openshift-manifests/operators/operator-group.yaml
+++ b/karavan-demo/postman/openshift-manifests/operators/operator-group.yaml
@@ -1,7 +1,7 @@
 apiVersion: operators.coreos.com/v1
 kind: OperatorGroup
 metadata:
-  name: postman
+  name: karavan
 spec:
   targetNamespaces:
-  - postman
+  - karavan
diff --git a/karavan-designer/src/designer/karavan.css 
b/karavan-designer/src/designer/karavan.css
index bf5ba84..edad6d2 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -489,6 +489,7 @@
 .karavan .dsl-page .flows {
     width: 100%;
     position: relative;
+    margin-bottom: 80px;
 }
 
 .karavan .dsl-page .flows .add-flow {
diff --git a/karavan-designer/src/designer/route/DslSelector.tsx 
b/karavan-designer/src/designer/route/DslSelector.tsx
index 54612c8..73b5c35 100644
--- a/karavan-designer/src/designer/route/DslSelector.tsx
+++ b/karavan-designer/src/designer/route/DslSelector.tsx
@@ -17,7 +17,7 @@
 import React from 'react';
 import {
     Badge,
-    Card, CardBody, CardFooter, CardHeader, Form, FormGroup, Gallery, 
PageSection,
+    Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, 
Gallery, Modal, PageSection,
     Tab, Tabs, TabTitleText,
     Text, TextInput,
 } from '@patternfly/react-core';
@@ -28,10 +28,12 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 
 interface Props {
     onDslSelect: (dsl: DslMetaModel, parentId: string, position?: number | 
undefined) => void,
+    onClose?: () => void,
     parentId: string,
     parentDsl?: string,
     showSteps: boolean,
     dark: boolean,
+    isOpen: boolean,
     position?: number
     tabIndex?: string | number
 }
@@ -45,10 +47,11 @@ export class DslSelector extends React.Component<Props, 
State> {
 
     public state: State = {
         tabIndex: this.props.tabIndex ? this.props.tabIndex : 
CamelUi.getSelectorModelTypes(this.props.parentDsl, this.props.showSteps)[0][0],
-    };
+    }
 
 
     selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: 
string | number) => {
+        console.log(eventKey)
         this.setState({tabIndex: eventKey})
     }
 
@@ -103,7 +106,8 @@ export class DslSelector extends React.Component<Props, 
State> {
                         </div>}
                     {dsl.navigation.toLowerCase() === "component"
                         && <div className="footer" style={{justifyContent: 
"flex-start"}}>
-                            {dsl.labels.split(',').map((s: string) => <Badge 
key={s} isRead className="labels">{s}</Badge>)}
+                            {dsl.labels.split(',').map((s: string,  i: number) 
=> <Badge key={s + i} isRead
+                                                                               
          className="labels">{s}</Badge>)}
                             <Badge isRead 
className="version">{dsl.version}</Badge>
                         </div>
                     }
@@ -114,26 +118,49 @@ export class DslSelector extends React.Component<Props, 
State> {
 
     render() {
         const parentDsl = this.props.parentDsl;
+        const title = parentDsl === undefined ? "Select source/from" : "Select 
step";
+        const labelText: string = this.state.tabIndex ? 
this.state.tabIndex.toString() : "";
         return (
-            <PageSection variant={this.props.dark ? "darker" : "light"}>
-                {this.searchInput()}
-                <Tabs data-tour="selector-tabs" style={{overflow: 'hidden'}} 
activeKey={this.state.tabIndex} onSelect={this.selectTab}>
-                    {CamelUi.getSelectorModelTypes(parentDsl, 
this.props.showSteps).map((label: [string, number], index: number) => {
-                        const labelText = label[0];
-                        const count = label[1];
-                        const title = ['kamelet', 
'component'].includes(labelText.toLowerCase()) ? labelText+"s (" + count + ")" 
: labelText;
-                        return (
-                            <Tab eventKey={labelText} key={"tab-" + labelText} 
title={<TabTitleText>{CamelUtil.capitalizeName(title)}</TabTitleText>}>
-                                <Gallery key={"gallery-" + labelText} 
hasGutter className="dsl-gallery">
-                                    
{CamelUi.getSelectorModelsForParentFiltered(parentDsl, labelText, 
this.props.showSteps)
-                                        .filter((dsl: DslMetaModel) => 
this.checkFilter(dsl))
-                                        .map((dsl: DslMetaModel, index: 
number) => this.getCard(dsl, index))}
-                                </Gallery>
-                            </Tab>
-                        )
-                    })}
-                </Tabs>
-            </PageSection>
-        );
+            <Modal
+                aria-label={title}
+                data-tour="selector"
+                width={'90%'}
+                className='dsl-modal'
+                isOpen={this.props.isOpen}
+                onClose={this.props.onClose}
+                header={
+                    <Flex direction={{default: "column"}}>
+                        <FlexItem>
+                            <h3>{title}</h3>
+                            {this.searchInput()}
+                        </FlexItem>
+                        <FlexItem>
+                            <Tabs data-tour="selector-tabs" style={{overflow: 
'hidden'}} activeKey={this.state.tabIndex}
+                                  onSelect={this.selectTab}>
+                                {CamelUi.getSelectorModelTypes(parentDsl, 
this.props.showSteps).map((label: [string, number], index: number) => {
+                                    const labelText = label[0];
+                                    const count = label[1];
+                                    const title = ['kamelet', 
'component'].includes(labelText.toLowerCase()) ? labelText + "s (" + count + 
")" : labelText;
+                                    return (
+                                        <Tab eventKey={labelText} key={"tab-" 
+ labelText}
+                                             
title={<TabTitleText>{CamelUtil.capitalizeName(title)}</TabTitleText>}>
+                                        </Tab>
+                                    )
+                                })}
+                            </Tabs>
+                        </FlexItem>
+                    </Flex>
+                }
+                actions={{}}>
+                <PageSection variant={this.props.dark ? "darker" : "light"}>
+
+                    <Gallery key={"gallery-" + labelText} hasGutter 
className="dsl-gallery">
+                        {CamelUi.getSelectorModelsForParentFiltered(parentDsl, 
labelText, this.props.showSteps)
+                            .filter((dsl: DslMetaModel) => 
this.checkFilter(dsl))
+                            .map((dsl: DslMetaModel, index: number) => 
this.getCard(dsl, index))}
+                    </Gallery>
+                </PageSection>
+            </Modal>
+        )
     }
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx 
b/karavan-designer/src/designer/route/RouteDesigner.tsx
index 85dbad7..bae6794 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -21,7 +21,7 @@ import {
     DrawerContent,
     DrawerContentBody,
     Button, Modal,
-    PageSection
+    PageSection, Flex, FlexItem, Text
 } from '@patternfly/react-core';
 import '../karavan.css';
 import {DslSelector} from "./DslSelector";
@@ -124,15 +124,22 @@ export class RouteDesigner extends React.Component<Props, 
State> {
                 this.openSelector(step?.uuid, !step?.dslName ? undefined : 
"FromDefinition", true, undefined, event.selectorTabIndex)
                 break;
             case "closeSelector":
-                if (event.step){
+                if (event.step) {
                     const clone = 
CamelUtil.cloneIntegration(this.props.integration);
-                    this.setState({integration: clone, key: 
Math.random().toString(), showSelector: false, selectedStep: event.step, 
selectedUuid: event.step.uuid, propertyOnly: false });
+                    this.setState({
+                        integration: clone,
+                        key: Math.random().toString(),
+                        showSelector: false,
+                        selectedStep: event.step,
+                        selectedUuid: event.step.uuid,
+                        propertyOnly: false
+                    });
                 } else {
                     this.setState({showSelector: false, key: 
Math.random().toString()});
                 }
                 break;
             case "selectElement":
-                if (event.step) this.selectElement( event.step);
+                if (event.step) this.selectElement(event.step);
                 break;
         }
     }
@@ -223,7 +230,14 @@ export class RouteDesigner extends React.Component<Props, 
State> {
     }
 
     openSelector = (parentId: string | undefined, parentDsl: string | 
undefined, showSteps: boolean = true, position?: number | undefined, 
selectorTabIndex?: string | number) => {
-        this.setState({showSelector: true, parentId: parentId || '', 
parentDsl: parentDsl, showSteps: showSteps, selectedPosition: position, 
selectorTabIndex: selectorTabIndex})
+        this.setState({
+            showSelector: true,
+            parentId: parentId || '',
+            parentDsl: parentDsl,
+            showSteps: showSteps,
+            selectedPosition: position,
+            selectorTabIndex: selectorTabIndex
+        })
     }
 
     closeDslSelector = () => {
@@ -295,23 +309,16 @@ export class RouteDesigner extends React.Component<Props, 
State> {
 
     getSelectorModal() {
         return (
-            <Modal
-                data-tour="selector"
-                title={this.state.parentDsl === undefined ? "Select 
source/from" : "Select step"}
-                width={'90%'}
-                className='dsl-modal'
+            <DslSelector
                 isOpen={this.state.showSelector}
                 onClose={() => this.closeDslSelector()}
-                actions={{}}>
-                <DslSelector
-                    dark={this.props.dark}
-                    parentId={this.state.parentId}
-                    parentDsl={this.state.parentDsl}
-                    showSteps={this.state.showSteps}
-                    position={this.state.selectedPosition}
-                    tabIndex={this.state.selectorTabIndex}
-                    onDslSelect={this.onDslSelect}/>
-            </Modal>)
+                dark={this.props.dark}
+                parentId={this.state.parentId}
+                parentDsl={this.state.parentDsl}
+                showSteps={this.state.showSteps}
+                position={this.state.selectedPosition}
+                tabIndex={this.state.selectorTabIndex}
+                onDslSelect={this.onDslSelect}/>)
     }
 
     getDeleteConfirmation() {
@@ -335,7 +342,9 @@ export class RouteDesigner extends React.Component<Props, 
State> {
 
     getPropertiesPanel() {
         return (
-            <DrawerPanelContent onResize={width => this.setState({key: 
Math.random().toString(1)})} style={{transform: "initial"}} isResizable 
hasNoBorder defaultSize={'400px'} maxSize={'800px'} minSize={'300px'}>
+            <DrawerPanelContent onResize={width => this.setState({key: 
Math.random().toString(1)})}
+                                style={{transform: "initial"}} isResizable 
hasNoBorder defaultSize={'400px'}
+                                maxSize={'800px'} minSize={'300px'}>
                 <DslProperties ref={this.state.ref}
                                integration={this.state.integration}
                                step={this.state.selectedStep}
@@ -353,7 +362,8 @@ export class RouteDesigner extends React.Component<Props, 
State> {
         const routes = CamelUi.getRoutes(this.state.integration);
         return (
             <div className="graph">
-                <DslConnections height={this.state.height} 
width={this.state.width} top={this.state.top} left={this.state.left} 
integration={this.state.integration}/>
+                <DslConnections height={this.state.height} 
width={this.state.width} top={this.state.top}
+                                left={this.state.left} 
integration={this.state.integration}/>
                 <div className="flows" data-click="FLOWS" onClick={event => 
this.unselectElement(event)}
                      ref={el => this.onResizePage(el)}>
                     {routes?.map((route: any, index: number) => (
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx 
b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index 9141da0..fb74c51 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
@@ -169,17 +169,11 @@ export class DslPropertyField extends 
React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <Modal
-                title="Select from Kubernetes"
-                width={'50%'}
-                className='dsl-modal'
+            <KubernetesSelector
+                dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
-                actions={{}}>
-                <KubernetesSelector
-                    dark={false}
-                    onSelect={this.selectKubernetes}/>
-            </Modal>)
+                onSelect={this.selectKubernetes}/>)
     }
 
     getStringInput = (property: PropertyMeta, value: any) => {
diff --git 
a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx 
b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
index e48b23c..eb2be0a 100644
--- a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
@@ -84,17 +84,11 @@ export class KameletPropertyField extends 
React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <Modal
-                title="Select from Kubernetes"
-                width={'50%'}
-                className='dsl-modal'
+            <KubernetesSelector
+                dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
-                actions={{}}>
-                <KubernetesSelector
-                    dark={false}
-                    onSelect={this.selectKubernetes}/>
-            </Modal>)
+                onSelect={this.selectKubernetes}/>)
     }
 
     getStringInput() {
diff --git 
a/karavan-designer/src/designer/route/property/KubernetesSelector.tsx 
b/karavan-designer/src/designer/route/property/KubernetesSelector.tsx
index 88c97b7..99ee3ba 100644
--- a/karavan-designer/src/designer/route/property/KubernetesSelector.tsx
+++ b/karavan-designer/src/designer/route/property/KubernetesSelector.tsx
@@ -17,16 +17,20 @@
 import React from 'react';
 import {
     Badge,
-    Button,
-    Form, FormGroup, PageSection,
+    Button, Flex, FlexItem,
+    Form, FormGroup, Modal, PageSection,
     Tab, Tabs, TabTitleText, TextInput,
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import {TableComposable, Tbody, Td, Th, Thead, Tr} from 
"@patternfly/react-table";
 import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {CamelUi} from "../../utils/CamelUi";
+import {CamelUtil} from 
"../../../../../../../../karavan-core/lib/api/CamelUtil";
 
 interface Props {
     onSelect: (value: string) => void,
+    onClose?: () => void,
+    isOpen: boolean,
     dark: boolean,
 }
 
@@ -71,123 +75,171 @@ export class KubernetesSelector extends 
React.Component<Props, State> {
         )
     }
 
-    render() {
+    getConfigMapTable() {
         const configMaps = this.state.configMaps;
-        console.log(configMaps);
-        const secrets = this.state.secrets;
-        const services = this.state.services;
-        console.log(services);
         return (
-            <PageSection variant={this.props.dark ? "darker" : "light"}>
-                {this.searchInput()}
-                <Tabs data-tour="selector-tabs" style={{overflow: 'hidden'}} 
activeKey={this.state.tabIndex} onSelect={this.selectTab}>
-                    <Tab eventKey={"configMap"} key={"configMap"} 
title={<TabTitleText>ConfigMaps</TabTitleText>}>
-                        <TableComposable variant='compact' borders={false}>
-                            <Thead>
-                                <Tr>
-                                    <Th/>
-                                    <Th key='name'>Name</Th>
-                                    <Th key='data'>Data</Th>
+            <TableComposable variant='compact' borders={false}>
+                <Thead>
+                    <Tr>
+                        <Th/>
+                        <Th key='name'>Name</Th>
+                        <Th key='data'>Data</Th>
+                    </Tr>
+                </Thead>
+                <Tbody>
+                    {configMaps
+                        .filter(name => this.checkFilter(name))
+                        .map((name, idx: number) => {
+                            const configMapName = name.split("/")[0];
+                            const data = name.split("/")[1];
+                            return (
+                                <Tr key={name}>
+                                    <Td noPadding isActionCell>
+                                        <Badge>CM</Badge>
+                                    </Td>
+                                    <Td noPadding>
+                                        {configMapName}
+                                    </Td>
+                                    <Td noPadding>
+                                        <Button style={{padding: '6px'}} 
variant={"link"} onClick={
+                                            e => 
this.props.onSelect?.call(this, "configmap:" + name)}>
+                                            {data}
+                                        </Button>
+                                    </Td>
                                 </Tr>
-                            </Thead>
-                            <Tbody>
-                                {configMaps
-                                    .filter(name => this.checkFilter(name))
-                                    .map((name, idx: number) => {
-                                        const configMapName = 
name.split("/")[0];
-                                        const data = name.split("/")[1];
-                                        return (
-                                            <Tr key={name}>
-                                                <Td noPadding isActionCell>
-                                                    <Badge>CM</Badge>
-                                                </Td>
-                                                <Td noPadding>
-                                                    {configMapName}
-                                                </Td>
-                                                <Td noPadding>
-                                                    <Button style={{padding: 
'6px'}} variant={"link"} onClick={
-                                                        e => 
this.props.onSelect?.call(this, "configmap:" + name)}>
-                                                        {data}
-                                                    </Button>
-                                                </Td>
-                                            </Tr>
-                                        )
-                                    })}
-                            </Tbody>
-                        </TableComposable>
-                    </Tab>
-                    <Tab eventKey={"secret"} key={"secret"} 
title={<TabTitleText>Secrets</TabTitleText>}>
-                        <TableComposable variant='compact' borders={false}>
-                            <Thead>
-                                <Tr>
-                                    <Th/>
-                                    <Th key='name'>Name</Th>
-                                    <Th key='data'>Data</Th>
+                            )
+                        })}
+                </Tbody>
+            </TableComposable>
+        )
+    }
+
+    getSecretsTable() {
+        const secrets = this.state.secrets;
+        return (
+            <TableComposable variant='compact' borders={false}>
+                <Thead>
+                    <Tr>
+                        <Th/>
+                        <Th key='name'>Name</Th>
+                        <Th key='data'>Data</Th>
+                    </Tr>
+                </Thead>
+                <Tbody>
+                    {secrets
+                        .filter(name => this.checkFilter(name))
+                        .map((name, idx: number) => {
+                            const configMapName = name.split("/")[0];
+                            const data = name.split("/")[1];
+                            return (
+                                <Tr key={name}>
+                                    <Td noPadding isActionCell>
+                                        <Badge>S</Badge>
+                                    </Td>
+                                    <Td noPadding>
+                                        {configMapName}
+                                    </Td>
+                                    <Td noPadding>
+                                        <Button style={{padding: '6px'}} 
variant={"link"} onClick={
+                                            e => 
this.props.onSelect?.call(this, "secret:" + name)}>
+                                            {data}
+                                        </Button>
+                                    </Td>
                                 </Tr>
-                            </Thead>
-                            <Tbody>
-                                {secrets
-                                    .filter(name => this.checkFilter(name))
-                                    .map((name, idx: number) => {
-                                        const configMapName = 
name.split("/")[0];
-                                        const data = name.split("/")[1];
-                                        return (
-                                            <Tr key={name}>
-                                                <Td noPadding isActionCell>
-                                                    <Badge>S</Badge>
-                                                </Td>
-                                                <Td noPadding>
-                                                    {configMapName}
-                                                </Td>
-                                                <Td noPadding>
-                                                    <Button style={{padding: 
'6px'}} variant={"link"} onClick={
-                                                        e => 
this.props.onSelect?.call(this, "secret:" + name)}>
-                                                        {data}
-                                                    </Button>
-                                                </Td>
-                                            </Tr>
-                                        )
-                                    })}
-                            </Tbody>
-                        </TableComposable>
-                    </Tab>
-                    <Tab eventKey={"service"} key={"service"} 
title={<TabTitleText>Services</TabTitleText>}>
-                        <TableComposable variant='compact' borders={false}>
-                            <Thead>
-                                <Tr>
-                                    <Th/>
-                                    <Th key='name'>Name</Th>
-                                    <Th key='host'>Host:Port</Th>
+                            )
+                        })}
+                </Tbody>
+            </TableComposable>
+        )
+    }
+
+    getServicesTable() {
+        const services = this.state.services;
+        return (
+            <TableComposable variant='compact' borders={false}>
+                <Thead>
+                    <Tr>
+                        <Th/>
+                        <Th key='name'>Name</Th>
+                        {/*<Th key='hostPort'>Host:Port</Th>*/}
+                        <Th key='host'>Host</Th>
+                        <Th key='port'>Port</Th>
+                    </Tr>
+                </Thead>
+                <Tbody>
+                    {services
+                        .filter(name => this.checkFilter(name))
+                        .map((name, idx: number) => {
+                            const serviceName = name.split("|")[0];
+                            const hostPort = name.split("|")[1];
+                            const host = hostPort.split(":")[0];
+                            const port = hostPort.split(":")[1];
+                            return (
+                                <Tr key={name}>
+                                    <Td noPadding isActionCell>
+                                        <Badge>S</Badge>
+                                    </Td>
+                                    <Td noPadding>
+                                        {serviceName}
+                                    </Td>
+                                    {/*<Td noPadding>*/}
+                                    {/*    <Button style={{padding: '6px'}} 
variant={"link"} onClick={*/}
+                                    {/*        e => 
this.props.onSelect?.call(this, hostPort)}>*/}
+                                    {/*        {hostPort}*/}
+                                    {/*    </Button>*/}
+                                    {/*</Td>*/}
+                                    <Td noPadding>
+                                        <Button style={{padding: '6px'}} 
variant={"link"} onClick={
+                                            e => 
this.props.onSelect?.call(this, host)}>
+                                            {host}
+                                        </Button>
+                                    </Td>
+                                    <Td noPadding>
+                                        <Button style={{padding: '6px'}} 
variant={"link"} onClick={
+                                            e => 
this.props.onSelect?.call(this, port)}>
+                                            {port}
+                                        </Button>
+                                    </Td>
                                 </Tr>
-                            </Thead>
-                            <Tbody>
-                                {services
-                                    .filter(name => this.checkFilter(name))
-                                    .map((name, idx: number) => {
-                                        const serviceName = name.split("|")[0];
-                                        const hostPort = name.split("|")[1];
-                                        return (
-                                            <Tr key={name}>
-                                                <Td noPadding isActionCell>
-                                                    <Badge>S</Badge>
-                                                </Td>
-                                                <Td noPadding>
-                                                    {serviceName}
-                                                </Td>
-                                                <Td noPadding>
-                                                    <Button style={{padding: 
'6px'}} variant={"link"} onClick={
-                                                        e => 
this.props.onSelect?.call(this, hostPort)}>
-                                                        {hostPort}
-                                                    </Button>
-                                                </Td>
-                                            </Tr>
-                                        )
-                                    })}
-                            </Tbody>
-                        </TableComposable>
-                    </Tab>
-                </Tabs>
-            </PageSection>
-        );
+                            )
+                        })}
+                </Tbody>
+            </TableComposable>
+        )
+    }
+
+    render() {
+        const tabIndex = this.state.tabIndex;
+        return (
+            <Modal
+                aria-label="Select from Kubernetes"
+                width={'50%'}
+                className='dsl-modal'
+                isOpen={this.props.isOpen}
+                onClose={this.props.onClose}
+                header={
+                    <Flex direction={{default: "column"}}>
+                        <FlexItem>
+                            <h3>{"Select from Kubernetes"}</h3>
+                            {this.searchInput()}
+                        </FlexItem>
+                        <FlexItem>
+                            <Tabs data-tour="selector-tabs" style={{overflow: 
'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}>
+                                <Tab eventKey={"configMap"} key={"configMap"} 
title={<TabTitleText>ConfigMaps</TabTitleText>} />
+                                <Tab eventKey={"secret"} key={"secret"} 
title={<TabTitleText>Secrets</TabTitleText>} />
+                                <Tab eventKey={"service"} key={"service"} 
title={<TabTitleText>Services</TabTitleText>} />
+                            </Tabs>
+                        </FlexItem>
+                    </Flex>
+                }
+                actions={{}}>
+                <PageSection variant={this.props.dark ? "darker" : "light"}>
+                    {this.searchInput()}
+                    {tabIndex === 'configMap' && this.getConfigMapTable()}
+                    {tabIndex === 'secret' && this.getSecretsTable()}
+                    {tabIndex === 'service' && this.getServicesTable()}
+                </PageSection>
+            </Modal>
+        )
     }
 }
\ No newline at end of file
diff --git a/karavan-vscode/webview/builder/BuilderPage.tsx 
b/karavan-vscode/webview/builder/BuilderPage.tsx
index 5ffeed0..605521c 100644
--- a/karavan-vscode/webview/builder/BuilderPage.tsx
+++ b/karavan-vscode/webview/builder/BuilderPage.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     Badge,
diff --git a/karavan-vscode/webview/builder/FileSelector.tsx 
b/karavan-vscode/webview/builder/FileSelector.tsx
index 2d0f2ab..ead44b9 100644
--- a/karavan-vscode/webview/builder/FileSelector.tsx
+++ b/karavan-vscode/webview/builder/FileSelector.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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,
diff --git a/karavan-vscode/webview/builder/ProfileSelector.tsx 
b/karavan-vscode/webview/builder/ProfileSelector.tsx
index b5f4351..ef140a4 100644
--- a/karavan-vscode/webview/builder/ProfileSelector.tsx
+++ b/karavan-vscode/webview/builder/ProfileSelector.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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,
diff --git a/karavan-vscode/webview/builder/PropertiesTable.tsx 
b/karavan-vscode/webview/builder/PropertiesTable.tsx
index 27d5a88..e3f5958 100644
--- a/karavan-vscode/webview/builder/PropertiesTable.tsx
+++ b/karavan-vscode/webview/builder/PropertiesTable.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, Flex, FlexItem,
@@ -100,7 +116,7 @@ export class PropertiesTable extends React.Component<Props, 
State> {
                         </Thead>
                         <Tbody>
                             {properties.map((property, idx: number) => {
-                                const readOnly = ["camel.jbang.gav", 
"camel.jbang.runtime"].includes(property.key);
+                                const readOnly = 
property.key.startsWith("camel.jbang");
                                 return (
                                     <Tr key={property.id}>
                                         <Td noPadding width={20} 
dataLabel="key">{this.getTextInputField(property, "key", readOnly)}</Td>
diff --git a/karavan-vscode/webview/components/ComponentCard.tsx 
b/karavan-vscode/webview/components/ComponentCard.tsx
index 925c720..6d465f3 100644
--- a/karavan-vscode/webview/components/ComponentCard.tsx
+++ b/karavan-vscode/webview/components/ComponentCard.tsx
@@ -1,9 +1,24 @@
+/*
+ * 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 {
     CardHeader, Card, CardTitle, CardBody, CardActions, CardFooter,Badge
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
-import {KameletModel} from "karavan-core/lib/model/KameletModels";
 import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
 import {Component} from "karavan-core/lib/model/ComponentModels";
 
diff --git a/karavan-vscode/webview/components/ComponentModal.tsx 
b/karavan-vscode/webview/components/ComponentModal.tsx
index 04ad022..0e73bc4 100644
--- a/karavan-vscode/webview/components/ComponentModal.tsx
+++ b/karavan-vscode/webview/components/ComponentModal.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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,
diff --git a/karavan-vscode/webview/components/ComponentsPage.tsx 
b/karavan-vscode/webview/components/ComponentsPage.tsx
index f1b5dc8..182ce03 100644
--- a/karavan-vscode/webview/components/ComponentsPage.tsx
+++ b/karavan-vscode/webview/components/ComponentsPage.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     Toolbar,
diff --git a/karavan-vscode/webview/eip/EipCard.tsx 
b/karavan-vscode/webview/eip/EipCard.tsx
index 310d429..0fab47e 100644
--- a/karavan-vscode/webview/eip/EipCard.tsx
+++ b/karavan-vscode/webview/eip/EipCard.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     CardHeader, Card, CardTitle, CardBody, CardFooter,Badge
diff --git a/karavan-vscode/webview/eip/EipModal.tsx 
b/karavan-vscode/webview/eip/EipModal.tsx
index f6ee6d9..34777ca 100644
--- a/karavan-vscode/webview/eip/EipModal.tsx
+++ b/karavan-vscode/webview/eip/EipModal.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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,
diff --git a/karavan-vscode/webview/eip/EipPage.tsx 
b/karavan-vscode/webview/eip/EipPage.tsx
index dd6e301..352d59a 100644
--- a/karavan-vscode/webview/eip/EipPage.tsx
+++ b/karavan-vscode/webview/eip/EipPage.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     Toolbar,
diff --git a/karavan-vscode/webview/kamelets/KameletCard.tsx 
b/karavan-vscode/webview/kamelets/KameletCard.tsx
index 3708af8..31ac3c6 100644
--- a/karavan-vscode/webview/kamelets/KameletCard.tsx
+++ b/karavan-vscode/webview/kamelets/KameletCard.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     CardHeader, Card, CardTitle, CardBody, CardActions, CardFooter,Badge
diff --git a/karavan-vscode/webview/kamelets/KameletModal.tsx 
b/karavan-vscode/webview/kamelets/KameletModal.tsx
index fb9532d..270683a 100644
--- a/karavan-vscode/webview/kamelets/KameletModal.tsx
+++ b/karavan-vscode/webview/kamelets/KameletModal.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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, {Component} from 'react';
 import {
     Button,
diff --git a/karavan-vscode/webview/kamelets/KameletsPage.tsx 
b/karavan-vscode/webview/kamelets/KameletsPage.tsx
index f4c26ce..9176532 100644
--- a/karavan-vscode/webview/kamelets/KameletsPage.tsx
+++ b/karavan-vscode/webview/kamelets/KameletsPage.tsx
@@ -1,3 +1,19 @@
+/*
+ * 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 {
     Toolbar,

Reply via email to