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/07/14 00:39:09 UTC

[camel-karavan] branch main updated (d57e1eb2 -> def90df7)

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 d57e1eb2 Trace In docker #817
     new bef05933 Infrastructure definition #817
     new def90df7 Infrasructure config for logs #817

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:
 .../camel/karavan/api/ConfigurationResource.java   |  2 +-
 .../apache/camel/karavan/api/DevModeResource.java  |  4 +-
 ...esResource.java => InfrastructureResource.java} | 39 +++++++----
 .../apache/camel/karavan/api/LogWatchResource.java | 44 ++++++++-----
 .../karavan/listener/DevModeCommandListener.java   |  6 +-
 .../camel/karavan/service/KaravanService.java      |  2 +-
 .../karavan-app/src/main/webui/src/Main.tsx        |  8 ++-
 .../src/main/webui/src/api/KaravanApi.tsx          | 34 +++++-----
 .../src/main/webui/src/api/ProjectModels.ts        |  2 +-
 .../src/main/webui/src/api/ProjectService.ts       | 24 +++----
 .../webui/src/designer/beans/BeanProperties.tsx    | 51 ++++++++-------
 .../route/property/ComponentParameterField.tsx     | 52 +++++++--------
 .../designer/route/property/DslPropertyField.tsx   | 53 +++++++--------
 ...etesSelector.tsx => InfrastructureSelector.tsx} | 23 ++++---
 .../route/property/KameletPropertyField.tsx        | 53 +++++++--------
 .../webui/src/designer/utils/InfrastructureAPI.ts  |  4 +-
 .../camel/karavan/bashi/ConductorService.java      | 75 ++++++++++++++--------
 .../org/apache/camel/karavan/bashi/Constants.java  |  1 -
 .../karavan/bashi/docker/DockerEventListener.java  | 70 ++++++++++++++------
 .../camel/karavan/bashi/docker/DockerService.java  | 31 ++++++++-
 .../camel/karavan/bashi/docker/LogCallback.java    | 26 ++++++++
 .../camel/karavan/datagrid/DatagridService.java    | 46 +++++++------
 .../camel/karavan/datagrid/model/CommandName.java  | 10 ---
 .../karavan/datagrid/model/ContainerInfo.java      | 70 ++++++++++++++++++++
 .../karavan/datagrid/model/DevModeCommand.java     | 45 ++++++++++---
 .../karavan/datagrid/model/DevModeCommandName.java | 12 ++++
 .../karavan/datagrid/model/DevModeCommandType.java |  9 +++
 .../karavan/datagrid/model/KaravanSchema.java      |  6 +-
 .../camel/karavan/datagrid/DataGridTest.java       | 22 +++++--
 .../src/designer/beans/BeanProperties.tsx          | 51 ++++++++-------
 .../route/property/ComponentParameterField.tsx     | 52 +++++++--------
 .../designer/route/property/DslPropertyField.tsx   | 53 +++++++--------
 ...etesSelector.tsx => InfrastructureSelector.tsx} | 23 ++++---
 .../route/property/KameletPropertyField.tsx        | 53 +++++++--------
 .../src/designer/utils/InfrastructureAPI.ts        |  4 +-
 35 files changed, 669 insertions(+), 391 deletions(-)
 rename karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/{KubernetesResource.java => InfrastructureResource.java} (84%)
 rename karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/{KubernetesSelector.tsx => InfrastructureSelector.tsx} (91%)
 rename karavan-designer/src/designer/utils/KubernetesAPI.ts => karavan-cloud/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts (77%)
 create mode 100644 karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java
 delete mode 100644 karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java
 create mode 100644 karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java
 create mode 100644 karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java
 create mode 100644 karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java
 rename karavan-designer/src/designer/route/property/{KubernetesSelector.tsx => InfrastructureSelector.tsx} (91%)
 rename karavan-cloud/karavan-app/src/main/webui/src/designer/utils/KubernetesAPI.ts => karavan-designer/src/designer/utils/InfrastructureAPI.ts (77%)


[camel-karavan] 02/02: Infrasructure config for logs #817

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 def90df7ca63cc9e68c90a29b57f866ac46d0013
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Jul 13 20:38:59 2023 -0400

    Infrasructure config for logs #817
---
 .../apache/camel/karavan/api/DevModeResource.java  |   4 +-
 .../camel/karavan/api/InfrastructureResource.java  |   5 +-
 .../apache/camel/karavan/api/LogWatchResource.java |  44 ++--
 .../karavan/listener/DevModeCommandListener.java   |   6 +-
 .../camel/karavan/service/KaravanService.java      |   2 +-
 .../webui/src/designer/beans/BeanProperties.tsx    |  38 ++--
 .../route/property/ComponentParameterField.tsx     |  36 +--
 .../designer/route/property/DslPropertyField.tsx   |  36 +--
 .../route/property/InfrastructureSelector.tsx      |   7 +-
 .../route/property/KameletPropertyField.tsx        |  36 +--
 .../designer/route/property/KubernetesSelector.tsx | 243 ---------------------
 .../camel/karavan/bashi/ConductorService.java      |  75 ++++---
 .../org/apache/camel/karavan/bashi/Constants.java  |   1 -
 .../karavan/bashi/docker/DockerEventListener.java  |  70 ++++--
 .../camel/karavan/bashi/docker/DockerService.java  |  31 ++-
 .../camel/karavan/bashi/docker/LogCallback.java    |  26 +++
 .../camel/karavan/datagrid/DatagridService.java    |  46 ++--
 .../camel/karavan/datagrid/model/CommandName.java  |  10 -
 .../karavan/datagrid/model/ContainerInfo.java      |  70 ++++++
 .../karavan/datagrid/model/DevModeCommand.java     |  45 +++-
 .../karavan/datagrid/model/DevModeCommandName.java |  12 +
 .../karavan/datagrid/model/DevModeCommandType.java |   9 +
 .../karavan/datagrid/model/KaravanSchema.java      |   6 +-
 .../camel/karavan/datagrid/DataGridTest.java       |  22 +-
 .../src/designer/beans/BeanProperties.tsx          |  38 ++--
 .../route/property/ComponentParameterField.tsx     |  36 +--
 .../designer/route/property/DslPropertyField.tsx   |  36 +--
 .../route/property/InfrastructureSelector.tsx      |   7 +-
 .../route/property/KameletPropertyField.tsx        |  36 +--
 29 files changed, 520 insertions(+), 513 deletions(-)

diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
index f56ad4d3..d0681bf4 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
@@ -57,7 +57,7 @@ public class DevModeResource {
         PodStatus status = datagridService.getDevModePodStatuses(runnerName, environment);
         if (status == null) {
             datagridService.saveDevModeStatus(new DevModeStatus(project.getProjectId(), null, null, false));
-            datagridService.sendDevModeCommand(project.getProjectId(), new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli()));
+            datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, project.getProjectId()));
             return Response.ok(runnerName).build();
         }
         return Response.notModified().build();
@@ -83,7 +83,7 @@ public class DevModeResource {
     @Consumes(MediaType.APPLICATION_JSON)
     @Path("/{projectId}/{deletePVC}")
     public Response deleteRunner(@PathParam("projectId") String projectId, @PathParam("deletePVC") boolean deletePVC) {
-        datagridService.sendDevModeCommand(projectId, new DevModeCommand(CommandName.DELETE, Instant.now().toEpochMilli()));
+        datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.DELETE, projectId));
         datagridService.deleteDevModeStatus(projectId);
         return Response.accepted().build();
     }
diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
index d2749563..f525f6a5 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
@@ -203,7 +203,10 @@ public class InfrastructureResource {
         if (kubernetesService.inKubernetes()) {
             return Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build();
         } else {
-            return Response.ok(List.of()).build();
+            List<String> list = datagridService.getContainerInfos(environment).stream()
+                    .map(ci -> ci.getPorts().stream().map(i -> ci.getContainerName() + ":" + i).collect(Collectors.toList()))
+                    .flatMap(List::stream).collect(Collectors.toList());
+            return Response.ok(list).build();
         }
     }
 
diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
index 5b1ba723..0fece15e 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/LogWatchResource.java
@@ -17,6 +17,9 @@
 package org.apache.camel.karavan.api;
 
 import io.fabric8.kubernetes.client.dsl.LogWatch;
+import org.apache.camel.karavan.datagrid.DatagridService;
+import org.apache.camel.karavan.datagrid.model.DevModeCommand;
+import org.apache.camel.karavan.datagrid.model.DevModeCommandName;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.eclipse.microprofile.context.ManagedExecutor;
 import org.jboss.logging.Logger;
@@ -44,6 +47,9 @@ public class LogWatchResource {
     @Inject
     KubernetesService kubernetesService;
 
+    @Inject
+    DatagridService datagridService;
+
     @Inject
     ManagedExecutor managedExecutor;
 
@@ -57,22 +63,30 @@ public class LogWatchResource {
     ) {
         managedExecutor.execute(() -> {
             LOGGER.info("LogWatch for " + name + " starting...");
-            try (SseEventSink sink = eventSink) {
-                LogWatch logWatch = type.equals("container")
-                        ? kubernetesService.getContainerLogWatch(name)
-                        : kubernetesService.getPipelineRunLogWatch(name);
-                BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput()));
-                try {
-                    for (String line; (line = reader.readLine()) != null && !sink.isClosed(); ) {
-                        sink.send(sse.newEvent(line));
-                    }
-                } catch (IOException e) {
-                    LOGGER.error(e.getMessage());
-                }
-                logWatch.close();
-                sink.close();
-                LOGGER.info("LogWatch for " + name + " closed");
+            if (kubernetesService.inKubernetes()) {
+                getKubernetesLogs(type, name, eventSink, sse);
+            } else {
+                datagridService.sendDevModeCommand(DevModeCommand.createDevModeCommand(DevModeCommandName.LOG, name));
             }
         });
     }
+
+    private void getKubernetesLogs(String type, String name, SseEventSink eventSink, Sse sse) {
+        try (SseEventSink sink = eventSink) {
+            LogWatch logWatch = type.equals("container")
+                    ? kubernetesService.getContainerLogWatch(name)
+                    : kubernetesService.getPipelineRunLogWatch(name);
+            BufferedReader reader = new BufferedReader(new InputStreamReader(logWatch.getOutput()));
+            try {
+                for (String line; (line = reader.readLine()) != null && !sink.isClosed(); ) {
+                    sink.send(sse.newEvent(line));
+                }
+            } catch (IOException e) {
+                LOGGER.error(e.getMessage());
+            }
+            logWatch.close();
+            sink.close();
+            LOGGER.info("LogWatch for " + name + " closed");
+        }
+    }
 }
