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 b9985be44545422ab24fd62852f045fc9234e096
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Fri Sep 8 17:52:42 2023 -0400

    Run prod container for #817
---
 karavan-designer/src/designer/karavan.css          |   3 +-
 ...ructureResource.java => ContainerResource.java} | 190 +++------------------
 .../apache/camel/karavan/api/ImagesResource.java   |  15 ++
 .../camel/karavan/api/InfrastructureResource.java  | 154 +----------------
 .../camel/karavan/docker/DockerForKaravan.java     |  18 +-
 .../apache/camel/karavan/docker/DockerService.java |  46 +++--
 .../karavan/infinispan/model/ContainerStatus.java  |  33 ++++
 .../apache/camel/karavan/service/CamelService.java |  27 +--
 .../karavan/service/ContainerStatusService.java    |  56 ++++++
 .../camel/karavan/service/ProjectService.java      |   8 +
 .../camel/karavan/service/ScheduledService.java    | 100 -----------
 .../camel-main-docker-application.properties       |   3 +
 .../src/main/webui/src/api/KaravanApi.tsx          |  27 ++-
 .../src/main/webui/src/api/ProjectModels.ts        |   2 +-
 .../src/main/webui/src/project/BuildToolbar.tsx    |  84 ++++++++-
 .../webui/src/project/build/ProjectBuildTab.tsx    |   2 +-
 .../src/project/trace/RunnerInfoTraceModal.tsx     |   1 -
 17 files changed, 288 insertions(+), 481 deletions(-)

diff --git a/karavan-designer/src/designer/karavan.css 
b/karavan-designer/src/designer/karavan.css
index 11324971..bf4d9d49 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -38,7 +38,8 @@
     height: 36px;
 }
 