\ No newline at end of file
diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java
index 26fea711..8c1956ad 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/listener/DevModeCommandListener.java
@@ -3,8 +3,8 @@ package org.apache.camel.karavan.listener;
 import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.core.json.JsonObject;
 import org.apache.camel.karavan.datagrid.DatagridService;
-import org.apache.camel.karavan.datagrid.model.CommandName;
 import org.apache.camel.karavan.datagrid.model.DevModeCommand;
+import org.apache.camel.karavan.datagrid.model.DevModeCommandName;
 import org.apache.camel.karavan.datagrid.model.Project;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -34,10 +34,10 @@ public class DevModeCommandListener {
         if (kubernetesService.inKubernetes()) {
             DevModeCommand command = message.mapTo(DevModeCommand.class);
             String runnerName = command.getProjectId() + "-" + DEVMODE_SUFFIX;
-            if (Objects.equals(command.getCommandName(), CommandName.RUN)) {
+            if (Objects.equals(command.getCommandName(), DevModeCommandName.RUN)) {
                 Project p = datagridService.getProject(command.getProjectId());
                 kubernetesService.tryCreateRunner(p, runnerName, "");
-            } else if (Objects.equals(command.getCommandName(), CommandName.DELETE)){
+            } else if (Objects.equals(command.getCommandName(), DevModeCommandName.DELETE)){
                 kubernetesService.deleteRunner(runnerName, false);
                 datagridService.deleteDevModeStatus(command.getProjectId());
             }
diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 177401a6..b0b1f359 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -48,7 +48,7 @@ public class KaravanService {
     void onStart(@Observes StartupEvent ev) {
         LOGGER.info("Start Karavan");
         datagridService.start();
-//        datagridService.clearAllStatuses();
+        datagridService.clearAllStatuses();
         setEnvironment();
         initialImport();
         startInformers();
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
index b7ab5532..24c1e202 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
@@ -54,9 +54,9 @@ interface State {
     bean?: NamedBeanDefinition
     properties: Map<string, [string, string, boolean]>
     key: string,
-    showKubernetesSelector: boolean
-    kubernetesSelectorUuid?: string
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorUuid?: string
+    infrastructureSelectorProperty?: string
 }
 
 export class BeanProperties extends React.Component<Props, State> {
@@ -70,7 +70,7 @@ export class BeanProperties extends React.Component<Props, State> {
     public state: State = {
         bean: this.props.bean,
         key: '',
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         properties: this.props.bean?.properties ? this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, [string, string, boolean]>()
     };
 
@@ -118,31 +118,31 @@ export class BeanProperties extends React.Component<Props, State> {
         })
     }
 
-    selectKubernetes = (value: string) => {
-        const propertyId = this.state.kubernetesSelectorProperty;
-        const uuid = this.state.kubernetesSelectorUuid;
+    selectInfrastructure = (value: string) => {
+        const propertyId = this.state.infrastructureSelectorProperty;
+        const uuid = this.state.infrastructureSelectorUuid;
         if (propertyId && uuid){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.propertyChanged(uuid, propertyId, value, false);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (uuid: string, propertyName: string) => {
-        this.setState({kubernetesSelectorUuid: uuid, kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (uuid: string, propertyName: string) => {
+        this.setState({infrastructureSelectorUuid: uuid, infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     cloneBean = () => {
@@ -208,8 +208,8 @@ export class BeanProperties extends React.Component<Props, State> {
                                            onChange={e => this.propertyChanged(i, e, value, showPassword)}/>
                                 <InputGroup>
                                     {inInfrastructure &&
-                                        <Tooltip position="bottom-end" content="Select value from Kubernetes">
-                                        <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}>
+                                        <Tooltip position="bottom-end" content="Select value from Infrastructure">
+                                        <Button variant="control" onClick={e => this.openInfrastructureSelector(i, key)}>
                                             {icon}
                                         </Button>
                                     </Tooltip>}
@@ -246,7 +246,7 @@ export class BeanProperties extends React.Component<Props, State> {
                     {this.state.bean === undefined && <IntegrationHeader integration={this.props.integration}/>}
                     {this.state.bean !== undefined && this.getBeanForm()}
                 </Form>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
index 39817f7c..ca1f6a0d 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
@@ -23,7 +23,7 @@ import {
     Select,
     SelectVariant,
     SelectDirection,
-    SelectOption, InputGroup, TextArea, Tooltip, Button,
+    SelectOption, InputGroup, TextArea, Tooltip, Button, capitalize,
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -57,8 +57,8 @@ interface State {
     selectStatus: Map<string, boolean>
     showEditor: boolean
     showPassword: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     ref: any
     id: string
 }
@@ -69,7 +69,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
         selectStatus: new Map<string, boolean>(),
         showEditor: false,
         showPassword: false,
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         ref: React.createRef(),
         id: prefix + "-" + this.props.property.name
     }
@@ -179,7 +179,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
         </InputGroup>
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -189,29 +189,29 @@ export class ComponentParameterField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyName = this.state.kubernetesSelectorProperty;
+        const propertyName = this.state.infrastructureSelectorProperty;
         if (propertyName) {
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.parametersChanged(propertyName, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput(property: ComponentProperty, value: any) {
@@ -221,8 +221,8 @@ export class ComponentParameterField extends React.Component<Props, State> {
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return <InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -340,7 +340,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
                     && this.getSelect(property, value)}
                 {property.type === 'boolean'
                     && this.getSwitch(property, value)}
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </FormGroup>
         )
     }
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
index e11ee485..d17a26c3 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
@@ -35,7 +35,7 @@ import {
     Text,
     Tooltip,
     Card,
-    InputGroup,
+    InputGroup, capitalize,
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -87,8 +87,8 @@ interface State {
     isShowAdvanced: Map<string, boolean>,
     arrayValues: Map<string, string>,
     showEditor: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    infrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     customCode?: string
     ref: any
 }
@@ -100,7 +100,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         arrayValues: new Map<string, string>(),
         isShowAdvanced: new Map<string, boolean>(),
         showEditor: false,
-        showKubernetesSelector: false,
+        infrastructureSelector: false,
         ref: React.createRef(),
     };
 
@@ -176,7 +176,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         return property.name === 'uri' && !['ToDefinition', 'ToDynamicDefinition', 'WireTapDefinition'].includes(dslName)
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -186,29 +186,29 @@ export class DslPropertyField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyName = this.state.kubernetesSelectorProperty;
+        const propertyName = this.state.infrastructureSelectorProperty;
         if (propertyName) {
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.propertyChanged(propertyName, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({infrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, infrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({infrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.infrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput = (property: PropertyMeta, value: any) => {
@@ -218,8 +218,8 @@ export class DslPropertyField extends React.Component<Props, State> {
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return (<InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -732,7 +732,7 @@ export class DslPropertyField extends React.Component<Props, State> {
                     {isKamelet && property.name === 'parameters' && this.getKameletParameters()}
                     {!isKamelet && property.name === 'parameters' && this.getComponentParameters(property)}
                 </FormGroup>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
index 04c8d43a..e0069bc0 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
@@ -208,6 +208,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
 
     render() {
         const tabIndex = this.state.tabIndex;
+        const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services'];
         return (
             <Modal
                 aria-label="Select from Infrastructure"
@@ -223,9 +224,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                         </FlexItem>
                         <FlexItem>
                             <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.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)}
                             </Tabs>
                         </FlexItem>
                     </Flex>
@@ -235,7 +234,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                     {this.searchInput()}
                     {tabIndex === 'configMap' && this.getConfigMapTable()}
                     {tabIndex === 'secret' && this.getSecretsTable()}
-                    {tabIndex === 'service' && this.getServicesTable()}
+                    {tabIndex === 'services' && this.getServicesTable()}
                 </PageSection>
             </Modal>
         )
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
index 8beed690..9b0a3b39 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
@@ -19,7 +19,7 @@ import {
     FormGroup,
     TextInput,
     Popover,
-    Switch, InputGroup, Button, TextArea, Tooltip
+    Switch, InputGroup, Button, TextArea, Tooltip, capitalize
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -45,8 +45,8 @@ interface State {
     selectIsOpen: boolean
     showEditor: boolean
     showPassword: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     ref: any
 }
 
@@ -56,7 +56,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
         selectIsOpen: false,
         showEditor: false,
         showPassword: false,
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         ref: React.createRef(),
     }
 
@@ -69,7 +69,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
         this.setState({selectIsOpen: false});
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -79,29 +79,29 @@ export class KameletPropertyField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyId = this.state.kubernetesSelectorProperty;
+        const propertyId = this.state.infrastructureSelectorProperty;
         if (propertyId){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.parametersChanged(propertyId, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput() {
@@ -115,8 +115,8 @@ export class KameletPropertyField extends React.Component<Props, State> {
         const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton
         return <InputGroup>
             {showInfraSelectorButton  &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.id)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -197,7 +197,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
                         onChange={e => this.parametersChanged(property.id, !Boolean(value))}/>
                     }
                 </FormGroup>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
deleted file mode 100644
index b7997eda..00000000
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
+++ /dev/null
@@ -1,243 +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.
- */
-import React from 'react';
-import {
-    Badge,
-    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 {InfrastructureAPI} from "../../utils/InfrastructureAPI";
-
-interface Props {
-    onSelect: (value: string) => void,
-    onClose?: () => void,
-    isOpen: boolean,
-    dark: boolean,
-}
-
-interface State {
-    tabIndex: string | number
-    filter?: string
-    configMaps:  string[]
-    secrets:  string[]
-    services:  string[]
-}
-
-export class KubernetesSelector extends React.Component<Props, State> {
-
-    public state: State = {
-        tabIndex: "configMap",
-        configMaps: InfrastructureAPI.configMaps,
-        secrets: InfrastructureAPI.secrets,
-        services: InfrastructureAPI.services
-    };
-
-    selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
-        this.setState({tabIndex: eventKey})
-    }
-
-    checkFilter = (name: string): boolean => {
-        if (this.state.filter !== undefined && name) {
-            return name.toLowerCase().includes(this.state.filter.toLowerCase())
-        } else {
-            return true;
-        }
-    }
-
-    searchInput = () => {
-        return (
-            <Form isHorizontal className="search" autoComplete="off">
-                <FormGroup fieldId="search">
-                    <TextInput className="text-field" type="text" id="search" name="search" iconVariant='search'
-                               value={this.state.filter}
-                               onChange={e => this.setState({filter: e})}/>
-                </FormGroup>
-            </Form>
-        )
-    }
-
-    getConfigMapTable() {
-        const configMaps = this.state.configMaps;
-        return (
-            <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>
-                            )
-                        })}
-                </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>
-                            )
-                        })}
-                </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)}>
-                                            {serviceName}
-                                        </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>
-                            )
-                        })}
-                </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 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-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java
index 09548632..c9998219 100644
--- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java
+++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/ConductorService.java
@@ -102,32 +102,6 @@ public class ConductorService {
         }
     }
 
-    @ConsumeEvent(value = DatagridService.ADDRESS_DEVMODE_COMMAND, blocking = true, ordered = true)
-    void receiveCommand(JsonObject message) throws InterruptedException {
-        LOGGER.info("DevMode Command: " + message);
-        DevModeCommand command = message.mapTo(DevModeCommand.class);
-        String containerName = command.getProjectId() + "-" + DEVMODE_SUFFIX;
-        Project p = datagridService.getProject(command.getProjectId());
-        if (Objects.equals(command.getCommandName(), CommandName.RUN)) {
-            LOGGER.infof("DevMode starting for %s", p.getProjectId());
-
-            HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health"))
-                    .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30);
-
-            dockerService.createContainer(containerName, runnerImage,
-                    List.of(), "", false, healthCheck,
-                    Map.of("type", "devmode", "projectId", p.getProjectId())
-            );
-            dockerService.startContainer(containerName);
-            LOGGER.infof("DevMode started for %s", p.getProjectId());
-
-        } else if (Objects.equals(command.getCommandName(), CommandName.DELETE)){
-            dockerService.stopContainer(containerName);
-            dockerService.deleteContainer(containerName);
-            datagridService.deleteDevModeStatus(p.getName());
-        }
-    }
-
     @ConsumeEvent(value = ADDRESS_CONTAINER_STATS, blocking = true, ordered = true)
     public void saveStats(JsonObject data) {
         String projectId = data.getString("projectId");
@@ -142,4 +116,53 @@ public class ConductorService {
             }
         }
     }
+
+    @ConsumeEvent(value = DatagridService.ADDRESS_DEVMODE_COMMAND, blocking = true, ordered = true)
+    void receiveCommand(JsonObject message) throws InterruptedException {
+        LOGGER.info("DevMode Command: " + message);
+        DevModeCommand command = message.mapTo(DevModeCommand.class);
+        switch (command.getCommandName()){
+            case RUN:
+                runContainer(command);
+                break;
+            case DELETE:
+                deleteContainer(command);
+                break;
+            case LOG:
+                logContainer(command);
+                break;
+        }
+        datagridService.deleteDevModeCommand(command);
+    }
+
+    void runContainer(DevModeCommand command) throws InterruptedException {
+        if (DevModeCommandType.DEVMODE.equals(command.getType())) {
+            String projectId = command.getProjectId();
+            LOGGER.infof("DevMode starting for %s", projectId);
+            HealthCheck healthCheck = new HealthCheck().withTest(List.of("CMD", "curl", "-f", "http://localhost:8080/q/dev/health"))
+                    .withInterval(10000000000L).withTimeout(10000000000L).withStartPeriod(10000000000L).withRetries(30);
+            dockerService.createContainer(command.getContainerName(), runnerImage,
+                    List.of(), "", false, healthCheck,
+                    Map.of("type", "devmode", "projectId", projectId));
+            dockerService.startContainer(command.getContainerName());
+            LOGGER.infof("DevMode started for %s", projectId);
+        } else {
+
+        }
+    }
+
+    void deleteContainer(DevModeCommand command) {
+        if (DevModeCommandType.DEVMODE.equals(command.getType())) {
+            datagridService.deleteDevModeStatus(command.getProjectId());
+            dockerService.stopContainer(command.getContainerName());
+            dockerService.deleteContainer(command.getContainerName());
+        } else {
+            dockerService.stopContainer(command.getContainerName());
+            dockerService.deleteContainer(command.getContainerName());
+        }
+    }
+
+    void logContainer(DevModeCommand command) {
+        dockerService.logContainer(command.getContainerName());
+    }
 }
\ No newline at end of file
diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java
index a0575eb2..38c3a89e 100644
--- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java
+++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/Constants.java
@@ -6,5 +6,4 @@ public class Constants {
     public static final String DATAGRID_CONTAINER_NAME = "infinispan";
 
     public static final String KARAVAN_CONTAINER_NAME = "karavan";
-    public static final String DEVMODE_SUFFIX = "devmode";
 }
diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java
index 4910e603..9b57dc72 100644
--- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java
+++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerEventListener.java
@@ -2,12 +2,13 @@ package org.apache.camel.karavan.bashi.docker;
 
 import com.github.dockerjava.api.async.ResultCallback;
 import com.github.dockerjava.api.model.Container;
+import com.github.dockerjava.api.model.ContainerPort;
 import com.github.dockerjava.api.model.Event;
 import com.github.dockerjava.api.model.EventType;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.bashi.ConductorService;
-import org.apache.camel.karavan.bashi.Constants;
 import org.apache.camel.karavan.datagrid.DatagridService;
+import org.apache.camel.karavan.datagrid.model.ContainerInfo;
 import org.apache.camel.karavan.datagrid.model.DevModeStatus;
 import org.apache.camel.karavan.datagrid.model.PodStatus;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -19,7 +20,11 @@ import java.io.Closeable;
 import java.io.IOException;
 import java.time.Instant;
 import java.util.Arrays;
+import java.util.List;
 import java.util.Objects;
+import java.util.stream.Collectors;
+
+import static org.apache.camel.karavan.datagrid.model.DevModeCommand.DEVMODE_SUFFIX;
 
 @ApplicationScoped
 public class DockerEventListener implements ResultCallback<Event> {
@@ -48,32 +53,61 @@ public class DockerEventListener implements ResultCallback<Event> {
         try {
             if (Objects.equals(event.getType(), EventType.CONTAINER)) {
                 Container container = dockerService.getContainer(event.getId());
+                onContainerEvent(event, container);
                 String status = event.getStatus();
                 if (container.getNames()[0].equals("/infinispan") && status.startsWith("health_status:")) {
+                    onInfinispanHealthEvent(event, container);
+                } else if (container.getNames()[0].endsWith(DEVMODE_SUFFIX) || Objects.equals(container.getLabels().get("type"), "devmode")) {
+                    onDevModeEvent(event, container);
+                }
+            }
+        } catch (Exception exception) {
+            LOGGER.error(exception.getMessage());
+        }
+    }
+
+    public void onContainerEvent(Event event, Container container) {
+        if (datagridService.isReady()) {
+            String name = container.getNames()[0].replace("/", "");
+            if (Arrays.asList("destroy", "stop", "die", "kill", "pause", "destroy", "rename").contains(event.getStatus())) {
+                datagridService.deleteContainerInfo(name);
+            } else if (Arrays.asList("create", "start", "unpause").contains(event.getStatus())) {
+                List<Integer> ports = Arrays.stream(container.getPorts()).map(ContainerPort::getPrivatePort).filter(Objects::nonNull).collect(Collectors.toList());
+                ContainerInfo ci = new ContainerInfo(name, container.getId(), container.getImage(), ports, environment);
+                datagridService.saveContainerInfo(ci);
+            }
+        }
+    }
+
+    public void onInfinispanHealthEvent(Event event, Container container) {
+        String status = event.getStatus();
+        String health = status.replace("health_status: ", "");
+        LOGGER.infof("Container %s health status: %s", container.getNames()[0], health);
+        eventBus.publish(ConductorService.ADDRESS_INFINISPAN_HEALTH, health);
+    }
+
+    public void onDevModeEvent(Event event, Container container) {
+        try {
+            if (datagridService.isReady()) {
+                String status = event.getStatus();
+                String name = container.getNames()[0].replace("/", "");
+                if (Arrays.asList("stop", "die", "kill", "pause", "destroy").contains(event.getStatus())) {
+                    String projectId = name.replace(DEVMODE_SUFFIX, "");
+                    datagridService.deletePodStatus(projectId, environment, name);
+                    datagridService.deleteCamelStatuses(projectId, environment);
+                } else if (Arrays.asList("start", "unpause").contains(event.getStatus())) {
+                    String projectId = name.replace(DEVMODE_SUFFIX, "");
+                    PodStatus ps = new PodStatus(name, true, null, projectId, environment, true, Instant.ofEpochSecond(container.getCreated()).toString());
+                    datagridService.savePodStatus(ps);
+                } else if (status.startsWith("health_status:")) {
                     String health = status.replace("health_status: ", "");
                     LOGGER.infof("Container %s health status: %s", container.getNames()[0], health);
-                    eventBus.publish(ConductorService.ADDRESS_INFINISPAN_HEALTH, health);
-                } else if (Objects.equals(container.getLabels().get("type"), "devmode") && status.startsWith("health_status:")) {
-                    String health = status.replace("health_status: ", "");
-                    LOGGER.infof("Container %s health status: %s", container.getNames()[0], health);
-//                     update DevModeStatus
+                    //update DevModeStatus
                     String containerName = container.getNames()[0].replace("/", "");
                     DevModeStatus dms = datagridService.getDevModeStatus(container.getLabels().get("projectId"));
                     dms.setContainerName(containerName);
                     dms.setContainerId(container.getId());
                     datagridService.saveDevModeStatus(dms);
-                } else if (container.getNames()[0].endsWith(Constants.DEVMODE_SUFFIX)) {
-                    if (Arrays.asList("stop", "die", "kill", "pause", "destroy").contains(event.getStatus())) {
-                        String name = container.getNames()[0].replace("/", "");
-                        String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, "");
-                        datagridService.deletePodStatus(projectId, environment, name);
-                        datagridService.deleteCamelStatuses(projectId, environment);
-                    } else if (Arrays.asList("start", "unpause").contains(event.getStatus())) {
-                        String name = container.getNames()[0].replace("/", "");
-                        String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, "");
-                        PodStatus ps = new PodStatus(name, true, null, projectId, environment, true, Instant.ofEpochSecond(container.getCreated()).toString());
-                        datagridService.savePodStatus(ps);
-                    }
                 }
             }
         } catch (Exception exception) {
diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java
index eb4c8ef3..7c58465d 100644
--- a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java
+++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/DockerService.java
@@ -5,6 +5,7 @@ import com.github.dockerjava.api.async.ResultCallback;
 import com.github.dockerjava.api.command.CreateContainerResponse;
 import com.github.dockerjava.api.command.CreateNetworkResponse;
 import com.github.dockerjava.api.command.HealthState;
+import com.github.dockerjava.api.command.LogContainerCmd;
 import com.github.dockerjava.api.model.*;
 import com.github.dockerjava.core.DefaultDockerClientConfig;
 import com.github.dockerjava.core.DockerClientConfig;
@@ -16,7 +17,6 @@ import io.quarkus.scheduler.Scheduled;
 import io.smallrye.mutiny.tuples.Tuple2;
 import io.vertx.core.eventbus.EventBus;
 import io.vertx.core.json.JsonObject;
-import org.apache.camel.karavan.bashi.Constants;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
@@ -25,12 +25,14 @@ import java.io.IOException;
 import java.text.DecimalFormat;
 import java.util.*;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
 
 import static org.apache.camel.karavan.bashi.ConductorService.ADDRESS_CONTAINER_STATS;
 import static org.apache.camel.karavan.bashi.ConductorService.ADDRESS_INFINISPAN_HEALTH;
 import static org.apache.camel.karavan.bashi.Constants.DATAGRID_CONTAINER_NAME;
 import static org.apache.camel.karavan.bashi.Constants.NETWORK_NAME;
+import static org.apache.camel.karavan.datagrid.model.DevModeCommand.DEVMODE_SUFFIX;
 
 @ApplicationScoped
 public class DockerService {
@@ -53,7 +55,7 @@ public class DockerService {
             Statistics stats = getContainerStats(container.getId());
 
             String name = container.getNames()[0].replace("/", "");
-            String projectId = name.replace("-" + Constants.DEVMODE_SUFFIX, "");
+            String projectId = name.replace(DEVMODE_SUFFIX, "");
             String memoryUsage = formatMemory(stats.getMemoryStats().getUsage());
             String memoryLimit = formatMemory(stats.getMemoryStats().getLimit());
             JsonObject data = JsonObject.of(
@@ -132,6 +134,11 @@ public class DockerService {
         return containers.get(0);
     }
 
+    public Container getContainerByName(String name) {
+        List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        return containers.get(0);
+    }
+
     public Statistics getContainerStats(String containerId) {
         InvocationBuilder.AsyncResultCallback<Statistics> callback = new InvocationBuilder.AsyncResultCallback<>();
         getDockerClient().statsCmd(containerId).withContainerId(containerId).withNoStream(true).exec(callback);
@@ -186,6 +193,18 @@ public class DockerService {
         startContainer(name);
     }
 
+    public void logContainer(String containerName) {
+        try {
+            LogCallback callback = new LogCallback();
+            Container container = getContainerByName(containerName);
+            getDockerClient().logContainerCmd(container.getId())
+                .withStdOut(true).withStdErr(true).withTimestamps(true).exec(callback);
+            callback.awaitCompletion();
+        } catch (InterruptedException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
     public void stopContainer(String name) {
         List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
         if (containers.size() == 1) {
@@ -204,6 +223,14 @@ public class DockerService {
         }
     }
 
+    public void killContainer(String name) {
+        List<Container> containers = getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        if (containers.size() == 1) {
+            Container container = containers.get(0);
+            getDockerClient().killContainerCmd(container.getId()).exec();
+        }
+    }
+
     public void pullImage(String image) throws InterruptedException {
         List<Image> images = getDockerClient().listImagesCmd().withShowAll(true).exec();
         if (!images.stream().filter(i -> Arrays.asList(i.getRepoTags()).contains(image)).findFirst().isPresent()) {
diff --git a/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java
new file mode 100644
index 00000000..48c061cd
--- /dev/null
+++ b/karavan-cloud/karavan-bashi/src/main/java/org/apache/camel/karavan/bashi/docker/LogCallback.java
@@ -0,0 +1,26 @@
+package org.apache.camel.karavan.bashi.docker;
+
+import com.github.dockerjava.api.async.ResultCallback;
+import com.github.dockerjava.api.model.Frame;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class LogCallback extends ResultCallback.Adapter<Frame> {
+    protected final StringBuffer log = new StringBuffer();
+
+    List<Frame> collectedFrames = new ArrayList<>();
+
+    boolean collectFrames = false;
+
+    @Override
+    public void onNext(Frame frame) {
+        if (collectFrames) collectedFrames.add(frame);
+        log.append(new String(frame.getPayload()));
+    }
+
+    @Override
+    public String toString() {
+        return log.toString();
+    }
+}
\ No newline at end of file
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java
index 38f40026..5df37b50 100644
--- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/DatagridService.java
@@ -73,6 +73,7 @@ public class DatagridService  {
     private RemoteCache<String, Environment> environments;
     private RemoteCache<String, String> commits;
     private RemoteCache<GroupedKey, DevModeStatus> devmodeStatuses;
+    private RemoteCache<GroupedKey, ContainerInfo> containers;
     private RemoteCache<GroupedKey, DevModeCommand> devmodeCommands;
     private final AtomicBoolean ready = new AtomicBoolean(false);
 
@@ -120,6 +121,7 @@ public class DatagridService  {
         commits = getOrCreateCache("commits", false);
         deploymentStatuses = getOrCreateCache(DeploymentStatus.CACHE, false);
         devmodeStatuses = getOrCreateCache(DevModeStatus.CACHE, false);
+        containers = getOrCreateCache(ContainerInfo.CACHE, false);
         devmodeCommands = getOrCreateCache(DevModeCommand.CACHE, true);
 
         cacheManager.getCache(DevModeCommand.CACHE).addClientListener(new DevModeCommandListener(eventBus));
@@ -140,15 +142,6 @@ public class DatagridService  {
         return cacheManager.administration().getOrCreateCache(name, new StringConfiguration(String.format(config, name)));
     }
 
-    private void cleanData() {
-        environments.clear();
-        deploymentStatuses.clear();
-        podStatuses.clear();
-        pipelineStatuses.clear();
-        camelStatuses.clear();
-        devmodeCommands.clear();
-    }
-
     @ConsumeEvent(value = ADDRESS_DEVMODE_COMMAND_INTERNAL, blocking = true, ordered = true, local = false)
     void sendCommand(JsonObject message) {
         GroupedKey key = message.mapTo(GroupedKey.class);
@@ -323,7 +316,7 @@ public class DatagridService  {
 
     public List<CamelStatus> getCamelStatusesByProjectIdEnv(String projectId, String env) {
         QueryFactory queryFactory = Search.getQueryFactory(camelStatuses);
-        return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus WHERE projectId = :projectId AND name = :env")
+        return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus WHERE projectId = :projectId AND env = :env")
                 .setParameter("projectId", projectId)
                 .setParameter("env", env)
                 .execute().list();
@@ -394,19 +387,35 @@ public class DatagridService  {
        return new ArrayList<>(devmodeStatuses.values());
     }
 
-    public void sendDevModeCommand(String projectId, DevModeCommand command) {
-        if (command.getProjectId() == null) {
-            command.setProjectId(projectId);
-        }
-        devmodeCommands.put(GroupedKey.create(projectId, DEFAULT_ENVIRONMENT, UUID.randomUUID().toString()), command);
+    public void sendDevModeCommand(DevModeCommand command) {
+        devmodeCommands.put(GroupedKey.create(command.getContainerName(), DEFAULT_ENVIRONMENT, command.getTime().toString()), command);
     }
 
     public DevModeCommand getDevModeCommand(GroupedKey key) {
         return devmodeCommands.get(key);
     }
 
-    public DevModeCommand getDevModeCommand(String projectId) {
-        return getDevModeCommand(GroupedKey.create(projectId, DEFAULT_ENVIRONMENT, projectId));
+    public void deleteDevModeCommand(DevModeCommand command) {
+        containers.remove(GroupedKey.create(command.getContainerName(), DEFAULT_ENVIRONMENT, command.getTime().toString()));
+    }
+
+    public void saveContainerInfo(ContainerInfo ci) {
+        containers.put(GroupedKey.create(ci.getContainerName(), ci.getEnv() != null ? ci.getEnv() : DEFAULT_ENVIRONMENT, ci.getContainerName()), ci);
+    }
+
+    public void getContainerInfo(String name, String env) {
+        containers.get(GroupedKey.create(name, env, name));
+    }
+
+    public List<ContainerInfo> getContainerInfos(String env) {
+        QueryFactory queryFactory = Search.getQueryFactory(containers);
+        return queryFactory.<ContainerInfo>create("FROM karavan.ContainerInfo WHERE env = :env")
+                .setParameter("env", env)
+                .execute().list();
+    }
+
+    public void deleteContainerInfo(String containerName) {
+        containers.remove(GroupedKey.create(containerName, DEFAULT_ENVIRONMENT, containerName));
     }
 
     public void clearAllStatuses() {
@@ -415,7 +424,8 @@ public class DatagridService  {
             podStatuses.clearAsync(),
             pipelineStatuses.clearAsync(),
             camelStatuses.clearAsync(),
-            devmodeCommands.clearAsync()
+            devmodeCommands.clearAsync(),
+            devmodeStatuses.clearAsync()
         ).join();
     }
 
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java
deleted file mode 100644
index ff34f9ad..00000000
--- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/CommandName.java
+++ /dev/null
@@ -1,10 +0,0 @@
-package org.apache.camel.karavan.datagrid.model;
-
-import org.infinispan.protostream.annotations.ProtoEnumValue;
-
-public enum CommandName {
-
-        @ProtoEnumValue(number = 0, name = "RUN") RUN,
-        @ProtoEnumValue (number = 1, name = "DELETE") DELETE,
-        @ProtoEnumValue (number = 2, name = "RELOAD") RELOAD
-}
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java
new file mode 100644
index 00000000..c23dcd16
--- /dev/null
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/ContainerInfo.java
@@ -0,0 +1,70 @@
+package org.apache.camel.karavan.datagrid.model;
+
+import org.infinispan.protostream.annotations.ProtoFactory;
+import org.infinispan.protostream.annotations.ProtoField;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ContainerInfo {
+    public static final String CACHE = "container_infos";
+    @ProtoField(number = 1)
+    String containerName;
+    @ProtoField(number = 2)
+    String containerId;
+    @ProtoField(number = 3)
+    String image;
+    @ProtoField(number = 4, collectionImplementation = ArrayList.class)
+    List<Integer> ports;
+    @ProtoField(number = 5)
+    String env;
+
+    @ProtoFactory
+    public ContainerInfo(String containerName, String containerId, String image, List<Integer> ports, String env) {
+        this.containerName = containerName;
+        this.containerId = containerId;
+        this.image = image;
+        this.ports = ports;
+        this.env = env;
+    }
+
+    public String getEnv() {
+        return env;
+    }
+
+    public void setEnv(String env) {
+        this.env = env;
+    }
+
+    public String getContainerName() {
+        return containerName;
+    }
+
+    public void setContainerName(String containerName) {
+        this.containerName = containerName;
+    }
+
+    public String getContainerId() {
+        return containerId;
+    }
+
+    public void setContainerId(String containerId) {
+        this.containerId = containerId;
+    }
+
+    public String getImage() {
+        return image;
+    }
+
+    public void setImage(String image) {
+        this.image = image;
+    }
+
+    public List<Integer> getPorts() {
+        return ports;
+    }
+
+    public void setPorts(List<Integer> ports) {
+        this.ports = ports;
+    }
+}
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java
index 1d5a6517..3bc80546 100644
--- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommand.java
@@ -3,29 +3,46 @@ package org.apache.camel.karavan.datagrid.model;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
+import java.time.Instant;
+
 public class DevModeCommand {
 
     public static final String CACHE = "devmode_commands";
+    public static final String DEVMODE_SUFFIX = "-devmode";
     @ProtoField(number = 1)
-    CommandName commandName;
+    DevModeCommandName commandName;
     @ProtoField(number = 2)
     String projectId;
     @ProtoField(number = 3)
+    String containerName;
+    @ProtoField(number = 4)
+    DevModeCommandType type;
+    @ProtoField(number = 5)
     Long time;
 
     @ProtoFactory
-    public DevModeCommand(CommandName commandName, String projectId, Long time) {
+    public DevModeCommand(DevModeCommandName commandName, String projectId, String containerName, DevModeCommandType type, Long time) {
         this.commandName = commandName;
         this.projectId = projectId;
+        this.containerName = containerName;
+        this.type = type;
         this.time = time;
     }
 
-    public DevModeCommand(CommandName commandName, Long time) {
-        this.commandName = commandName;
-        this.time = time;
+    public static DevModeCommand createDevModeCommand(DevModeCommandName commandName, String projectId) {
+        return new DevModeCommand(commandName, projectId, projectId + DEVMODE_SUFFIX, DevModeCommandType.DEVMODE, Instant.now().toEpochMilli());
+    }
+
+    public static DevModeCommand createDevServiceCommand(DevModeCommandName commandName, String serviceName) {
+        return new DevModeCommand(commandName, null, serviceName, DevModeCommandType.DEVSERVICE, Instant.now().toEpochMilli());
     }
 
-    public DevModeCommand() {
+    public DevModeCommandName getCommandName() {
+        return commandName;
+    }
+
+    public void setCommandName(DevModeCommandName commandName) {
+        this.commandName = commandName;
     }
 
     public String getProjectId() {
@@ -36,12 +53,20 @@ public class DevModeCommand {
         this.projectId = projectId;
     }
 
-    public CommandName getCommandName() {
-        return commandName;
+    public String getContainerName() {
+        return containerName;
     }
 
-    public void setCommandName(CommandName commandName) {
-        this.commandName = commandName;
+    public void setContainerName(String containerName) {
+        this.containerName = containerName;
+    }
+
+    public DevModeCommandType getType() {
+        return type;
+    }
+
+    public void setType(DevModeCommandType type) {
+        this.type = type;
     }
 
     public Long getTime() {
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java
new file mode 100644
index 00000000..aa0a550b
--- /dev/null
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandName.java
@@ -0,0 +1,12 @@
+package org.apache.camel.karavan.datagrid.model;
+
+import org.infinispan.protostream.annotations.ProtoEnumValue;
+
+public enum DevModeCommandName {
+
+        @ProtoEnumValue(number = 0, name = "RUN") RUN,
+        @ProtoEnumValue (number = 1, name = "STOP") STOP,
+        @ProtoEnumValue (number = 2, name = "DELETE") DELETE,
+        @ProtoEnumValue (number = 3, name = "RELOAD") RELOAD,
+        @ProtoEnumValue (number = 4, name = "LOG") LOG
+}
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java
new file mode 100644
index 00000000..c0a1d582
--- /dev/null
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/DevModeCommandType.java
@@ -0,0 +1,9 @@
+package org.apache.camel.karavan.datagrid.model;
+
+import org.infinispan.protostream.annotations.ProtoEnumValue;
+
+public enum DevModeCommandType {
+
+        @ProtoEnumValue(number = 0, name = "DEVMODE") DEVMODE,
+        @ProtoEnumValue (number = 1, name = "DEVSERVICE") DEVSERVICE
+}
diff --git a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java
index be78b42a..22d5e741 100644
--- a/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java
+++ b/karavan-cloud/karavan-datagrid/src/main/java/org/apache/camel/karavan/datagrid/model/KaravanSchema.java
@@ -14,10 +14,12 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
                 PodStatus.class,
                 Environment.class,
                 ServiceStatus.class,
-                CommandName.class,
+                DevModeCommandName.class,
+                DevModeCommandType.class,
                 CamelStatusName.class,
                 DevModeCommand.class,
-                DevModeStatus.class
+                DevModeStatus.class,
+                ContainerInfo.class
         },
         schemaFileName = "karavan.proto",
         schemaFilePath = "proto/",
diff --git a/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java b/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java
index 5e4fb8c0..e809d178 100644
--- a/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java
+++ b/karavan-cloud/karavan-datagrid/src/test/java/org/apache/camel/karavan/datagrid/DataGridTest.java
@@ -10,7 +10,6 @@ import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.TestInstance;
 
 import javax.inject.Inject;
-import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.concurrent.*;
@@ -38,15 +37,24 @@ public class DataGridTest {
         commandsReceived.add(message.mapTo(DevModeCommand.class));
     }
 
-//    @Test
+    @Test
+    public void testContainersStatuses() throws InterruptedException {
+        ContainerInfo ci = new ContainerInfo("demo", "id", "image", List.of(8080, 8081, 8082), "dev");
+        datagridService.saveContainerInfo(ci);
+        List<ContainerInfo> list = datagridService.getContainerInfos("dev");
+        System.out.println(list);
+        assertEquals(1, list.size());
+    }
+
+    @Test
     public void sendCommand() throws InterruptedException {
         List<DevModeCommand> commandsSent = List.of(
-                new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli()),
-                new DevModeCommand(CommandName.RELOAD, Instant.now().toEpochMilli()),
-                new DevModeCommand(CommandName.DELETE, Instant.now().toEpochMilli()),
-                new DevModeCommand(CommandName.RUN, Instant.now().toEpochMilli())
+                DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, "test1"),
+                DevModeCommand.createDevModeCommand(DevModeCommandName.RELOAD, "test1"),
+                DevModeCommand.createDevModeCommand(DevModeCommandName.DELETE, "test1"),
+                DevModeCommand.createDevModeCommand(DevModeCommandName.RUN, "test1")
         );
-        commandsSent.forEach(devModeCommand -> datagridService.sendDevModeCommand("test1", devModeCommand));
+        commandsSent.forEach(devModeCommand -> datagridService.sendDevModeCommand(devModeCommand));
 
         CountDownLatch latch = new CountDownLatch(4);
         latch.await(5, TimeUnit.SECONDS);
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx b/karavan-designer/src/designer/beans/BeanProperties.tsx
index b7ab5532..24c1e202 100644
--- a/karavan-designer/src/designer/beans/BeanProperties.tsx
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -54,9 +54,9 @@ interface State {
     bean?: NamedBeanDefinition
     properties: Map<string, [string, string, boolean]>
     key: string,
-    showKubernetesSelector: boolean
-    kubernetesSelectorUuid?: string
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorUuid?: string
+    infrastructureSelectorProperty?: string
 }
 
 export class BeanProperties extends React.Component<Props, State> {
@@ -70,7 +70,7 @@ export class BeanProperties extends React.Component<Props, State> {
     public state: State = {
         bean: this.props.bean,
         key: '',
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         properties: this.props.bean?.properties ? this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, [string, string, boolean]>()
     };
 
@@ -118,31 +118,31 @@ export class BeanProperties extends React.Component<Props, State> {
         })
     }
 
-    selectKubernetes = (value: string) => {
-        const propertyId = this.state.kubernetesSelectorProperty;
-        const uuid = this.state.kubernetesSelectorUuid;
+    selectInfrastructure = (value: string) => {
+        const propertyId = this.state.infrastructureSelectorProperty;
+        const uuid = this.state.infrastructureSelectorUuid;
         if (propertyId && uuid){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.propertyChanged(uuid, propertyId, value, false);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (uuid: string, propertyName: string) => {
-        this.setState({kubernetesSelectorUuid: uuid, kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (uuid: string, propertyName: string) => {
+        this.setState({infrastructureSelectorUuid: uuid, infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     cloneBean = () => {
@@ -208,8 +208,8 @@ export class BeanProperties extends React.Component<Props, State> {
                                            onChange={e => this.propertyChanged(i, e, value, showPassword)}/>
                                 <InputGroup>
                                     {inInfrastructure &&
-                                        <Tooltip position="bottom-end" content="Select value from Kubernetes">
-                                        <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}>
+                                        <Tooltip position="bottom-end" content="Select value from Infrastructure">
+                                        <Button variant="control" onClick={e => this.openInfrastructureSelector(i, key)}>
                                             {icon}
                                         </Button>
                                     </Tooltip>}
@@ -246,7 +246,7 @@ export class BeanProperties extends React.Component<Props, State> {
                     {this.state.bean === undefined && <IntegrationHeader integration={this.props.integration}/>}
                     {this.state.bean !== undefined && this.getBeanForm()}
                 </Form>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }
diff --git a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
index 39817f7c..ca1f6a0d 100644
--- a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
@@ -23,7 +23,7 @@ import {
     Select,
     SelectVariant,
     SelectDirection,
-    SelectOption, InputGroup, TextArea, Tooltip, Button,
+    SelectOption, InputGroup, TextArea, Tooltip, Button, capitalize,
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -57,8 +57,8 @@ interface State {
     selectStatus: Map<string, boolean>
     showEditor: boolean
     showPassword: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     ref: any
     id: string
 }
@@ -69,7 +69,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
         selectStatus: new Map<string, boolean>(),
         showEditor: false,
         showPassword: false,
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         ref: React.createRef(),
         id: prefix + "-" + this.props.property.name
     }
@@ -179,7 +179,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
         </InputGroup>
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -189,29 +189,29 @@ export class ComponentParameterField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyName = this.state.kubernetesSelectorProperty;
+        const propertyName = this.state.infrastructureSelectorProperty;
         if (propertyName) {
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.parametersChanged(propertyName, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput(property: ComponentProperty, value: any) {
@@ -221,8 +221,8 @@ export class ComponentParameterField extends React.Component<Props, State> {
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return <InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -340,7 +340,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
                     && this.getSelect(property, value)}
                 {property.type === 'boolean'
                     && this.getSwitch(property, value)}
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </FormGroup>
         )
     }
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index e11ee485..d17a26c3 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
@@ -35,7 +35,7 @@ import {
     Text,
     Tooltip,
     Card,
-    InputGroup,
+    InputGroup, capitalize,
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -87,8 +87,8 @@ interface State {
     isShowAdvanced: Map<string, boolean>,
     arrayValues: Map<string, string>,
     showEditor: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    infrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     customCode?: string
     ref: any
 }
@@ -100,7 +100,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         arrayValues: new Map<string, string>(),
         isShowAdvanced: new Map<string, boolean>(),
         showEditor: false,
-        showKubernetesSelector: false,
+        infrastructureSelector: false,
         ref: React.createRef(),
     };
 
@@ -176,7 +176,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         return property.name === 'uri' && !['ToDefinition', 'ToDynamicDefinition', 'WireTapDefinition'].includes(dslName)
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -186,29 +186,29 @@ export class DslPropertyField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyName = this.state.kubernetesSelectorProperty;
+        const propertyName = this.state.infrastructureSelectorProperty;
         if (propertyName) {
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.propertyChanged(propertyName, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({infrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, infrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({infrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.infrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput = (property: PropertyMeta, value: any) => {
@@ -218,8 +218,8 @@ export class DslPropertyField extends React.Component<Props, State> {
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return (<InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -732,7 +732,7 @@ export class DslPropertyField extends React.Component<Props, State> {
                     {isKamelet && property.name === 'parameters' && this.getKameletParameters()}
                     {!isKamelet && property.name === 'parameters' && this.getComponentParameters(property)}
                 </FormGroup>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }
diff --git a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
index 04c8d43a..e0069bc0 100644
--- a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
+++ b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
@@ -208,6 +208,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
 
     render() {
         const tabIndex = this.state.tabIndex;
+        const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services'];
         return (
             <Modal
                 aria-label="Select from Infrastructure"
@@ -223,9 +224,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                         </FlexItem>
                         <FlexItem>
                             <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.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)}
                             </Tabs>
                         </FlexItem>
                     </Flex>
@@ -235,7 +234,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                     {this.searchInput()}
                     {tabIndex === 'configMap' && this.getConfigMapTable()}
                     {tabIndex === 'secret' && this.getSecretsTable()}
-                    {tabIndex === 'service' && this.getServicesTable()}
+                    {tabIndex === 'services' && this.getServicesTable()}
                 </PageSection>
             </Modal>
         )
diff --git a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
index 8beed690..9b0a3b39 100644
--- a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
@@ -19,7 +19,7 @@ import {
     FormGroup,
     TextInput,
     Popover,
-    Switch, InputGroup, Button, TextArea, Tooltip
+    Switch, InputGroup, Button, TextArea, Tooltip, capitalize
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -45,8 +45,8 @@ interface State {
     selectIsOpen: boolean
     showEditor: boolean
     showPassword: boolean
-    showKubernetesSelector: boolean
-    kubernetesSelectorProperty?: string
+    showInfrastructureSelector: boolean
+    infrastructureSelectorProperty?: string
     ref: any
 }
 
@@ -56,7 +56,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
         selectIsOpen: false,
         showEditor: false,
         showPassword: false,
-        showKubernetesSelector: false,
+        showInfrastructureSelector: false,
         ref: React.createRef(),
     }
 
@@ -69,7 +69,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
         this.setState({selectIsOpen: false});
     }
 
-    selectKubernetes = (value: string) => {
+    selectInfrastructure = (value: string) => {
         // check if there is a selection
         const textVal = this.state.ref.current;
         const cursorStart = textVal.selectionStart;
@@ -79,29 +79,29 @@ export class KameletPropertyField extends React.Component<Props, State> {
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyId = this.state.kubernetesSelectorProperty;
+        const propertyId = this.state.infrastructureSelectorProperty;
         if (propertyId){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
             this.parametersChanged(propertyId, value);
-            this.setState({showKubernetesSelector: false, kubernetesSelectorProperty: undefined})
+            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
         }
     }
 
-    openKubernetesSelector = (propertyName: string) => {
-        this.setState({kubernetesSelectorProperty: propertyName, showKubernetesSelector: true});
+    openInfrastructureSelector = (propertyName: string) => {
+        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
     }
 
-    closeKubernetesSelector = () => {
-        this.setState({showKubernetesSelector: false})
+    closeInfrastructureSelector = () => {
+        this.setState({showInfrastructureSelector: false})
     }
 
-    getKubernetesSelectorModal() {
+    getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showKubernetesSelector}
-                onClose={() => this.closeKubernetesSelector()}
-                onSelect={this.selectKubernetes}/>)
+                isOpen={this.state.showInfrastructureSelector}
+                onClose={() => this.closeInfrastructureSelector()}
+                onSelect={this.selectInfrastructure}/>)
     }
 
     getStringInput() {
@@ -115,8 +115,8 @@ export class KameletPropertyField extends React.Component<Props, State> {
         const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton
         return <InputGroup>
             {showInfraSelectorButton  &&
-                <Tooltip position="bottom-end" content="Select from Kubernetes">
-                    <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}>
+                <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
+                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.id)}>
                         {icon}
                     </Button>
                 </Tooltip>}
@@ -197,7 +197,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
                         onChange={e => this.parametersChanged(property.id, !Boolean(value))}/>
                     }
                 </FormGroup>
-                {this.getKubernetesSelectorModal()}
+                {this.getInfrastructureSelectorModal()}
             </div>
         )
     }


[camel-karavan] 01/02: Infrastructure definition #817

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 bef05933c33672a6040fe2181255a7ca2a5c5e7a
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Jul 13 12:54:53 2023 -0400

    Infrastructure definition #817
---
 .../camel/karavan/api/ConfigurationResource.java   |  2 +-
 ...esResource.java => InfrastructureResource.java} | 36 ++++++++++++++--------
 .../karavan-app/src/main/webui/src/Main.tsx        |  8 +++--
 .../src/main/webui/src/api/KaravanApi.tsx          | 34 ++++++++++----------
 .../src/main/webui/src/api/ProjectModels.ts        |  2 +-
 .../src/main/webui/src/api/ProjectService.ts       | 24 ++++++---------
 .../webui/src/designer/beans/BeanProperties.tsx    | 13 +++++---
 .../route/property/ComponentParameterField.tsx     | 16 +++++-----
 .../designer/route/property/DslPropertyField.tsx   | 17 +++++-----
 .../route/property/InfrastructureSelector.tsx      | 16 +++++-----
 .../route/property/KameletPropertyField.tsx        | 17 +++++-----
 .../designer/route/property/KubernetesSelector.tsx |  8 ++---
 .../{KubernetesAPI.ts => InfrastructureAPI.ts}     |  4 +--
 .../src/designer/beans/BeanProperties.tsx          | 13 +++++---
 .../route/property/ComponentParameterField.tsx     | 16 +++++-----
 .../designer/route/property/DslPropertyField.tsx   | 17 +++++-----
 .../route/property/InfrastructureSelector.tsx      | 16 +++++-----
 .../route/property/KameletPropertyField.tsx        | 17 +++++-----
 .../{KubernetesAPI.ts => InfrastructureAPI.ts}     |  4 +--
 19 files changed, 154 insertions(+), 126 deletions(-)

diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
index 486e8fba..3bd0f2de 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
@@ -57,7 +57,7 @@ public class ConfigurationResource {
         return Response.ok(
                 Map.of(
                         "version", version,
-                        "inKubernetes", kubernetesService.inKubernetes(),
+                        "infrastructure", kubernetesService.inKubernetes() ? "kubernetes" : "docker",
                         "environment", environment,
                         "environments", datagridService.getEnvironments().stream()
                                 .map(e -> e.getName())
diff --git a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
similarity index 87%
rename from karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
rename to karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
index 6ff1020e..d2749563 100644
--- a/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-cloud/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
@@ -36,8 +36,8 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.stream.Collectors;
 
-@Path("/api/kubernetes")
-public class KubernetesResource {
+@Path("/api/infrastructure")
+public class InfrastructureResource {
 
     @Inject
     EventBus eventBus;
@@ -51,7 +51,7 @@ public class KubernetesResource {
     @ConfigProperty(name = "karavan.environment")
     String environment;
 
-    private static final Logger LOGGER = Logger.getLogger(KubernetesResource.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(InfrastructureResource.class.getName());
 
     @POST
     @Produces(MediaType.APPLICATION_JSON)
@@ -176,23 +176,35 @@ public class KubernetesResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/configmap/{env}")
-    public Response getConfigMaps(@PathParam("env") String env) throws Exception {
-        return Response.ok(kubernetesService.getConfigMaps(kubernetesService.getNamespace())).build();
+    @Path("/configmaps")
+    public Response getConfigMaps() throws Exception {
+        if (kubernetesService.inKubernetes()) {
+            return Response.ok(kubernetesService.getConfigMaps(kubernetesService.getNamespace())).build();
+        } else {
+            return Response.ok(List.of()).build();
+        }
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/secret/{env}")
-    public Response getSecrets(@PathParam("env") String env) throws Exception {
-        return Response.ok(kubernetesService.getSecrets(kubernetesService.getNamespace())).build();
+    @Path("/secrets")
+    public Response getSecrets() throws Exception {
+        if (kubernetesService.inKubernetes()) {
+            return Response.ok(kubernetesService.getSecrets(kubernetesService.getNamespace())).build();
+        } else {
+            return Response.ok(List.of()).build();
+        }
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/service/{env}")
-    public Response getServices(@PathParam("env") String env) throws Exception {
-        return Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build();
+    @Path("/services")
+    public Response getServices() throws Exception {
+        if (kubernetesService.inKubernetes()) {
+            return Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build();
+        } else {
+            return Response.ok(List.of()).build();
+        }
     }
 
     // TODO: implement log watch
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/Main.tsx b/karavan-cloud/karavan-app/src/main/webui/src/Main.tsx
index cf61f783..a2de26fa 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/Main.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/Main.tsx
@@ -28,10 +28,11 @@ import {MainLogin} from "./MainLogin";
 import {DashboardPage} from "./dashboard/DashboardPage";
 import {Subscription} from "rxjs";
 import {ProjectEventBus} from "./api/ProjectEventBus";
-import {PodStatus, Project, ToastMessage} from "./api/ProjectModels";
+import {AppConfig, PodStatus, Project, ToastMessage} from "./api/ProjectModels";
 import {ProjectPage} from "./project/ProjectPage";
 import {useAppConfigStore, useDevModeStore, useFileStore, useProjectStore} from "./api/ProjectStore";
 import {Notification} from "./Notification";
+import {InfrastructureAPI} from "./designer/utils/InfrastructureAPI";
 
 class MenuItem {
     pageId: string = '';
@@ -111,9 +112,10 @@ export class Main extends React.Component<Props, State> {
     }
 
     getData() {
-        KaravanApi.getConfiguration((config: any) => {
+        KaravanApi.getConfiguration((config: AppConfig) => {
             this.setState({config: config, request: uuidv4()});
-            useAppConfigStore.setState({config: config})
+            useAppConfigStore.setState({config: config});
+            InfrastructureAPI.infrastructure = config.infrastructure;
         });
         this.updateKamelets();
         this.updateComponents();
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-cloud/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index f1549a3a..747808e1 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -349,7 +349,7 @@ export class KaravanApi {
     }
 
     static async pipelineRun(project: Project, environment: string, after: (res: AxiosResponse<any>) => void) {
-        instance.post('/api/kubernetes/pipeline/' + environment, project)
+        instance.post('/api/infrastructure/pipeline/' + environment, project)
             .then(res => {
                 after(res);
             }).catch(err => {
@@ -358,7 +358,7 @@ export class KaravanApi {
     }
 
     static async getPipelineLog(environment: string, pipelineRunName: string, after: (res: AxiosResponse<any>) => void) {
-        instance.get('/api/kubernetes/pipeline/log/' + environment + "/" + pipelineRunName)
+        instance.get('/api/infrastructure/pipeline/log/' + environment + "/" + pipelineRunName)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -369,7 +369,7 @@ export class KaravanApi {
     }
 
     static async stopPipelineRun(environment: string, pipelineRunName: string, after: (res: AxiosResponse<any>) => void) {
-        instance.delete('/api/kubernetes/pipelinerun/' + environment + "/" + pipelineRunName)
+        instance.delete('/api/infrastructure/pipelinerun/' + environment + "/" + pipelineRunName)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -380,7 +380,7 @@ export class KaravanApi {
     }
 
     static async getContainerLog(environment: string, name: string, after: (res: AxiosResponse<string>) => void) {
-        instance.get('/api/kubernetes/container/log/' + environment + "/" + name)
+        instance.get('/api/infrastructure/container/log/' + environment + "/" + name)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -391,7 +391,7 @@ export class KaravanApi {
     }
 
     static async getAllServiceStatuses(after: (statuses: ServiceStatus[]) => void) {
-        instance.get('/api/kubernetes/service')
+        instance.get('/api/infrastructure/service')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -402,7 +402,7 @@ export class KaravanApi {
     }
 
     static async getAllDeploymentStatuses(after: (statuses: DeploymentStatus[]) => void) {
-        instance.get('/api/kubernetes/deployment')
+        instance.get('/api/infrastructure/deployment')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -413,7 +413,7 @@ export class KaravanApi {
     }
 
     static async getDeploymentStatuses(env: string, after: (statuses: DeploymentStatus[]) => void) {
-        instance.get('/api/kubernetes/deployment/' + env)
+        instance.get('/api/infrastructure/deployment/' + env)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -424,7 +424,7 @@ export class KaravanApi {
     }
 
     static async rolloutDeployment(name: string, environment: string, after: (res: AxiosResponse<any>) => void) {
-        instance.post('/api/kubernetes/deployment/rollout/' + environment + '/' + name, "")
+        instance.post('/api/infrastructure/deployment/rollout/' + environment + '/' + name, "")
             .then(res => {
                 after(res);
             }).catch(err => {
@@ -433,7 +433,7 @@ export class KaravanApi {
     }
 
     static async deleteDeployment(environment: string, name: string, after: (res: AxiosResponse<any>) => void) {
-        instance.delete('/api/kubernetes/deployment/' + environment + '/' + name)
+        instance.delete('/api/infrastructure/deployment/' + environment + '/' + name)
             .then(res => {
                 after(res);
             }).catch(err => {
@@ -442,7 +442,7 @@ export class KaravanApi {
     }
 
     static async getProjectPodStatuses(project: string, env: string, after: (statuses: PodStatus[]) => void) {
-        instance.get('/api/kubernetes/pod/' + project + "/" + env)
+        instance.get('/api/infrastructure/pod/' + project + "/" + env)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -453,7 +453,7 @@ export class KaravanApi {
     }
 
     static async deletePod(environment: string, name: string, after: (res: AxiosResponse<any>) => void) {
-        instance.delete('/api/kubernetes/pod/' + environment + '/' + name)
+        instance.delete('/api/infrastructure/pod/' + environment + '/' + name)
             .then(res => {
                 after(res);
             }).catch(err => {
@@ -461,8 +461,8 @@ export class KaravanApi {
         });
     }
 
-    static async getConfigMaps(environment: string, after: (any: []) => void) {
-        instance.get('/api/kubernetes/configmap/' + environment)
+    static async getConfigMaps(after: (any: []) => void) {
+        instance.get('/api/infrastructure/configmaps/')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -472,8 +472,8 @@ export class KaravanApi {
         });
     }
 
-    static async getSecrets(environment: string, after: (any: []) => void) {
-        instance.get('/api/kubernetes/secret/' + environment)
+    static async getSecrets(after: (any: []) => void) {
+        instance.get('/api/infrastructure/secrets')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -483,8 +483,8 @@ export class KaravanApi {
         });
     }
 
-    static async getServices(environment: string, after: (any: []) => void) {
-        instance.get('/api/kubernetes/service/' + environment)
+    static async getServices(after: (any: []) => void) {
+        instance.get('/api/infrastructure/services')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectModels.ts b/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectModels.ts
index 66ebe79b..8f54d1e2 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectModels.ts
+++ b/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectModels.ts
@@ -2,7 +2,7 @@ import {v4 as uuidv4} from "uuid";
 
 export class AppConfig {
     version: string = '';
-    inKubernetes: boolean = true;
+    infrastructure: 'kubernetes' | 'docker' | 'local' = 'local';
     environment: string = '';
     environments: string[] = [];
     runtime: string = '';
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectService.ts b/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectService.ts
index d3a60eb2..dba7ffd8 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectService.ts
+++ b/karavan-cloud/karavan-app/src/main/webui/src/api/ProjectService.ts
@@ -1,7 +1,7 @@
 import {KaravanApi} from "./KaravanApi";
 import {DeploymentStatus, PodStatus, Project, ProjectFile, ToastMessage} from "./ProjectModels";
 import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
-import {KubernetesAPI} from "../designer/utils/KubernetesAPI";
+import {InfrastructureAPI} from "../designer/utils/InfrastructureAPI";
 import {unstable_batchedUpdates} from 'react-dom'
 import {
     useAppConfigStore,
@@ -174,7 +174,6 @@ export class ProjectService {
 
     public static refreshProjectData() {
         const project = useProjectStore.getState().project;
-        const environment = useAppConfigStore.getState().config.environment;
         KaravanApi.getProject(project.projectId, (project: Project) => {
             // ProjectEventBus.selectProject(project);
             KaravanApi.getTemplatesFiles((files: ProjectFile[]) => {
@@ -190,17 +189,14 @@ export class ProjectService {
             useFilesStore.setState({files: files});
         });
 
-        KubernetesAPI.inKubernetes = true;
-        if (environment) {
-            KaravanApi.getConfigMaps(environment, (any: []) => {
-                KubernetesAPI.setConfigMaps(any);
-            });
-            KaravanApi.getSecrets(environment, (any: []) => {
-                KubernetesAPI.setSecrets(any);
-            });
-            KaravanApi.getServices(environment, (any: []) => {
-                KubernetesAPI.setServices(any);
-            });
-        }
+        KaravanApi.getConfigMaps((any: []) => {
+            InfrastructureAPI.setConfigMaps(any);
+        });
+        KaravanApi.getSecrets((any: []) => {
+            InfrastructureAPI.setSecrets(any);
+        });
+        KaravanApi.getServices((any: []) => {
+            InfrastructureAPI.setServices(any);
+        });
     }
 }
\ No newline at end of file
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
index 78f475f4..b7ab5532 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/beans/BeanProperties.tsx
@@ -34,11 +34,12 @@ import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import {IntegrationHeader} from "../utils/KaravanComponents";
 import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
-import {KubernetesSelector} from "../route/property/KubernetesSelector";
+import {InfrastructureSelector} from "../route/property/InfrastructureSelector";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
-import {KubernetesAPI} from "../utils/KubernetesAPI";
+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";
 
 
 interface Props {
@@ -137,7 +138,7 @@ export class BeanProperties extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -199,15 +200,17 @@ export class BeanProperties extends React.Component<Props, State> {
                         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" name="key" value={key}
                                            onChange={e => this.propertyChanged(i, e, value, showPassword)}/>
                                 <InputGroup>
-                                    {KubernetesAPI.inKubernetes &&
+                                    {inInfrastructure &&
                                         <Tooltip position="bottom-end" content="Select value from Kubernetes">
                                         <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}>
-                                            <KubernetesIcon/>
+                                            {icon}
                                         </Button>
                                     </Tooltip>}
                                     <TextInput
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
index e9c6d02f..39817f7c 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/ComponentParameterField.tsx
@@ -34,9 +34,10 @@ import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefin
 import {ToDefinition} from "karavan-core/lib/model/CamelDefinition";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
+import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
 import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
@@ -206,7 +207,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -215,13 +216,14 @@ export class ComponentParameterField extends React.Component<Props, State> {
 
     getStringInput(property: ComponentProperty, value: any) {
         const {showEditor, showPassword} = this.state;
-        const inKubernetes = KubernetesAPI.inKubernetes;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return <InputGroup>
-            {inKubernetes && !showEditor && !noKubeSelectorButton &&
+            {inInfrastructure && !showEditor && !noInfraSelectorButton &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) &&
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
index fb81df12..e11ee485 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/DslPropertyField.tsx
@@ -60,13 +60,13 @@ import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import EditorIcon from "@patternfly/react-icons/dist/js/icons/code-icon";
 import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
 import {ModalEditor} from "./ModalEditor";
 import {KaravanInstance} from "../../KaravanDesigner";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 
 interface Props {
     property: PropertyMeta,
@@ -204,7 +204,7 @@ export class DslPropertyField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -213,13 +213,14 @@ export class DslPropertyField extends React.Component<Props, State> {
 
     getStringInput = (property: PropertyMeta, value: any) => {
         const showEditor = this.state.showEditor;
-        const inKubernetes = KubernetesAPI.inKubernetes;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return (<InputGroup>
-            {inKubernetes && !showEditor && !noKubeSelectorButton &&
+            {inInfrastructure && !showEditor && !noInfraSelectorButton &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) && <TextInput
diff --git a/karavan-designer/src/designer/route/property/KubernetesSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
similarity index 95%
rename from karavan-designer/src/designer/route/property/KubernetesSelector.tsx
rename to karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
index a6091575..04c8d43a 100644
--- a/karavan-designer/src/designer/route/property/KubernetesSelector.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/InfrastructureSelector.tsx
@@ -17,13 +17,13 @@
 import React from 'react';
 import {
     Badge,
-    Button, Flex, FlexItem,
+    Button, capitalize, 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 {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 
 interface Props {
     onSelect: (value: string) => void,
@@ -40,13 +40,13 @@ interface State {
     services:  string[]
 }
 
-export class KubernetesSelector extends React.Component<Props, State> {
+export class InfrastructureSelector extends React.Component<Props, State> {
 
     public state: State = {
         tabIndex: "configMap",
-        configMaps: KubernetesAPI.configMaps,
-        secrets: KubernetesAPI.secrets,
-        services: KubernetesAPI.services
+        configMaps: InfrastructureAPI.configMaps,
+        secrets: InfrastructureAPI.secrets,
+        services: InfrastructureAPI.services
     };
 
     selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
@@ -210,7 +210,7 @@ export class KubernetesSelector extends React.Component<Props, State> {
         const tabIndex = this.state.tabIndex;
         return (
             <Modal
-                aria-label="Select from Kubernetes"
+                aria-label="Select from Infrastructure"
                 width={'50%'}
                 className='dsl-modal'
                 isOpen={this.props.isOpen}
@@ -218,7 +218,7 @@ export class KubernetesSelector extends React.Component<Props, State> {
                 header={
                     <Flex direction={{default: "column"}}>
                         <FlexItem>
-                            <h3>{"Select from Kubernetes"}</h3>
+                            <h3>{"Select from " + capitalize(InfrastructureAPI.infrastructure)}</h3>
                             {this.searchInput()}
                         </FlexItem>
                         <FlexItem>
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
index cda5ac3f..8beed690 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KameletPropertyField.tsx
@@ -27,11 +27,12 @@ import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import {Property} from "karavan-core/lib/model/KameletModels";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
 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";
 
 interface Props {
     property: Property,
@@ -96,7 +97,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -108,13 +109,15 @@ export class KameletPropertyField extends React.Component<Props, State> {
         const {property, value} = this.props;
         const prefix = "parameters";
         const id = prefix + "-" + property.id;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.id);
-        const showKubeSelectorButton = KubernetesAPI.inKubernetes && !showEditor && !noKubeSelectorButton
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.id);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
+        const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton
         return <InputGroup>
-            {showKubeSelectorButton  &&
+            {showInfraSelectorButton  &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.format === "password") &&
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
index a6091575..b7997eda 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
@@ -23,7 +23,7 @@ import {
 } from '@patternfly/react-core';
 import '../../karavan.css';
 import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 
 interface Props {
     onSelect: (value: string) => void,
@@ -44,9 +44,9 @@ export class KubernetesSelector extends React.Component<Props, State> {
 
     public state: State = {
         tabIndex: "configMap",
-        configMaps: KubernetesAPI.configMaps,
-        secrets: KubernetesAPI.secrets,
-        services: KubernetesAPI.services
+        configMaps: InfrastructureAPI.configMaps,
+        secrets: InfrastructureAPI.secrets,
+        services: InfrastructureAPI.services
     };
 
     selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/utils/KubernetesAPI.ts b/karavan-cloud/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts
similarity index 77%
rename from karavan-cloud/karavan-app/src/main/webui/src/designer/utils/KubernetesAPI.ts
rename to karavan-cloud/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts
index 5168bc3c..8b182dc1 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/utils/KubernetesAPI.ts
+++ b/karavan-cloud/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts
@@ -1,6 +1,6 @@
-export class KubernetesAPI {
+export class InfrastructureAPI {
 
-    static inKubernetes: boolean = false;
+    static infrastructure: 'kubernetes' | 'docker' | 'local' = 'local';
     static configMaps: string[] = [];
     static secrets: string[] = [];
     static services: string[] = [];
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx b/karavan-designer/src/designer/beans/BeanProperties.tsx
index 78f475f4..b7ab5532 100644
--- a/karavan-designer/src/designer/beans/BeanProperties.tsx
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -34,11 +34,12 @@ import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import {IntegrationHeader} from "../utils/KaravanComponents";
 import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
-import {KubernetesSelector} from "../route/property/KubernetesSelector";
+import {InfrastructureSelector} from "../route/property/InfrastructureSelector";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
-import {KubernetesAPI} from "../utils/KubernetesAPI";
+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";
 
 
 interface Props {
@@ -137,7 +138,7 @@ export class BeanProperties extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -199,15 +200,17 @@ export class BeanProperties extends React.Component<Props, State> {
                         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" name="key" value={key}
                                            onChange={e => this.propertyChanged(i, e, value, showPassword)}/>
                                 <InputGroup>
-                                    {KubernetesAPI.inKubernetes &&
+                                    {inInfrastructure &&
                                         <Tooltip position="bottom-end" content="Select value from Kubernetes">
                                         <Button variant="control" onClick={e => this.openKubernetesSelector(i, key)}>
-                                            <KubernetesIcon/>
+                                            {icon}
                                         </Button>
                                     </Tooltip>}
                                     <TextInput
diff --git a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
index e9c6d02f..39817f7c 100644
--- a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
@@ -34,9 +34,10 @@ import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefin
 import {ToDefinition} from "karavan-core/lib/model/CamelDefinition";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
+import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
 import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
@@ -206,7 +207,7 @@ export class ComponentParameterField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -215,13 +216,14 @@ export class ComponentParameterField extends React.Component<Props, State> {
 
     getStringInput(property: ComponentProperty, value: any) {
         const {showEditor, showPassword} = this.state;
-        const inKubernetes = KubernetesAPI.inKubernetes;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return <InputGroup>
-            {inKubernetes && !showEditor && !noKubeSelectorButton &&
+            {inInfrastructure && !showEditor && !noInfraSelectorButton &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) &&
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index fb81df12..e11ee485 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
@@ -60,13 +60,13 @@ import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import EditorIcon from "@patternfly/react-icons/dist/js/icons/code-icon";
 import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
 import {ModalEditor} from "./ModalEditor";
 import {KaravanInstance} from "../../KaravanDesigner";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 
 interface Props {
     property: PropertyMeta,
@@ -204,7 +204,7 @@ export class DslPropertyField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -213,13 +213,14 @@ export class DslPropertyField extends React.Component<Props, State> {
 
     getStringInput = (property: PropertyMeta, value: any) => {
         const showEditor = this.state.showEditor;
-        const inKubernetes = KubernetesAPI.inKubernetes;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return (<InputGroup>
-            {inKubernetes && !showEditor && !noKubeSelectorButton &&
+            {inInfrastructure && !showEditor && !noInfraSelectorButton &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.name)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) && <TextInput
diff --git a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
similarity index 95%
copy from karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
copy to karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
index a6091575..04c8d43a 100644
--- a/karavan-cloud/karavan-app/src/main/webui/src/designer/route/property/KubernetesSelector.tsx
+++ b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
@@ -17,13 +17,13 @@
 import React from 'react';
 import {
     Badge,
-    Button, Flex, FlexItem,
+    Button, capitalize, 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 {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 
 interface Props {
     onSelect: (value: string) => void,
@@ -40,13 +40,13 @@ interface State {
     services:  string[]
 }
 
-export class KubernetesSelector extends React.Component<Props, State> {
+export class InfrastructureSelector extends React.Component<Props, State> {
 
     public state: State = {
         tabIndex: "configMap",
-        configMaps: KubernetesAPI.configMaps,
-        secrets: KubernetesAPI.secrets,
-        services: KubernetesAPI.services
+        configMaps: InfrastructureAPI.configMaps,
+        secrets: InfrastructureAPI.secrets,
+        services: InfrastructureAPI.services
     };
 
     selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
@@ -210,7 +210,7 @@ export class KubernetesSelector extends React.Component<Props, State> {
         const tabIndex = this.state.tabIndex;
         return (
             <Modal
-                aria-label="Select from Kubernetes"
+                aria-label="Select from Infrastructure"
                 width={'50%'}
                 className='dsl-modal'
                 isOpen={this.props.isOpen}
@@ -218,7 +218,7 @@ export class KubernetesSelector extends React.Component<Props, State> {
                 header={
                     <Flex direction={{default: "column"}}>
                         <FlexItem>
-                            <h3>{"Select from Kubernetes"}</h3>
+                            <h3>{"Select from " + capitalize(InfrastructureAPI.infrastructure)}</h3>
                             {this.searchInput()}
                         </FlexItem>
                         <FlexItem>
diff --git a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
index cda5ac3f..8beed690 100644
--- a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
@@ -27,11 +27,12 @@ import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 import ExpandIcon from "@patternfly/react-icons/dist/js/icons/expand-icon";
 import CompressIcon from "@patternfly/react-icons/dist/js/icons/compress-icon";
 import {Property} from "karavan-core/lib/model/KameletModels";
-import {KubernetesSelector} from "./KubernetesSelector";
-import {KubernetesAPI} from "../../utils/KubernetesAPI";
+import {InfrastructureSelector} from "./InfrastructureSelector";
+import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon";
 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";
 
 interface Props {
     property: Property,
@@ -96,7 +97,7 @@ export class KameletPropertyField extends React.Component<Props, State> {
 
     getKubernetesSelectorModal() {
         return (
-            <KubernetesSelector
+            <InfrastructureSelector
                 dark={false}
                 isOpen={this.state.showKubernetesSelector}
                 onClose={() => this.closeKubernetesSelector()}
@@ -108,13 +109,15 @@ export class KameletPropertyField extends React.Component<Props, State> {
         const {property, value} = this.props;
         const prefix = "parameters";
         const id = prefix + "-" + property.id;
-        const noKubeSelectorButton = ["uri", "id", "description", "group"].includes(property.id);
-        const showKubeSelectorButton = KubernetesAPI.inKubernetes && !showEditor && !noKubeSelectorButton
+        const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
+        const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.id);
+        const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
+        const showInfraSelectorButton = inInfrastructure && !showEditor && !noInfraSelectorButton
         return <InputGroup>
-            {showKubeSelectorButton  &&
+            {showInfraSelectorButton  &&
                 <Tooltip position="bottom-end" content="Select from Kubernetes">
                     <Button variant="control" onClick={e => this.openKubernetesSelector(property.id)}>
-                        <KubernetesIcon/>
+                        {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.format === "password") &&
diff --git a/karavan-designer/src/designer/utils/KubernetesAPI.ts b/karavan-designer/src/designer/utils/InfrastructureAPI.ts
similarity index 77%
rename from karavan-designer/src/designer/utils/KubernetesAPI.ts
rename to karavan-designer/src/designer/utils/InfrastructureAPI.ts
index 5168bc3c..8b182dc1 100644
--- a/karavan-designer/src/designer/utils/KubernetesAPI.ts
+++ b/karavan-designer/src/designer/utils/InfrastructureAPI.ts
@@ -1,6 +1,6 @@
-export class KubernetesAPI {
+export class InfrastructureAPI {
 
-    static inKubernetes: boolean = false;
+    static infrastructure: 'kubernetes' | 'docker' | 'local' = 'local';
     static configMaps: string[] = [];
     static secrets: string[] = [];
     static services: string[] = [];