-.karavan .pf-v5-c-switch__input:focus ~ .pf-v5-c-switch__toggle {
+.karavan .pf-v5-c-switch__input:focus ~ .pf-v5-c-switch__toggle,
+.pf-v5-c-modal-box .pf-v5-c-switch__input:focus ~ .pf-v5-c-switch__toggle {
     outline: transparent;
     outline-offset: 0;
 }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
similarity index 52%
copy from 
karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
copy to 
karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
index f6408f84..8a237d20 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ContainerResource.java
@@ -20,26 +20,23 @@ import io.smallrye.mutiny.Multi;
 import io.vertx.core.json.JsonObject;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import io.vertx.mutiny.core.eventbus.Message;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
+import org.apache.camel.karavan.code.CodeService;
 import org.apache.camel.karavan.code.DockerComposeConverter;
+import org.apache.camel.karavan.code.model.DockerComposeService;
 import org.apache.camel.karavan.docker.DockerForKaravan;
 import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.code.model.DockerComposeService;
 import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.infinispan.model.ContainerStatus;
-import org.apache.camel.karavan.infinispan.model.DeploymentStatus;
-import org.apache.camel.karavan.infinispan.model.Project;
-import org.apache.camel.karavan.infinispan.model.ServiceStatus;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
-import org.apache.camel.karavan.code.CodeService;
-import org.apache.camel.karavan.service.ProjectService;
 import org.apache.camel.karavan.service.ConfigService;
+import org.apache.camel.karavan.service.ProjectService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
-import jakarta.inject.Inject;
-import jakarta.ws.rs.*;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
 import java.util.Comparator;
 import java.util.List;
 import java.util.Objects;
@@ -47,8 +44,8 @@ import java.util.stream.Collectors;
 
 import static 
org.apache.camel.karavan.service.ContainerStatusService.CONTAINER_STATUS;
 
-@Path("/api/infrastructure")
-public class InfrastructureResource {
+@Path("/api/container")
+public class ContainerResource {
 
     @Inject
     EventBus eventBus;
@@ -74,109 +71,10 @@ public class InfrastructureResource {
     @ConfigProperty(name = "karavan.environment")
     String environment;
 
-    private static final Logger LOGGER = 
Logger.getLogger(InfrastructureResource.class.getName());
-
-    @POST
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/{env}")
-    public String createPipeline(@PathParam("env") String env, Project 
project) throws Exception {
-        Project p = infinispanService.getProject(project.getProjectId());
-        return kubernetesService.createPipelineRun(project);
-    }
+    private static final Logger LOGGER = 
Logger.getLogger(ContainerResource.class.getName());
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/{env}/{name}")
-    public Response getPipeline(@PathParam("env") String env,
-                                @PathParam("name") String name) throws 
Exception {
-        return Response.ok(kubernetesService.getPipelineRun(name, 
kubernetesService.getNamespace())).build();
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/log/{env}/{name}")
-    public Response getPipelineLog(@PathParam("env") String env,
-                                   @PathParam("name") String name) throws 
Exception {
-        return Response.ok(kubernetesService.getPipelineRunLog(name, 
kubernetesService.getNamespace())).build();
-    }
-
-    @DELETE
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/pipelinerun/{env}/{name}")
-    public Response stopPipelineRun(@PathParam("env") String env, 
@PathParam("name") String name) throws Exception {
-        kubernetesService.stopPipelineRun(name, 
kubernetesService.getNamespace());
-        return Response.ok().build();
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/log/{env}/{name}")
-    public Response getContainerLog(@PathParam("env") String env,
-                                    @PathParam("name") String name) throws 
Exception {
-        return Response.ok(kubernetesService.getContainerLog(name, 
kubernetesService.getNamespace())).build();
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment")
-    public List<DeploymentStatus> getAllDeploymentStatuses() throws Exception {
-        if (infinispanService.isReady()) {
-            return infinispanService.getDeploymentStatuses().stream()
-                    
.sorted(Comparator.comparing(DeploymentStatus::getProjectId))
-                    .collect(Collectors.toList());
-        } else {
-            return List.of();
-        }
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment/{env}")
-    public List<DeploymentStatus> getDeploymentStatusesByEnv(@PathParam("env") 
String env) throws Exception {
-        if (infinispanService.isReady()) {
-        return infinispanService.getDeploymentStatuses(env).stream()
-                .sorted(Comparator.comparing(DeploymentStatus::getProjectId))
-                .collect(Collectors.toList());
-        } else {
-            return List.of();
-        }
-    }
-
-    @POST
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment/rollout/{env}/{name}")
-    public Response rollout(@PathParam("env") String env, @PathParam("name") 
String name) throws Exception {
-        kubernetesService.rolloutDeployment(name, 
kubernetesService.getNamespace());
-        return Response.ok().build();
-    }
-
-    @DELETE
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/deployment/{env}/{name}")
-    public Response deleteDeployment(@PathParam("env") String env, 
@PathParam("name") String name) throws Exception {
-        kubernetesService.deleteDeployment(name, 
kubernetesService.getNamespace());
-        return Response.ok().build();
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/service")
-    public List<ServiceStatus> getAllServiceStatuses() throws Exception {
-        if (infinispanService.isReady()) {
-            return infinispanService.getServiceStatuses().stream()
-                    .sorted(Comparator.comparing(ServiceStatus::getProjectId))
-                    .collect(Collectors.toList());
-        } else {
-            return List.of();
-        }
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container")
     public List<ContainerStatus> getAllContainerStatuses() throws Exception {
         if (infinispanService.isReady()) {
             return infinispanService.getContainerStatuses().stream()
@@ -190,7 +88,7 @@ public class InfrastructureResource {
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}/{type}/{name}")
+    @Path("/{env}/{type}/{name}")
     public Response manageContainer(@PathParam("env") String env, 
@PathParam("type") String type, @PathParam("name") String name, JsonObject 
command) throws Exception {
         if (infinispanService.isReady()) {
             // set container statuses
@@ -202,7 +100,13 @@ public class InfrastructureResource {
                         String code = projectService.getDevServiceCode();
                         DockerComposeService dockerComposeService = 
DockerComposeConverter.fromCode(code, name);
                         if (dockerComposeService != null) {
-                            
dockerForKaravan.createDevserviceContainer(dockerComposeService);
+                            
dockerService.createContainerFromCompose(dockerComposeService, 
ContainerStatus.ContainerType.devmode);
+                            
dockerService.runContainer(dockerComposeService.getContainer_name());
+                        }
+                    } else if (Objects.equals(type, 
ContainerStatus.ContainerType.project.name())) {
+                        DockerComposeService dockerComposeService = 
projectService.getProjectDockerComposeService(name);
+                        if (dockerComposeService != null) {
+                            
dockerService.createContainerFromCompose(dockerComposeService, 
ContainerStatus.ContainerType.project);
                             
dockerService.runContainer(dockerComposeService.getContainer_name());
                         }
                     } else if (Objects.equals(type, 
ContainerStatus.ContainerType.devmode.name())) {
@@ -217,6 +121,9 @@ public class InfrastructureResource {
                 } else if 
(command.getString("command").equalsIgnoreCase("pause")) {
                     dockerService.pauseContainer(name);
                     return Response.ok().build();
+                } else if 
(command.getString("command").equalsIgnoreCase("delete")) {
+                    dockerService.deleteContainer(name);
+                    return Response.ok().build();
                 }
             }
         }
@@ -234,7 +141,7 @@ public class InfrastructureResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}")
+    @Path("/{env}")
     public List<ContainerStatus> getContainerStatusesByEnv(@PathParam("env") 
String env) throws Exception {
         return infinispanService.getContainerStatuses(env).stream()
                 .sorted(Comparator.comparing(ContainerStatus::getProjectId))
@@ -243,7 +150,7 @@ public class InfrastructureResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/{projectId}/{env}")
+    @Path("/{projectId}/{env}")
     public List<ContainerStatus> 
getContainerStatusesByProjectAndEnv(@PathParam("projectId") String projectId, 
@PathParam("env") String env) throws Exception {
         return infinispanService.getContainerStatuses(projectId, env).stream()
                 .filter(podStatus -> Objects.equals(podStatus.getType(), 
ContainerStatus.ContainerType.project))
@@ -254,7 +161,7 @@ public class InfrastructureResource {
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}/{type}/{name}")
+    @Path("/{env}/{type}/{name}")
     public Response deleteContainer(@PathParam("env") String env, 
@PathParam("type") String type, @PathParam("name") String name) {
         if (infinispanService.isReady()) {
             // set container statuses
@@ -274,56 +181,9 @@ public class InfrastructureResource {
         return Response.notModified().build();
     }
 
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/imagetag/{env}/{projectId}")
-    public Response getProjectImageTags(@PathParam("env") String env, 
@PathParam("projectId") String projectId) throws Exception {
-        return Response.ok(kubernetesService.getProjectImageTags(projectId, 
kubernetesService.getNamespace())).build();
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/configmaps")
-    public Response getConfigMaps() throws Exception {
-        if (ConfigService.inKubernetes()) {
-            return 
Response.ok(kubernetesService.getConfigMaps(kubernetesService.getNamespace())).build();
-        } else {
-            return Response.ok(List.of()).build();
-        }
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/secrets")
-    public Response getSecrets() throws Exception {
-        if (ConfigService.inKubernetes()) {
-            return 
Response.ok(kubernetesService.getSecrets(kubernetesService.getNamespace())).build();
-        } else {
-            return Response.ok(List.of()).build();
-        }
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/services")
-    public Response getServices() throws Exception {
-        if (infinispanService.isReady()) {
-            if (ConfigService.inKubernetes()) {
-                return 
Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build();
-            } else {
-                List<String> list = 
infinispanService.getContainerStatuses(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();
-            }
-        } else {
-            return Response.ok(List.of()).build();
-        }
-    }
-
     // TODO: implement log watch
     @GET
-    @Path("/container/log/watch/{env}/{name}")
+    @Path("/log/watch/{env}/{name}")
     @Produces(MediaType.SERVER_SENT_EVENTS)
     public Multi<String> getContainerLogWatch(@PathParam("env") String env, 
@PathParam("name") String name) {
         LOGGER.info("Start sourcing");
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
index 9d4e0371..fe1a9f7a 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ImagesResource.java
@@ -23,9 +23,12 @@ import jakarta.ws.rs.core.MediaType;
 import jakarta.ws.rs.core.Response;
 import org.apache.camel.karavan.docker.DockerService;
 import org.apache.camel.karavan.infinispan.model.Project;
+import org.apache.camel.karavan.service.ConfigService;
 import org.apache.camel.karavan.service.ProjectService;
 import org.apache.camel.karavan.service.RegistryService;
 
+import java.net.URLDecoder;
+import java.nio.charset.StandardCharsets;
 import java.util.Comparator;
 import java.util.List;
 
@@ -65,4 +68,16 @@ public class ImagesResource {
             return Response.serverError().entity(e.getMessage()).build();
         }
     }
+
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/{imageName}")
+    public Response deleteImage(@HeaderParam("username") String username, 
@PathParam("imageName") String imageName) {
+        if (ConfigService.inKubernetes()) {
+            return Response.ok().build();
+        } else {
+            dockerService.deleteImage(imageName);
+            return Response.ok().build();
+        }
+    }
 }
\ No newline at end of file
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
index f6408f84..7c2a6b6a 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
@@ -16,61 +16,32 @@
  */
 package org.apache.camel.karavan.api;
 
-import io.smallrye.mutiny.Multi;
-import io.vertx.core.json.JsonObject;
-import io.vertx.mutiny.core.eventbus.EventBus;
-import io.vertx.mutiny.core.eventbus.Message;
-import org.apache.camel.karavan.code.DockerComposeConverter;
-import org.apache.camel.karavan.docker.DockerForKaravan;
-import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.code.model.DockerComposeService;
+import jakarta.inject.Inject;
+import jakarta.ws.rs.*;
+import jakarta.ws.rs.core.MediaType;
+import jakarta.ws.rs.core.Response;
 import org.apache.camel.karavan.infinispan.InfinispanService;
-import org.apache.camel.karavan.infinispan.model.ContainerStatus;
 import org.apache.camel.karavan.infinispan.model.DeploymentStatus;
 import org.apache.camel.karavan.infinispan.model.Project;
 import org.apache.camel.karavan.infinispan.model.ServiceStatus;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
-import org.apache.camel.karavan.code.CodeService;
-import org.apache.camel.karavan.service.ProjectService;
 import org.apache.camel.karavan.service.ConfigService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
-import jakarta.inject.Inject;
-import jakarta.ws.rs.*;
-import jakarta.ws.rs.core.MediaType;
-import jakarta.ws.rs.core.Response;
 import java.util.Comparator;
 import java.util.List;
-import java.util.Objects;
 import java.util.stream.Collectors;
 
-import static 
org.apache.camel.karavan.service.ContainerStatusService.CONTAINER_STATUS;
-
 @Path("/api/infrastructure")
 public class InfrastructureResource {
 
-    @Inject
-    EventBus eventBus;
-
     @Inject
     InfinispanService infinispanService;
 
     @Inject
     KubernetesService kubernetesService;
 
-    @Inject
-    DockerForKaravan dockerForKaravan;
-
-    @Inject
-    DockerService dockerService;
-
-    @Inject
-    ProjectService projectService;
-
-    @Inject
-    CodeService codeService;
-
     @ConfigProperty(name = "karavan.environment")
     String environment;
 
@@ -110,14 +81,6 @@ public class InfrastructureResource {
         return Response.ok().build();
     }
 
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/log/{env}/{name}")
-    public Response getContainerLog(@PathParam("env") String env,
-                                    @PathParam("name") String name) throws 
Exception {
-        return Response.ok(kubernetesService.getContainerLog(name, 
kubernetesService.getNamespace())).build();
-    }
-
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/deployment")
@@ -174,106 +137,6 @@ public class InfrastructureResource {
         }
     }
 
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container")
-    public List<ContainerStatus> getAllContainerStatuses() throws Exception {
-        if (infinispanService.isReady()) {
-            return infinispanService.getContainerStatuses().stream()
-                    
.sorted(Comparator.comparing(ContainerStatus::getProjectId))
-                    .collect(Collectors.toList());
-        } else {
-            return List.of();
-        }
-    }
-
-    @POST
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}/{type}/{name}")
-    public Response manageContainer(@PathParam("env") String env, 
@PathParam("type") String type, @PathParam("name") String name, JsonObject 
command) throws Exception {
-        if (infinispanService.isReady()) {
-            // set container statuses
-            setContainerStatusTransit(name, type);
-            // exec docker commands
-            if (command.containsKey("command")) {
-                if (command.getString("command").equalsIgnoreCase("run")) {
-                    if (Objects.equals(type, 
ContainerStatus.ContainerType.devservice.name())) {
-                        String code = projectService.getDevServiceCode();
-                        DockerComposeService dockerComposeService = 
DockerComposeConverter.fromCode(code, name);
-                        if (dockerComposeService != null) {
-                            
dockerForKaravan.createDevserviceContainer(dockerComposeService);
-                            
dockerService.runContainer(dockerComposeService.getContainer_name());
-                        }
-                    } else if (Objects.equals(type, 
ContainerStatus.ContainerType.devmode.name())) {
-//                        TODO: merge with DevMode service
-//                        dockerForKaravan.createDevmodeContainer(name, "");
-//                        dockerService.runContainer(name);
-                    }
-                    return Response.ok().build();
-                } else if 
(command.getString("command").equalsIgnoreCase("stop")) {
-                    dockerService.stopContainer(name);
-                    return Response.ok().build();
-                } else if 
(command.getString("command").equalsIgnoreCase("pause")) {
-                    dockerService.pauseContainer(name);
-                    return Response.ok().build();
-                }
-            }
-        }
-        return Response.notModified().build();
-    }
-
-    private void setContainerStatusTransit(String name, String type){
-        ContainerStatus status = infinispanService.getContainerStatus(name, 
environment, name);
-        if (status == null) {
-            status = ContainerStatus.createByType(name, environment, 
ContainerStatus.ContainerType.valueOf(type));
-        }
-        status.setInTransit(true);
-        eventBus.send(CONTAINER_STATUS, JsonObject.mapFrom(status));
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}")
-    public List<ContainerStatus> getContainerStatusesByEnv(@PathParam("env") 
String env) throws Exception {
-        return infinispanService.getContainerStatuses(env).stream()
-                .sorted(Comparator.comparing(ContainerStatus::getProjectId))
-                .collect(Collectors.toList());
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/{projectId}/{env}")
-    public List<ContainerStatus> 
getContainerStatusesByProjectAndEnv(@PathParam("projectId") String projectId, 
@PathParam("env") String env) throws Exception {
-        return infinispanService.getContainerStatuses(projectId, env).stream()
-                .filter(podStatus -> Objects.equals(podStatus.getType(), 
ContainerStatus.ContainerType.project))
-                
.sorted(Comparator.comparing(ContainerStatus::getContainerName))
-                .collect(Collectors.toList());
-    }
-
-    @DELETE
-    @Produces(MediaType.APPLICATION_JSON)
-    @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/container/{env}/{type}/{name}")
-    public Response deleteContainer(@PathParam("env") String env, 
@PathParam("type") String type, @PathParam("name") String name) {
-        if (infinispanService.isReady()) {
-            // set container statuses
-            setContainerStatusTransit(name, type);
-            try {
-                if (ConfigService.inKubernetes()) {
-                    kubernetesService.deletePod(name, 
kubernetesService.getNamespace());
-                } else {
-                    dockerService.deleteContainer(name);
-                }
-                return Response.accepted().build();
-            } catch (Exception e) {
-                LOGGER.error(e.getMessage());
-                return Response.notModified().build();
-            }
-        }
-        return Response.notModified().build();
-    }
-
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/imagetag/{env}/{projectId}")
@@ -320,13 +183,4 @@ public class InfrastructureResource {
             return Response.ok(List.of()).build();
         }
     }
-
-    // TODO: implement log watch
-    @GET
-    @Path("/container/log/watch/{env}/{name}")
-    @Produces(MediaType.SERVER_SENT_EVENTS)
-    public Multi<String> getContainerLogWatch(@PathParam("env") String env, 
@PathParam("name") String name) {
-        LOGGER.info("Start sourcing");
-        return eventBus.<String>consumer(name + "-" + 
kubernetesService.getNamespace()).toMulti().map(Message::body);
-    }
 }
\ No newline at end of file
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
index cfa74f84..41861af7 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerForKaravan.java
@@ -69,27 +69,23 @@ public class DockerForKaravan {
     }
 
     public void runBuildProject(String projectId, String script, Map<String, 
String> files, List<String> env,  Map<String, String> volumes, String tag) 
throws Exception {
-        dockerService.deleteContainer(projectId + BUILDER_SUFFIX);
-        Container c = createBuildContainer(projectId, env, volumes, tag);
+        String containerName = projectId + BUILDER_SUFFIX;
+        dockerService.deleteContainer(containerName);
+        Container c = createBuildContainer(containerName, projectId, env, 
volumes, tag);
         dockerService.copyFiles(c.getId(), "/code", files);
         dockerService.copyExecFile(c.getId(), "/karavan", "build.sh", script);
-        dockerService.runContainer(projectId);
+        dockerService.runContainer(c);
     }
 
-    protected Container createBuildContainer(String projectId, List<String> 
env, Map<String, String> volumes, String tag) throws InterruptedException {
-        LOGGER.infof("Starting Build Container for %s ", projectId);
+    protected Container createBuildContainer(String containerName, String 
projectId, List<String> env, Map<String, String> volumes, String tag) throws 
InterruptedException {
+        LOGGER.infof("Starting Build Container ", containerName);
 
-        return dockerService.createContainer(projectId + BUILDER_SUFFIX, 
devmodeImage,
+        return dockerService.createContainer(containerName, devmodeImage,
                 env, Map.of(), new HealthCheck(),
                 Map.of(LABEL_TYPE, ContainerStatus.ContainerType.build.name(), 
LABEL_PROJECT_ID, projectId, LABEL_TAG, tag),
                 volumes, null,"/karavan/build.sh");
     }
 
-    public void createDevserviceContainer(DockerComposeService 
dockerComposeService) throws InterruptedException {
-        LOGGER.infof("DevService starting for ", 
dockerComposeService.getContainer_name());
-        dockerService.createContainerFromCompose(dockerComposeService, 
ContainerStatus.ContainerType.devservice);
-    }
-
     public void syncImage(String projectId, String tag) throws 
InterruptedException {
         String image = registryService.getRegistryWithGroup() + "/" + 
projectId + ":" + tag;
         dockerService.pullImage(image);
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
index 0f680ad8..9d5ac75f 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/docker/DockerService.java
@@ -103,6 +103,7 @@ public class DockerService extends DockerServiceUtils {
     public void stopListeners() throws IOException {
         dockerEventListener.close();
     }
+
     public void createNetwork() {
         if (!getDockerClient().listNetworksCmd().exec().stream()
                 .filter(n -> n.getName().equals(NETWORK_NAME))
@@ -124,7 +125,7 @@ public class DockerService extends DockerServiceUtils {
     }
 
     public Container getContainerByName(String name) {
-        List<Container> containers = 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        List<Container> containers = findContainer(name);
         return containers.size() > 0 ? containers.get(0) : null;
     }
 
@@ -142,7 +143,7 @@ public class DockerService extends DockerServiceUtils {
     }
 
     public Container createContainerFromCompose(DockerComposeService compose, 
ContainerStatus.ContainerType type) throws InterruptedException {
-        List<Container> containers = 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(compose.getContainer_name())).exec();
+        List<Container> containers = 
findContainer(compose.getContainer_name());
         if (containers.isEmpty()) {
             LOGGER.infof("Compose Service starting for %s", 
compose.getContainer_name());
 
@@ -160,10 +161,15 @@ public class DockerService extends DockerServiceUtils {
         }
     }
 
+    public List<Container> findContainer(String containerName) {
+        return 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(containerName)).exec()
+                .stream().filter(c -> 
Objects.equals(c.getNames()[0].replaceFirst("/", ""), containerName)).toList();
+    }
+
     public Container createContainer(String name, String image, List<String> 
env, Map<Integer, Integer> ports,
                                      HealthCheck healthCheck, Map<String, 
String> labels,
                                      Map<String, String> volumes, String 
network, String... command) throws InterruptedException {
-        List<Container> containers = 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        List<Container> containers = findContainer(name);
         if (containers.size() == 0) {
             pullImage(image);
 
@@ -186,7 +192,7 @@ public class DockerService extends DockerServiceUtils {
             }
             createContainerCmd.withHostConfig(new HostConfig()
                     .withPortBindings(portBindings)
-                            .withMounts(mounts)
+                    .withMounts(mounts)
                     .withNetworkMode(network != null ? network : 
NETWORK_NAME));
 
             CreateContainerResponse response = createContainerCmd.exec();
@@ -200,14 +206,17 @@ public class DockerService extends DockerServiceUtils {
     }
 
     public void runContainer(String name) {
-        List<Container> containers = 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        List<Container> containers = findContainer(name);
         if (containers.size() == 1) {
-            Container container = containers.get(0);
-            if (container.getState().equals("paused")) {
-                
getDockerClient().unpauseContainerCmd(container.getId()).exec();
-            } else if (!container.getState().equals("running")) {
-                getDockerClient().startContainerCmd(container.getId()).exec();
-            }
+            runContainer(containers.get(0));
+        }
+    }
+
+    public void runContainer(Container container) {
+        if (container.getState().equals("paused")) {
+            getDockerClient().unpauseContainerCmd(container.getId()).exec();
+        } else if (!container.getState().equals("running")) {
+            getDockerClient().startContainerCmd(container.getId()).exec();
         }
     }
 
@@ -247,10 +256,10 @@ public class DockerService extends DockerServiceUtils {
     }
 
     public void copyFiles(String containerId, String containerPath, 
Map<String, String> files) {
-            String temp = 
vertx.fileSystem().createTempDirectoryBlocking(containerId);
-            files.forEach((fileName, code) -> addFile(temp, fileName, code));
-            
dockerClient.copyArchiveToContainerCmd(containerId).withRemotePath(containerPath)
-                    .withDirChildrenOnly(true).withHostResource(temp).exec();
+        String temp = 
vertx.fileSystem().createTempDirectoryBlocking(containerId);
+        files.forEach((fileName, code) -> addFile(temp, fileName, code));
+        
dockerClient.copyArchiveToContainerCmd(containerId).withRemotePath(containerPath)
+                .withDirChildrenOnly(true).withHostResource(temp).exec();
     }
 
     public void copyExecFile(String containerId, String containerPath, String 
filename, String script) {
@@ -259,7 +268,7 @@ public class DockerService extends DockerServiceUtils {
         vertx.fileSystem().writeFileBlocking(path, Buffer.buffer(script));
 
         try (ByteArrayOutputStream byteArrayOutputStream = new 
ByteArrayOutputStream();
-                TarArchiveOutputStream tarArchive = new 
TarArchiveOutputStream(byteArrayOutputStream)) {
+             TarArchiveOutputStream tarArchive = new 
TarArchiveOutputStream(byteArrayOutputStream)) {
             tarArchive.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);
             
tarArchive.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);
 
@@ -328,7 +337,7 @@ public class DockerService extends DockerServiceUtils {
     }
 
     public void deleteContainer(String name) {
-        List<Container> containers = 
getDockerClient().listContainersCmd().withShowAll(true).withNameFilter(List.of(name)).exec();
+        List<Container> containers = findContainer(name);
         if (containers.size() == 1) {
             Container container = containers.get(0);
             
getDockerClient().removeContainerCmd(container.getId()).withForce(true).exec();
@@ -382,4 +391,7 @@ public class DockerService extends DockerServiceUtils {
         return 
getDockerClient().listImagesCmd().withShowAll(true).exec().stream()
                 .map(image -> image.getRepoTags()[0]).toList();
     }
+
+    public void deleteImage(String imageName) {
+    }
 }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
index ab7c04b8..e734abc4 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/ContainerStatus.java
@@ -4,6 +4,7 @@ import org.infinispan.protostream.annotations.ProtoEnumValue;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
+import java.time.Instant;
 import java.util.ArrayList;
 import java.util.List;
 
@@ -65,8 +66,29 @@ public class ContainerStatus {
     Boolean codeLoaded;
     @ProtoField(number = 15)
     Boolean inTransit = false;
+    @ProtoField(number = 16)
+    String initDate;
 
     @ProtoFactory
+    public ContainerStatus(String projectId, String containerName, String 
containerId, String image, List<Integer> ports, String env, ContainerType type, 
String memoryInfo, String cpuInfo, String created, String finished, 
List<Command> commands, String state, Boolean codeLoaded, Boolean inTransit, 
String initDate) {
+        this.projectId = projectId;
+        this.containerName = containerName;
+        this.containerId = containerId;
+        this.image = image;
+        this.ports = ports;
+        this.env = env;
+        this.type = type;
+        this.memoryInfo = memoryInfo;
+        this.cpuInfo = cpuInfo;
+        this.created = created;
+        this.finished = finished;
+        this.commands = commands;
+        this.state = state;
+        this.codeLoaded = codeLoaded;
+        this.inTransit = inTransit;
+        this.initDate = initDate;
+    }
+
     public ContainerStatus(String projectId, String containerName, String 
containerId, String image, List<Integer> ports, String env, ContainerType type, 
String memoryInfo, String cpuInfo, String created, String finished, 
List<Command> commands, String state, Boolean codeLoaded, Boolean inTransit) {
         this.projectId = projectId;
         this.containerName = containerName;
@@ -83,6 +105,7 @@ public class ContainerStatus {
         this.state = state;
         this.codeLoaded = codeLoaded;
         this.inTransit = inTransit;
+        this.initDate = Instant.now().toString();
     }
 
     public ContainerStatus(String containerName, List<Command> commands, 
String projectId, String env, ContainerType type, String memoryInfo, String 
cpuInfo, String created) {
@@ -94,6 +117,7 @@ public class ContainerStatus {
         this.memoryInfo = memoryInfo;
         this.cpuInfo = cpuInfo;
         this.created = created;
+        this.initDate = Instant.now().toString();
     }
 
     public ContainerStatus(String containerName, List<Command> commands, 
String projectId, String env, ContainerType type, String created) {
@@ -103,6 +127,7 @@ public class ContainerStatus {
         this.env = env;
         this.created = created;
         this.type = type;
+        this.initDate = Instant.now().toString();
     }
 
     public static ContainerStatus createDevMode(String projectId, String env) {
@@ -242,6 +267,14 @@ public class ContainerStatus {
         this.finished = finished;
     }
 
+    public String getInitDate() {
+        return initDate;
+    }
+
+    public void setInitDate(String initDate) {
+        this.initDate = initDate;
+    }
+
     @Override
     public String toString() {
         return "ContainerStatus{" +
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
index 7f054871..8bc62635 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/CamelService.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.karavan.service;
 
+import io.quarkus.scheduler.Scheduled;
 import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.core.json.JsonObject;
 import io.vertx.mutiny.core.Vertx;
@@ -70,6 +71,19 @@ public class CamelService {
         return webClient;
     }
 
+    @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution 
= Scheduled.ConcurrentExecution.SKIP)
+    public void collectCamelStatuses() {
+        if (infinispanService.isReady()) {
+            infinispanService.getContainerStatuses(environment).stream()
+                    .filter(cs ->
+                            cs.getType() == 
ContainerStatus.ContainerType.project
+                                    || cs.getType() == 
ContainerStatus.ContainerType.devmode
+                    ).forEach(pod -> {
+                        CamelStatusRequest csr = new 
CamelStatusRequest(pod.getProjectId(), pod.getContainerName());
+                        eventBus.publish(CMD_COLLECT_CAMEL_STATUS, 
JsonObject.mapFrom(csr));
+                    });
+        }
+    }
 
     private boolean camelIsStarted(CamelStatus camelStatus) {
         try {
@@ -129,19 +143,6 @@ public class CamelService {
         }
     }
 
-    public void collectCamelStatuses() {
-        if (infinispanService.isReady()) {
-            infinispanService.getContainerStatuses(environment).stream()
-                    .filter(cs ->
-                            cs.getType() == 
ContainerStatus.ContainerType.project
-                            || cs.getType() == 
ContainerStatus.ContainerType.devmode
-                    ).forEach(pod -> {
-                CamelStatusRequest csr = new 
CamelStatusRequest(pod.getProjectId(), pod.getContainerName());
-                eventBus.publish(CMD_COLLECT_CAMEL_STATUS, 
JsonObject.mapFrom(csr));
-            });
-        }
-    }
-
     @ConsumeEvent(value = CMD_COLLECT_CAMEL_STATUS, blocking = true, ordered = 
true)
     public void collectCamelStatuses(JsonObject data) {
         CamelStatusRequest dms = data.mapTo(CamelStatusRequest.class);
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
index 5fc126eb..c3b310bc 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ContainerStatusService.java
@@ -1,14 +1,20 @@
 package org.apache.camel.karavan.service;
 
+import io.quarkus.scheduler.Scheduled;
 import io.quarkus.vertx.ConsumeEvent;
+import io.vertx.core.eventbus.EventBus;
 import io.vertx.core.json.JsonObject;
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
+import org.apache.camel.karavan.docker.DockerService;
 import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.infinispan.model.ContainerStatus;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.List;
 import java.util.Objects;
 
 @ApplicationScoped
@@ -16,10 +22,60 @@ public class ContainerStatusService {
 
     public static final String CONTAINER_STATUS = "CONTAINER_STATUS";
     private static final Logger LOGGER = 
Logger.getLogger(ContainerStatusService.class.getName());
+    @ConfigProperty(name = "karavan.environment")
+    String environment;
 
     @Inject
     InfinispanService infinispanService;
 
+    @Inject
+    DockerService dockerService;
+
+    @Inject
+    EventBus eventBus;
+
+    @Scheduled(every = "{karavan.container.statistics.interval}", 
concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+    void collectContainersStatistics() {
+        if (infinispanService.isReady()) {
+            List<ContainerStatus> statusesInDocker = 
dockerService.collectContainersStatistics();
+            statusesInDocker.forEach(containerStatus -> {
+                eventBus.send(ContainerStatusService.CONTAINER_STATUS, 
JsonObject.mapFrom(containerStatus));
+            });
+        }
+    }
+
+    @Scheduled(every = "{karavan.container.status.interval}", 
concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
+    void collectContainersStatuses() {
+        if (infinispanService.isReady()) {
+            List<ContainerStatus> statusesInDocker = 
dockerService.collectContainersStatuses();
+            statusesInDocker.forEach(containerStatus -> {
+                eventBus.send(ContainerStatusService.CONTAINER_STATUS, 
JsonObject.mapFrom(containerStatus));
+            });
+            cleanContainersStatuses(statusesInDocker);
+        }
+    }
+
+    void cleanContainersStatuses(List<ContainerStatus> statusesInDocker) {
+        if (infinispanService.isReady()) {
+            List<String> namesInDocker = 
statusesInDocker.stream().map(ContainerStatus::getContainerName).toList();
+            List<ContainerStatus> statusesInInfinispan = 
infinispanService.getContainerStatuses(environment);
+            // clean deleted
+            statusesInInfinispan.stream()
+                    .filter(cs -> !checkTransit(cs))
+                    .filter(cs -> 
!namesInDocker.contains(cs.getContainerName()))
+                    .forEach(containerStatus -> {
+                        
infinispanService.deleteContainerStatus(containerStatus);
+                        
infinispanService.deleteCamelStatuses(containerStatus.getProjectId(), 
containerStatus.getEnv());
+                    });
+        }
+    }
+
+    private boolean checkTransit(ContainerStatus cs) {
+        if (cs.getContainerId() == null && cs.getInTransit()) {
+            return Instant.parse(cs.getInitDate()).until(Instant.now(), 
ChronoUnit.SECONDS) < 10;
+        }
+        return false;
+    }
 
     @ConsumeEvent(value = CONTAINER_STATUS, blocking = true, ordered = true)
     public void saveContainerStatus(JsonObject data) {
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
index 5ce1e34f..ebd49e08 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ProjectService.java
@@ -387,4 +387,12 @@ public class ProjectService implements HealthCheck {
             }
         }
     }
+
+    public DockerComposeService getProjectDockerComposeService(String 
projectId) {
+        ProjectFile file = infinispanService.getProjectFile(projectId, 
PROJECT_COMPOSE_FILENAME);
+        if (file != null) {
+            return DockerComposeConverter.fromCode(file.getCode(), projectId);
+        }
+        return null;
+    }
 }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
deleted file mode 100644
index 1a90dc6c..00000000
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/service/ScheduledService.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.apache.camel.karavan.service;
-
-import io.quarkus.scheduler.Scheduled;
-import io.vertx.core.eventbus.EventBus;
-import io.vertx.core.json.JsonObject;
-import org.apache.camel.karavan.docker.DockerForInfinispan;
-import org.apache.camel.karavan.docker.DockerService;
-import org.apache.camel.karavan.infinispan.InfinispanService;
-import org.apache.camel.karavan.infinispan.model.ContainerStatus;
-import org.eclipse.microprofile.config.inject.ConfigProperty;
-import org.jboss.logging.Logger;
-
-import jakarta.enterprise.context.ApplicationScoped;
-import jakarta.inject.Inject;
-import java.util.List;
-
-@ApplicationScoped
-public class ScheduledService {
-
-    private static final Logger LOGGER = 
Logger.getLogger(ScheduledService.class.getName());
-
-    @ConfigProperty(name = "karavan.environment")
-    String environment;
-
-    @Inject
-    DockerService dockerService;
-
-    @Inject
-    DockerForInfinispan dockerForInfinispan;
-
-    @Inject
-    ProjectService projectService;
-
-    @Inject
-    CamelService camelService;
-
-    @Inject
-    InfinispanService infinispanService;
-
-    @Inject
-    EventBus eventBus;
-
-    @Scheduled(every = "{karavan.container.statistics.interval}", 
concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
-    void collectContainersStatistics() {
-        if (infinispanService.isReady()) {
-            List<ContainerStatus> statusesInDocker = 
dockerService.collectContainersStatistics();
-            statusesInDocker.forEach(containerStatus -> {
-                eventBus.send(ContainerStatusService.CONTAINER_STATUS, 
JsonObject.mapFrom(containerStatus));
-            });
-        }
-    }
-
-    @Scheduled(every = "{karavan.container.status.interval}", 
concurrentExecution = Scheduled.ConcurrentExecution.SKIP)
-    void collectContainersStatuses() {
-        if (infinispanService.isReady()) {
-            List<ContainerStatus> statusesInDocker = 
dockerService.collectContainersStatuses();
-            statusesInDocker.forEach(containerStatus -> {
-                eventBus.send(ContainerStatusService.CONTAINER_STATUS, 
JsonObject.mapFrom(containerStatus));
-            });
-            cleanContainersStatuses(statusesInDocker);
-        }
-    }
-
-    void cleanContainersStatuses(List<ContainerStatus> statusesInDocker) {
-        if (infinispanService.isReady()) {
-            List<String> namesInDocker = 
statusesInDocker.stream().map(ContainerStatus::getContainerName).toList();
-            List<ContainerStatus> statusesInInfinispan = 
infinispanService.getContainerStatuses(environment);
-            // clean deleted
-            statusesInInfinispan.stream()
-                    .filter(cs -> !(cs.getContainerId() == null && 
cs.getInTransit()))
-                    .filter(cs -> 
!namesInDocker.contains(cs.getContainerName()))
-                    .forEach(containerStatus -> {
-                        
infinispanService.deleteContainerStatus(containerStatus);
-                        
infinispanService.deleteCamelStatuses(containerStatus.getProjectId(), 
containerStatus.getEnv());
-                    });
-        }
-    }
-
-
-    @Scheduled(every = "{karavan.camel.status.interval}", concurrentExecution 
= Scheduled.ConcurrentExecution.SKIP)
-    void collectCamelStatuses() {
-        camelService.collectCamelStatuses();
-    }
-}
diff --git 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
index 5048638c..2ce5adb2 100644
--- 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
+++ 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-docker-application.properties
@@ -5,6 +5,9 @@ camel.jbang.gav=org.camel.karavan.demo:{projectId}:1
 camel.jbang.runtime=camel-main
 camel.jbang.version=4.0.0-RC2
 camel.jbang.dependencies=camel-console,camel-platform-http-main
+camel.context.dev-console=true
+camel.main.backlogTracing=true
+camel.main.beanIntrospectionExtendedStatistics=true
 camel.health.enabled=true
 camel.health.exposure-level=full
 camel.server.enabled=true
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx 
b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index d6bcfcd2..fd66d5cd 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -412,7 +412,7 @@ export class KaravanApi {
     }
 
     static async getContainerLog(environment: string, name: string, after: 
(res: AxiosResponse<string>) => void) {
-        instance.get('/api/infrastructure/container/log/' + environment + "/" 
+ name)
+        instance.get('/api/container/log/' + environment + "/" + name)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -434,7 +434,7 @@ export class KaravanApi {
     }
 
     static async getAllContainerStatuses(after: (statuses: ContainerStatus[]) 
=> void) {
-        instance.get('/api/infrastructure/container')
+        instance.get('/api/container')
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -484,19 +484,12 @@ export class KaravanApi {
         });
     }
 
-    static async getProjectPodStatuses(project: string, env: string, after: 
(statuses: ContainerStatus[]) => void) {
-        instance.get('/api/infrastructure/container/' + project + "/" + env)
-            .then(res => {
-                if (res.status === 200) {
-                    after(res.data);
-                }
-            }).catch(err => {
-            console.log(err);
-        });
-    }
-
-    static async manageContainer(environment: string, type: 'devmove' | 
'devservice' | 'project' | 'internal' | 'unknown',  name: string, command: 
'run' | 'pause' | 'stop', after: (res: AxiosResponse<any>) => void) {
-        instance.post('/api/infrastructure/container/' + environment + '/' + 
type + "/" + name, {command: command})
+    static async manageContainer(environment: string,
+                                 type: 'devmove' | 'devservice' | 'project' | 
'internal' | 'build' | 'unknown',
+                                 name: string,
+                                 command: 'run' | 'pause' | 'stop' | 'delete',
+                                 after: (res: AxiosResponse<any>) => void) {
+        instance.post('/api/container/' + environment + '/' + type + "/" + 
name, {command: command})
             .then(res => {
                 after(res);
             }).catch(err => {
@@ -504,8 +497,8 @@ export class KaravanApi {
         });
     }
 
-    static async deleteContainer(environment: string, type: 'devmove' | 
'devservice' | 'project' | 'internal' | 'unknown', name: string, after: (res: 
AxiosResponse<any>) => void) {
-        instance.delete('/api/infrastructure/container/' + environment + '/' + 
type + "/" + name)
+    static async deleteContainer(environment: string, type: 'devmove' | 
'devservice' | 'project' | 'internal' | 'build' | 'unknown', name: string, 
after: (res: AxiosResponse<any>) => void) {
+        instance.delete('/api/container/' + environment + '/' + type + "/" + 
name)
             .then(res => {
                 after(res);
             }).catch(err => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts 
b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
index 460690b7..8dd5e485 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectModels.ts
@@ -73,7 +73,7 @@ export class ContainerStatus {
     deployment: string = '';
     projectId: string = '';
     env: string = '';
-    type: 'devmove' | 'devservice' | 'project' | 'internal' | 'unknown' = 
'unknown';
+    type: 'devmove' | 'devservice' | 'project' | 'internal' | 'build' | 
'unknown' = 'unknown';
     memoryInfo: string = '';
     cpuInfo: string = '';
     created: string = '';
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/BuildToolbar.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/BuildToolbar.tsx
index 1fa7a8f0..e18284c5 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/BuildToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/BuildToolbar.tsx
@@ -1,9 +1,18 @@
 import React from 'react';
-import {Button, Flex, FlexItem} from '@patternfly/react-core';
+import {Button, Flex, FlexItem, Label, Spinner, Tooltip, TooltipPosition} from 
'@patternfly/react-core';
 import '../designer/karavan.css';
 import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/trash-icon";
-import {useAppConfigStore} from "../api/ProjectStore";
+import {useAppConfigStore, useDevModeStore, useLogStore, useProjectStore, 
useStatusesStore} from "../api/ProjectStore";
 import {shallow} from "zustand/shallow";
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import DownIcon from 
"@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import RunIcon from "@patternfly/react-icons/dist/esm/icons/play-icon";
+import {ProjectService} from "../api/ProjectService";
+import ReloadIcon from "@patternfly/react-icons/dist/esm/icons/bolt-icon";
+import {KaravanApi} from "../api/KaravanApi";
+import {ProjectEventBus} from "../api/ProjectEventBus";
+import {EventBus} from "../designer/utils/EventBus";
+import StopIcon from "@patternfly/react-icons/dist/js/icons/stop-icon";
 
 interface Props {
     reloadOnly?: boolean
@@ -12,11 +21,78 @@ interface Props {
 export function BuildToolbar (props: Props) {
 
     const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const [status] = useDevModeStore((state) => [state.status], shallow)
+    const [project] = useProjectStore((state) => [state.project], shallow)
+    const [containers] = useStatusesStore((state) => [state.containers], 
shallow);
+    const [setShowLog] = useLogStore((s) => [s.setShowLog], shallow);
+
+    const containerStatus = containers.filter(c => c.containerName === 
project.projectId).at(0);
+    const commands = containerStatus?.commands || ['run'];
+    const isRunning = containerStatus?.state === 'running';
+    const inTransit = containerStatus?.inTransit;
+    const isLoading = status === 'wip';
+    const color = containerStatus?.state === 'running' ? "green" : "grey";
+    const icon = isRunning ? <UpIcon/> : <DownIcon/>;
 
     return (<Flex className="toolbar" direction={{default: "row"}} 
alignItems={{default: "alignItemsCenter"}}>
         <FlexItem>
-                <Button style={{visibility:"hidden"}} size="sm" 
variant={"control"} icon={<DeleteIcon/>} onClick={() => {}}>
+            {(inTransit || isLoading) && <Spinner size="lg" 
aria-label="spinner"/>}
+        </FlexItem>
+        {containerStatus?.containerId && <FlexItem>
+            <Label icon={icon} color={color}>
+                <Tooltip content={"Show log"} 
position={TooltipPosition.bottom}>
+                    <Button className='labeled-button' variant="link" 
isDisabled={!isRunning}
+                            onClick={e =>
+                                setShowLog(true, 'container', 
containerStatus.containerName)}>
+                        {containerStatus.containerName}
+                    </Button>
+                </Tooltip>
+            </Label>
+        </FlexItem>}
+        {!isRunning && <FlexItem>
+            <Tooltip content="Run container" position={TooltipPosition.bottom}>
+                <Button size="sm"
+                        isDisabled={(!(commands.length === 0) && 
!commands.includes('run')) || inTransit}
+                        variant={"primary"}
+                        icon={<RunIcon/>}
+                        onClick={() => {
+                            KaravanApi.manageContainer('dev', 'project', 
project.projectId, 'run', res => {
+                                setShowLog(false, 'container', undefined)
+                            });
+                        }}>
+                    {"Run"}
                 </Button>
+            </Tooltip>
+        </FlexItem>}
+        {config.infrastructure !== 'kubernetes' &&
+            <FlexItem>
+                <Tooltip content="Stop container" 
position={TooltipPosition.bottom}>
+                    <Button size="sm"
+                            isDisabled={!commands.includes('stop') || 
inTransit}
+                            variant={"control"}
+                            icon={<StopIcon/>}
+                            onClick={() => {
+                                KaravanApi.manageContainer('dev', 'project', 
project.projectId, 'stop', res => {
+                                    setShowLog(false, 'container', undefined)
+                                });
+                            }}>
+                    </Button>
+                </Tooltip>
+            </FlexItem>
+        }
+        <FlexItem>
+            <Tooltip content="Delete container" 
position={TooltipPosition.bottom}>
+                <Button size="sm"
+                        isDisabled={!commands.includes('delete') || inTransit}
+                        variant={"control"}
+                        icon={<DeleteIcon/>}
+                        onClick={() => {
+                            KaravanApi.manageContainer('dev', 'project', 
project.projectId, 'delete', res => {
+                                setShowLog(false, 'container', undefined)
+                            });
+                        }}>
+                </Button>
+            </Tooltip>
         </FlexItem>
     </Flex>);
-}
+}
\ No newline at end of file
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx
index 6c916da4..e761bbcb 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/build/ProjectBuildTab.tsx
@@ -14,7 +14,7 @@ export function ProjectBuildTab () {
             <div>
                 {/*{["dev", "test", "prod"].map(env =>*/}
                 {config.environments.map(env =>
-                    <BuildPanel env={env}/>
+                    <BuildPanel key={env} env={env}/>
                 )}
             </div>
         </PageSection>
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
 
b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
index 6a2b9986..af950b60 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
@@ -42,7 +42,6 @@ export function RunnerInfoTraceModal (props: Props) {
         return Array.from(new Set((props.nodes).map((item: any) => 
item?.routeId)));
     }
 
-    console.log(props.nodes)
     return (
         <Modal
             title={"Exchange: " + props.exchangeId}

Reply via email to