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 681572a62e247e44929dd56cb34bf1ec1ba24d43
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Sep 12 20:42:09 2023 -0400

    Camel statuses for #885
---
 .../apache/camel/karavan/api/DevModeResource.java  |  16 --
 .../apache/camel/karavan/api/ProjectResource.java  |  39 ++++-
 .../apache/camel/karavan/api/StatusResource.java   |  18 +--
 .../org/apache/camel/karavan/git/GitService.java   |   3 +-
 .../karavan/infinispan/InfinispanService.java      |  27 ++--
 .../karavan/infinispan/model/CamelStatus.java      |  43 ++----
 .../{CamelStatus.java => CamelStatusValue.java}    |  40 +----
 .../karavan/infinispan/model/ContainerStatus.java  |  33 ++++-
 .../karavan/infinispan/model/KaravanSchema.java    |   3 +-
 .../karavan/kubernetes/KubernetesService.java      |  67 ++-------
 .../camel/karavan/kubernetes/PodEventHandler.java  |   1 +
 .../apache/camel/karavan/service/CamelService.java |  69 ++++-----
 .../camel-main-docker-application.properties       |   7 +-
 .../camel-main-kubernetes-application.properties   |   2 +
 .../camel-main-openshift-application.properties    |   2 +
 .../src/main/webui/src/api/KaravanApi.tsx          |  17 ++-
 .../src/main/webui/src/api/ProjectModels.ts        |   6 +-
 .../src/main/webui/src/api/ProjectStore.ts         |  40 +++--
 .../webui/src/containers/ContainerTableRow.tsx     |   5 +-
 .../karavan-app/src/main/webui/src/main/Main.tsx   |   1 -
 .../src/main/webui/src/main/MainDataPoller.tsx     |   2 +-
 .../main/webui/src/project/ProjectDataPoller.tsx   |  33 ++---
 .../src/main/webui/src/project/ProjectPage.tsx     |   2 +
 .../src/main/webui/src/project/ProjectPanel.tsx    |  24 ++-
 .../webui/src/project/dashboard/DashboardTab.tsx   |  73 +++++----
 .../webui/src/project/dashboard/InfoContainer.tsx  |  10 +-
 .../webui/src/project/dashboard/InfoContext.tsx    |  37 +++--
 .../webui/src/project/dashboard/InfoMemory.tsx     |  35 +++--
 .../src/main/webui/src/project/files/FilesTab.tsx  | 120 +++++++--------
 .../src/main/webui/src/project/trace/TraceTab.tsx  | 163 +++++++++------------
 .../project/trace/{TraceTab.tsx => TraceTable.tsx} |  41 +++---
 .../src/main/webui/src/projects/ProjectsPage.tsx   |   2 -
 .../src/main/webui/src/templates/TemplatesPage.tsx |   2 +-
 .../camel/karavan/infinispan/DataGridTest.java     |   8 +-
 34 files changed, 477 insertions(+), 514 deletions(-)

diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
index 9a49d65b..2b73642a 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/DevModeResource.java
@@ -133,20 +133,4 @@ public class DevModeResource {
             return Response.noContent().build();
         }
     }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/status/{projectId}/{statusName}")
-    public Response getCamelStatusByProjectAndEnv(@PathParam("projectId") 
String projectId, @PathParam("statusName") String statusName) {
-        if (infinispanService.isReady()) {
-            CamelStatus status = infinispanService.getCamelStatus(projectId, 
environment, statusName);
-            if (status != null) {
-                return Response.ok(status).build();
-            } else {
-                return Response.noContent().build();
-            }
-        } else {
-            return Response.noContent().build();
-        }
-    }
 }
\ No newline at end of file
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
index fc9cd54f..4217e0f4 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/ProjectResource.java
@@ -19,9 +19,7 @@ package org.apache.camel.karavan.api;
 import jakarta.ws.rs.core.Response;
 import org.apache.camel.karavan.docker.DockerService;
 import org.apache.camel.karavan.infinispan.InfinispanService;
-import org.apache.camel.karavan.infinispan.model.GroupedKey;
-import org.apache.camel.karavan.infinispan.model.Project;
-import org.apache.camel.karavan.infinispan.model.ProjectFile;
+import org.apache.camel.karavan.infinispan.model.*;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
 import org.apache.camel.karavan.git.GitService;
 import jakarta.inject.Inject;
@@ -35,6 +33,7 @@ import java.net.URLDecoder;
 import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.stream.Collectors;
 
 @Path("/api/project")
@@ -117,6 +116,40 @@ public class ProjectResource {
         }
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/status/camel/{projectId}/{env}")
+    public Response getCamelStatusForProjectAndEnv(@PathParam("projectId") 
String projectId, @PathParam("env") String env) {
+        List<CamelStatus> statuses = 
infinispanService.getCamelStatusesByProjectAndEnv(projectId, env)
+                .stream().map(camelStatus -> {
+                    var stats = camelStatus.getStatuses().stream().filter(s -> 
!Objects.equals(s.getName(), CamelStatusValue.Name.trace)).toList();
+                    camelStatus.setStatuses(stats);
+                    return camelStatus;
+                }).toList();
+        if (statuses != null && !statuses.isEmpty()) {
+            return Response.ok(statuses).build();
+        } else {
+            return Response.noContent().build();
+        }
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/traces/{projectId}/{env}")
+    public Response getCamelTracesForProjectAndEnv(@PathParam("projectId") 
String projectId, @PathParam("env") String env) {
+        List<CamelStatus> statuses = 
infinispanService.getCamelStatusesByProjectAndEnv(projectId, env)
+                .stream().map(camelStatus -> {
+                    var stats = camelStatus.getStatuses().stream().filter(s -> 
Objects.equals(s.getName(), CamelStatusValue.Name.trace)).toList();
+                    camelStatus.setStatuses(stats);
+                    return camelStatus;
+                }).toList();
+        if (statuses != null && !statuses.isEmpty()) {
+            return Response.ok(statuses).build();
+        } else {
+            return Response.noContent().build();
+        }
+    }
+
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
index 0e3fdd8a..97710ad1 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
@@ -52,22 +52,10 @@ public class StatusResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/camel/{projectId}/{env}")
-    public Response getCamelStatusByProjectAndEnv(@PathParam("projectId") 
String projectId, @PathParam("env") String env) {
-        CamelStatus status = infinispanService.getCamelStatus(projectId, env, 
CamelStatus.Name.context.name());
-        if (status != null) {
-            return Response.ok(status).build();
-        } else {
-            return Response.noContent().build();
-        }
-    }
-
-    @GET
-    @Produces(MediaType.APPLICATION_JSON)
-    @Path("/camel/{env}")
-    public List<CamelStatus> getCamelStatusByEnv(@PathParam("env") String env) 
{
+    @Path("/camel/context/{env}")
+    public List<CamelStatus> getCamelContextStatusByEnv(@PathParam("env") 
String env) {
         if (infinispanService.isReady()) {
-            return infinispanService.getCamelStatusesByEnv(env, 
CamelStatus.Name.context);
+            return infinispanService.getCamelStatusesByEnv(env, 
CamelStatusValue.Name.context);
         } else {
             return List.of();
         }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
index c81c40e7..99cb38ff 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/git/GitService.java
@@ -89,7 +89,6 @@ public class GitService {
         String propertiesPrefix = "karavan.";
         String branch = ConfigProvider.getConfig().getValue(propertiesPrefix + 
"git-branch", String.class);
         if (ConfigService.inKubernetes()) {
-            Secret secret = kubernetesService.getKaravanSecret();
             String uri = kubernetesService.getKaravanSecret("git-repository");
             String username = 
kubernetesService.getKaravanSecret("git-username");
             String password = 
kubernetesService.getKaravanSecret("git-password");
@@ -451,7 +450,7 @@ public class GitService {
         return files;
     }
 
-//    @Retry(maxRetries = 100, delay = 2000)
+    @Retry(maxRetries = 100, delay = 2000)
     public boolean checkGit() throws Exception {
         LOGGER.info("Check git");
         GitConfig gitConfig = getGitConfig();
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
index da0d21a8..ce164102 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
@@ -279,8 +279,8 @@ public class InfinispanService implements HealthCheck {
         containerStatuses.remove(GroupedKey.create(projectId, env, 
containerName));
     }
 
-    public CamelStatus getCamelStatus(String projectId, String env, String 
name) {
-        GroupedKey key = GroupedKey.create(projectId, env, name);
+    public CamelStatus getCamelStatus(String projectId, String env, String 
containerName) {
+        GroupedKey key = GroupedKey.create(projectId, env, containerName);
         return camelStatuses.get(key);
     }
 
@@ -288,15 +288,19 @@ public class InfinispanService implements HealthCheck {
         return camelStatuses.get(key);
     }
 
-    public List<CamelStatus> getCamelStatusesByEnv(String env, 
CamelStatus.Name name) {
+    public List<CamelStatus> getCamelStatusesByEnv(String env, 
CamelStatusValue.Name name) {
         QueryFactory queryFactory = Search.getQueryFactory(camelStatuses);
-        return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus 
WHERE env = :env AND name = :name")
+        List<CamelStatus> statuses = queryFactory.<CamelStatus>create("FROM 
karavan.CamelStatus WHERE env = :env")
                 .setParameter("env", env)
-                .setParameter("name", name)
                 .execute().list();
+        return statuses.stream().map(cs -> {
+            var values = cs.getStatuses();
+            cs.setStatuses(values.stream().filter(v -> 
Objects.equals(v.getName(), name)).toList());
+            return cs;
+        }).toList();
     }
 
-    public List<CamelStatus> getCamelStatusesByProjectIdEnv(String projectId, 
String env) {
+    public List<CamelStatus> getCamelStatusesByProjectAndEnv(String projectId, 
String env) {
         QueryFactory queryFactory = Search.getQueryFactory(camelStatuses);
         return queryFactory.<CamelStatus>create("FROM karavan.CamelStatus 
WHERE projectId = :projectId AND env = :env")
                 .setParameter("projectId", projectId)
@@ -305,7 +309,7 @@ public class InfinispanService implements HealthCheck {
     }
 
     public void saveCamelStatus(CamelStatus status) {
-        GroupedKey key = GroupedKey.create(status.getProjectId(), 
status.getEnv(), status.getName().name());
+        GroupedKey key = GroupedKey.create(status.getProjectId(), 
status.getEnv(), status.getContainerName());
         camelStatuses.put(key, status);
     }
 
@@ -315,8 +319,13 @@ public class InfinispanService implements HealthCheck {
     }
 
     public void deleteCamelStatuses(String projectId, String env) {
-        Arrays.stream(CamelStatus.Name.values()).forEach(name -> {
-            GroupedKey key = GroupedKey.create(projectId, env, name.name());
+        QueryFactory queryFactory = Search.getQueryFactory(camelStatuses);
+        List<CamelStatus> statuses = queryFactory.<CamelStatus>create("FROM 
karavan.CamelStatus WHERE projectId = :projectId AND env = :env")
+                .setParameter("projectId", projectId)
+                .setParameter("env", env)
+                .execute().list();
+        statuses.forEach(s -> {
+            GroupedKey key = GroupedKey.create(projectId, env, 
s.getContainerName());
             camelStatuses.remove(key);
         });
     }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
index 37109261..9c335c4c 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
@@ -1,41 +1,28 @@
 package org.apache.camel.karavan.infinispan.model;
 
-import org.infinispan.protostream.annotations.ProtoEnumValue;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
-public class CamelStatus {
-
-    public enum Name {
+import java.util.ArrayList;
+import java.util.List;
 
-        @ProtoEnumValue(number = 0, name = "context") context,
-        @ProtoEnumValue (number = 1, name = "inflight") inflight,
-        @ProtoEnumValue (number = 2, name = "memory") memory,
-        @ProtoEnumValue (number = 3, name = "properties") properties,
-        @ProtoEnumValue (number = 4, name = "route") route,
-        @ProtoEnumValue (number = 5, name = "trace") trace,
-        @ProtoEnumValue (number = 6, name = "jvm") jvm,
-        @ProtoEnumValue (number = 7, name = "source") source
-    }
+public class CamelStatus {
 
     public static final String CACHE = "camel_statuses";
     @ProtoField(number = 1)
     String projectId;
     @ProtoField(number = 2)
     String containerName;
-    @ProtoField(number = 3)
-    Name name;
+    @ProtoField(number = 3, collectionImplementation = ArrayList.class)
+    List<CamelStatusValue> statuses;
     @ProtoField(number = 4)
-    String status;
-    @ProtoField(number = 5)
     String env;
 
     @ProtoFactory
-    public CamelStatus(String projectId, String containerName, Name name, 
String status, String env) {
+    public CamelStatus(String projectId, String containerName, 
List<CamelStatusValue> statuses, String env) {
         this.projectId = projectId;
         this.containerName = containerName;
-        this.name = name;
-        this.status = status;
+        this.statuses = statuses;
         this.env = env;
     }
 
@@ -55,20 +42,12 @@ public class CamelStatus {
         this.containerName = containerName;
     }
 
-    public Name getName() {
-        return name;
-    }
-
-    public void setName(Name name) {
-        this.name = name;
-    }
-
-    public String getStatus() {
-        return status;
+    public List<CamelStatusValue> getStatuses() {
+        return statuses;
     }
 
-    public void setStatus(String status) {
-        this.status = status;
+    public void setStatuses(List<CamelStatusValue> statuses) {
+        this.statuses = statuses;
     }
 
     public String getEnv() {
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatusValue.java
similarity index 57%
copy from 
karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
copy to 
karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatusValue.java
index 37109261..426ab575 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatus.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/CamelStatusValue.java
@@ -4,7 +4,7 @@ import org.infinispan.protostream.annotations.ProtoEnumValue;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
-public class CamelStatus {
+public class CamelStatusValue {
 
     public enum Name {
 
@@ -18,41 +18,15 @@ public class CamelStatus {
         @ProtoEnumValue (number = 7, name = "source") source
     }
 
-    public static final String CACHE = "camel_statuses";
     @ProtoField(number = 1)
-    String projectId;
-    @ProtoField(number = 2)
-    String containerName;
-    @ProtoField(number = 3)
     Name name;
-    @ProtoField(number = 4)
+    @ProtoField(number = 2)
     String status;
-    @ProtoField(number = 5)
-    String env;
 
     @ProtoFactory
-    public CamelStatus(String projectId, String containerName, Name name, 
String status, String env) {
-        this.projectId = projectId;
-        this.containerName = containerName;
+    public CamelStatusValue(Name name, String status) {
         this.name = name;
         this.status = status;
-        this.env = env;
-    }
-
-    public String getProjectId() {
-        return projectId;
-    }
-
-    public void setProjectId(String projectId) {
-        this.projectId = projectId;
-    }
-
-    public String getContainerName() {
-        return containerName;
-    }
-
-    public void setContainerName(String containerName) {
-        this.containerName = containerName;
     }
 
     public Name getName() {
@@ -70,12 +44,4 @@ public class CamelStatus {
     public void setStatus(String status) {
         this.status = status;
     }
-
-    public String getEnv() {
-        return env;
-    }
-
-    public void setEnv(String env) {
-        this.env = env;
-    }
 }
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 4244db7a..14e48b30 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
@@ -70,8 +70,31 @@ public class ContainerStatus {
     Boolean inTransit = false;
     @ProtoField(number = 17)
     String initDate;
+    @ProtoField(number = 18)
+    String podIP;
 
     @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, String phase, Boolean codeLoaded, Boolean 
inTransit, String initDate, String podIP) {
+        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.phase = phase;
+        this.codeLoaded = codeLoaded;
+        this.inTransit = inTransit;
+        this.initDate = initDate;
+        this.podIP = podIP;
+    }
+
     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, String phase, Boolean codeLoaded, Boolean 
inTransit, String initDate) {
         this.projectId = projectId;
         this.containerName = containerName;
@@ -149,6 +172,13 @@ public class ContainerStatus {
     public ContainerStatus() {
     }
 
+    public String getPodIP() {
+        return podIP;
+    }
+
+    public void setPodIP(String podIP) {
+        this.podIP = podIP;
+    }
 
     public String getProjectId() {
         return projectId;
@@ -302,10 +332,11 @@ public class ContainerStatus {
                 ", finished='" + finished + '\'' +
                 ", commands=" + commands +
                 ", state='" + state + '\'' +
-                ", status='" + phase + '\'' +
+                ", phase='" + phase + '\'' +
                 ", codeLoaded=" + codeLoaded +
                 ", inTransit=" + inTransit +
                 ", initDate='" + initDate + '\'' +
+                ", podIP='" + podIP + '\'' +
                 '}';
     }
 }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
index 3ccde791..07018809 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/infinispan/model/KaravanSchema.java
@@ -10,7 +10,8 @@ import 
org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
                 Project.Type.class,
                 ProjectFile.class,
                 CamelStatus.class,
-                CamelStatus.Name.class,
+                CamelStatusValue.class,
+                CamelStatusValue.Name.class,
                 DeploymentStatus.class,
                 ContainerStatus.class,
                 ContainerStatus.ContainerType.class,
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
index ffd24a68..d47e1853 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/KubernetesService.java
@@ -24,6 +24,7 @@ import io.fabric8.kubernetes.client.dsl.LogWatch;
 import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
 import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
+import io.quarkus.runtime.configuration.ProfileManager;
 import io.smallrye.mutiny.tuples.Tuple2;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import org.apache.camel.karavan.infinispan.InfinispanService;
@@ -32,6 +33,7 @@ import org.apache.camel.karavan.infinispan.model.Project;
 import org.apache.camel.karavan.infinispan.model.ProjectFile;
 import org.apache.camel.karavan.code.CodeService;
 import org.apache.camel.karavan.service.ConfigService;
+import org.eclipse.microprofile.config.ConfigProvider;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.health.HealthCheck;
 import org.eclipse.microprofile.health.HealthCheckResponse;
@@ -64,6 +66,8 @@ public class KubernetesService implements HealthCheck {
     @Inject
     InfinispanService infinispanService;
 
+    private String namespace;
+
     @Produces
     public KubernetesClient kubernetesClient() {
         return new DefaultKubernetesClient();
@@ -248,31 +252,12 @@ public class KubernetesService implements HealthCheck {
                 .build();
     }
 
-
-    public String getContainerLog(String podName, String namespace) {
-        try (KubernetesClient client = kubernetesClient()) {
-            String logText = 
client.pods().inNamespace(namespace).withName(podName).getLog(true);
-            return logText;
-        }
-    }
-
     public Tuple2<LogWatch, KubernetesClient> getContainerLogWatch(String 
podName) {
         KubernetesClient client = kubernetesClient();
         LogWatch logWatch = 
client.pods().inNamespace(getNamespace()).withName(podName).tailingLines(100).watchLog();
         return Tuple2.of(logWatch, client);
     }
 
-    private List<Condition> getCancelConditions(String reason) {
-        List<Condition> cancelConditions = new ArrayList<>();
-        Condition taskRunCancelCondition = new Condition();
-        taskRunCancelCondition.setType("Succeeded");
-        taskRunCancelCondition.setStatus("False");
-        taskRunCancelCondition.setReason(reason);
-        taskRunCancelCondition.setMessage("Cancelled successfully.");
-        cancelConditions.add(taskRunCancelCondition);
-        return cancelConditions;
-    }
-
     public void rolloutDeployment(String name, String namespace) {
         try (KubernetesClient client = kubernetesClient()) {
             
client.apps().deployments().inNamespace(namespace).withName(name).rolling().restart();
@@ -300,43 +285,6 @@ public class KubernetesService implements HealthCheck {
         }
     }
 
-    public Deployment getDeployment(String name, String namespace) {
-        try (KubernetesClient client = kubernetesClient()) {
-            return 
client.apps().deployments().inNamespace(namespace).withName(name).get();
-        } catch (Exception ex) {
-            LOGGER.error(ex.getMessage());
-            return null;
-        }
-    }
-
-    public boolean hasDeployment(String name, String namespace) {
-        try (KubernetesClient client = kubernetesClient()) {
-            Deployment deployment = 
client.apps().deployments().inNamespace(namespace).withName(name).get();
-            return deployment != null;
-        } catch (Exception ex) {
-            LOGGER.error(ex.getMessage());
-            return false;
-        }
-    }
-
-    public List<String> getCamelDeployments(String namespace) {
-        try (KubernetesClient client = kubernetesClient()) {
-            return 
client.apps().deployments().inNamespace(namespace).withLabels(getRuntimeLabels()).list().getItems()
-                    .stream().map(deployment -> 
deployment.getMetadata().getName()).collect(Collectors.toList());
-        } catch (Exception ex) {
-            LOGGER.error(ex.getMessage());
-            return List.of();
-        }
-    }
-
-    private String getPodReason(Pod pod) {
-        try {
-            return 
pod.getStatus().getContainerStatuses().get(0).getState().getWaiting().getReason();
-        } catch (Exception e) {
-            return "";
-        }
-    }
-
     public List<String> getConfigMaps(String namespace) {
         List<String> result = new ArrayList<>();
         try (KubernetesClient client = kubernetesClient()) {
@@ -561,8 +509,11 @@ public class KubernetesService implements HealthCheck {
     }
 
     public String getNamespace() {
-        try (KubernetesClient client = kubernetesClient()) {
-            return client.getNamespace();
+        if (namespace == null) {
+            try (KubernetesClient client = kubernetesClient()) {
+                namespace = ProfileManager.getLaunchMode().isDevOrTest() ? 
"karavan" : client.getNamespace();
+            }
         }
+        return namespace;
     }
 }
diff --git 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
index fa03e433..4e1372b7 100644
--- 
a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
+++ 
b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/kubernetes/PodEventHandler.java
@@ -108,6 +108,7 @@ public class PodEventHandler implements 
ResourceEventHandler<Pod> {
                     creationTimestamp);
             status.setContainerId(pod.getMetadata().getName());
             status.setPhase(pod.getStatus().getPhase());
+            status.setPodIP(pod.getStatus().getPodIP());
             if (ready) {
                 status.setState(ContainerStatus.State.running.name());
             } else if (failed) {
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 d9ca389a..f8478d10 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
@@ -26,6 +26,7 @@ import io.vertx.mutiny.ext.web.client.HttpResponse;
 import io.vertx.mutiny.ext.web.client.WebClient;
 import org.apache.camel.karavan.infinispan.InfinispanService;
 import org.apache.camel.karavan.infinispan.model.CamelStatus;
+import org.apache.camel.karavan.infinispan.model.CamelStatusValue;
 import org.apache.camel.karavan.infinispan.model.ContainerStatus;
 import org.apache.camel.karavan.infinispan.model.ProjectFile;
 import org.apache.camel.karavan.kubernetes.KubernetesService;
@@ -36,10 +37,8 @@ import org.jboss.logging.Logger;
 
 import jakarta.enterprise.context.ApplicationScoped;
 import jakarta.inject.Inject;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
+
+import java.util.*;
 import java.util.concurrent.ExecutionException;
 
 @ApplicationScoped
@@ -92,16 +91,6 @@ public class CamelService {
         }
     }
 
-    private boolean camelIsStarted(CamelStatus camelStatus) {
-        try {
-            String status = camelStatus.getStatus();
-            JsonObject obj = new JsonObject(status);
-            return Objects.equals("Started", 
obj.getJsonObject("context").getString("state"));
-        } catch (Exception e) {
-            return false;
-        }
-    }
-
     @ConsumeEvent(value = RELOAD_PROJECT_CODE, blocking = true, ordered = true)
     public void reloadProjectCode(String projectId) {
         LOGGER.info("Reload project code " + projectId);
@@ -120,7 +109,7 @@ public class CamelService {
     @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 
1000)
     public boolean putRequest(String containerName, String fileName, String 
body, int timeout) {
         try {
-            String url = getContainerAddress(containerName) + "/q/upload/" + 
fileName;
+            String url = getContainerAddressForReload(containerName) + 
"/q/upload/" + fileName;
             HttpResponse<Buffer> result = getWebClient().putAbs(url)
                     
.timeout(timeout).sendBuffer(Buffer.buffer(body)).subscribeAsCompletionStage().toCompletableFuture().get();
             return result.statusCode() == 200;
@@ -131,7 +120,7 @@ public class CamelService {
     }
 
     public String reloadRequest(String containerName) {
-        String url = getContainerAddress(containerName) + 
"/q/dev/reload?reload=true";
+        String url = getContainerAddressForReload(containerName) + 
"/q/dev/reload?reload=true";
         try {
             return result(url, 1000);
         } catch (InterruptedException | ExecutionException e) {
@@ -140,7 +129,7 @@ public class CamelService {
         return null;
     }
 
-    public String getContainerAddress(String containerName) {
+    public String getContainerAddressForReload(String containerName) {
         if (ConfigService.inKubernetes()) {
             return "http://"; + containerName + "." + 
kubernetesService.getNamespace();
         } else if (ConfigService.inDocker()) {
@@ -151,22 +140,46 @@ public class CamelService {
         }
     }
 
+    public String getContainerAddressForStatus(ContainerStatus 
containerStatus) {
+        if (ConfigService.inKubernetes()) {
+            String podIP = containerStatus.getPodIP().replace(".", "-");
+            return "http://"; + podIP + "." + kubernetesService.getNamespace() 
+ ".pod.cluster.local:8080";
+        } else if (ConfigService.inDocker()) {
+            return "http://"; + containerStatus.getContainerName() + ":8080";
+        } else {
+            Integer port = 
projectService.getProjectPort(containerStatus.getContainerName());
+            return "http://localhost:"; + port;
+        }
+    }
+
+    public String getCamelStatus(ContainerStatus containerStatus, 
CamelStatusValue.Name statusName) {
+        String url = getContainerAddressForStatus(containerStatus) + "/q/dev/" 
+ statusName.name();
+        try {
+            return result(url, 500);
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.error(e.getMessage());
+        }
+        return null;
+    }
+
     @ConsumeEvent(value = CMD_COLLECT_CAMEL_STATUS, blocking = true, ordered = 
true)
     public void collectCamelStatuses(JsonObject data) {
         CamelStatusRequest dms = 
data.getJsonObject("camelStatusRequest").mapTo(CamelStatusRequest.class);
         ContainerStatus containerStatus = 
data.getJsonObject("containerStatus").mapTo(ContainerStatus.class);
         String projectId = dms.getProjectId();
-        Arrays.stream(CamelStatus.Name.values()).forEach(statusName -> {
-            String containerName = dms.getContainerName();
-            String status = getCamelStatus(containerName, statusName);
+        String containerName = dms.getContainerName();
+        List<CamelStatusValue> statuses = new ArrayList<>();
+        Arrays.stream(CamelStatusValue.Name.values()).forEach(statusName -> {
+            String status = getCamelStatus(containerStatus, statusName);
             if (status != null) {
-                CamelStatus cs = new CamelStatus(projectId, containerName, 
statusName, status, environment);
-                infinispanService.saveCamelStatus(cs);
-                if (ConfigService.inKubernetes() && Objects.equals(statusName, 
CamelStatus.Name.context)) {
+                statuses.add(new CamelStatusValue(statusName, status));
+                if (ConfigService.inKubernetes() && Objects.equals(statusName, 
CamelStatusValue.Name.context)) {
                     checkReloadRequired(containerStatus);
                 }
             }
         });
+        CamelStatus cs = new CamelStatus(projectId, containerName, statuses, 
environment);
+        infinispanService.saveCamelStatus(cs);
     }
 
     private void checkReloadRequired(ContainerStatus cs) {
@@ -179,16 +192,6 @@ public class CamelService {
         }
     }
 
-    public String getCamelStatus(String podName, CamelStatus.Name statusName) {
-        String url = getContainerAddress(podName) + "/q/dev/" + 
statusName.name();
-        try {
-            return result(url, 500);
-        } catch (InterruptedException | ExecutionException e) {
-            LOGGER.error(e.getMessage());
-        }
-        return null;
-    }
-
     @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 
1000)
     public String result(String url, int timeout) throws InterruptedException, 
ExecutionException {
         try {
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 48b4fb35..5fab57b9 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,13 +5,12 @@ 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.server.enabled=true
+camel.server.healthCheckEnabled=true
+camel.server.devConsoleEnabled=true
 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
-camel.server.healthCheckEnabled=true
-camel.server.devConsoleEnabled=true
 jkube.version=1.14.0
 
jib.from.image=gcr.io/distroless/java17@sha256:3a4ea21bd7b412b8b6ae61313b39337d8f03bb6844013810e8e4625d8c765edb
diff --git 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
index 467d45e0..ff0c5b6a 100644
--- 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
+++ 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-kubernetes-application.properties
@@ -10,6 +10,8 @@ camel.health.exposure-level=full
 camel.server.enabled=true
 camel.server.healthCheckEnabled=true
 camel.server.devConsoleEnabled=true
+camel.context.dev-console=true
+camel.main.beanIntrospectionExtendedStatistics=true
 label.runtime=app.kubernetes.io/runtime
 
jib.from.image=gcr.io/distroless/java17@sha256:3a4ea21bd7b412b8b6ae61313b39337d8f03bb6844013810e8e4625d8c765edb
 jkube.version=1.14.0
diff --git 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
index 467d45e0..ff0c5b6a 100644
--- 
a/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
+++ 
b/karavan-web/karavan-app/src/main/resources/snippets/camel-main-openshift-application.properties
@@ -10,6 +10,8 @@ camel.health.exposure-level=full
 camel.server.enabled=true
 camel.server.healthCheckEnabled=true
 camel.server.devConsoleEnabled=true
+camel.context.dev-console=true
+camel.main.beanIntrospectionExtendedStatistics=true
 label.runtime=app.kubernetes.io/runtime
 
jib.from.image=gcr.io/distroless/java17@sha256:3a4ea21bd7b412b8b6ae61313b39337d8f03bb6844013810e8e4625d8c765edb
 jkube.version=1.14.0
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 af9487a0..9dae7bba 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
@@ -192,8 +192,8 @@ export class KaravanApi {
         });
     }
 
-    static async getAllCamelStatuses(env: string, after: (statuses: 
CamelStatus[]) => void) {
-        instance.get('/api/status/camel/' + env)
+    static async getAllCamelContextStatuses(env: string, after: (statuses: 
CamelStatus[]) => void) {
+        instance.get('/api/status/camel/context/' + env)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
@@ -329,8 +329,17 @@ export class KaravanApi {
         });
     }
 
-    static async getDevModeStatus(projectId: string, statusName: string, 
after: (res: AxiosResponse<CamelStatus>) => void) {
-        instance.get('/api/devmode/status/' + projectId + "/" + statusName)
+    static async getProjectCamelStatuses(projectId: string, env: string, 
after: (res: AxiosResponse<CamelStatus[]>) => void) {
+        instance.get('/api/project/status/camel/' + projectId + "/" + env)
+            .then(res => {
+                after(res);
+            }).catch(err => {
+            after(err);
+        });
+    }
+
+    static async getProjectCamelTraces(projectId: string, env: string, after: 
(res: AxiosResponse<CamelStatus[]>) => void) {
+        instance.get('/api/project/traces/' + projectId + "/" + env)
             .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 61ad544a..4a2170b6 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
@@ -91,9 +91,13 @@ export class ContainerStatus {
 export class CamelStatus {
     projectId: string = '';
     containerName: string = '';
+    statuses: CamelStatusValue[] = [];
+    env: string = '';
+}
+
+export class CamelStatusValue {
     name: string = '';
     status: string = '';
-    env: string = '';
 }
 
 export class ProjectFile {
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts 
b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
index 78b066ab..8e14aa29 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -87,14 +87,10 @@ interface ProjectState {
     tabIndex: string | number;
     setTabIndex: (tabIndex: string | number) => void;
     setOperation: (o: "create" | "select" | "delete"| "none" | "copy") => void;
-    memory: any,
-    setMemory: (memory: any) => void;
-    jvm: any,
-    setJvm: (jvm: any) => void;
-    context: any,
-    setContext: (context: any) => void;
-    trace: any,
-    setTrace: (trace: any) => void;
+    camelStatuses: CamelStatus[],
+    setCamelStatuses: (camelStatuses: CamelStatus[]) => void;
+    camelTraces: CamelStatus[],
+    setCamelTraces: (camelTraces: CamelStatus[]) => void;
     refreshTrace: boolean
     setRefreshTrace: (refreshTrace: boolean) => void;
 }
@@ -134,21 +130,21 @@ export const useProjectStore = 
createWithEqualityFn<ProjectState>((set) => ({
             return {images: state.images};
         });
     },
-    memory: {},
-    setMemory: (memory: boolean)  => {
-        set({memory: memory})
-    },
-    jvm: {},
-    setJvm: (jvm: boolean)  => {
-        set({jvm: jvm})
-    },
-    context: {},
-    setContext: (context: boolean)  => {
-        set({context: context})
+    camelStatuses: [],
+    setCamelStatuses: (camelStatuses: CamelStatus[])  => {
+        set((state: ProjectState) => {
+            state.camelStatuses.length = 0;
+            state.camelStatuses.push(...camelStatuses);
+            return {camelStatuses: state.camelStatuses};
+        });
     },
-    trace: {},
-    setTrace: (trace: boolean)  => {
-        set({trace: trace})
+    camelTraces: [],
+    setCamelTraces: (camelTraces: CamelStatus[])  => {
+        set((state: ProjectState) => {
+            state.camelTraces.length = 0;
+            state.camelTraces.push(...camelTraces);
+            return {camelTraces: state.camelTraces};
+        });
     },
     refreshTrace: false,
     setRefreshTrace: (refreshTrace: boolean)  => {
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx 
b/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
index 4cc43eb9..9e855217 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/containers/ContainerTableRow.tsx
@@ -24,6 +24,9 @@ export function ContainerTableRow (props: Props) {
 
     const container = props.container;
     const commands = container.commands;
+    const imageParts = container.image.split("@");
+    const image = imageParts[0];
+    const imageSha = imageParts[1];
     const ports = container.ports;
     const isRunning = container.state === 'running';
     const inTransit = container.inTransit;
@@ -48,7 +51,7 @@ export function ContainerTableRow (props: Props) {
                 <Td>
                     <Label color={color}>{container.containerName}</Label>
                 </Td>
-                <Td>{container.image}</Td>
+                <Td>{image}</Td>
                 <Td>
                     {isRunning && container.cpuInfo && <Label 
color={color}>{container.cpuInfo}</Label>}
                 </Td>
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx 
b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index 36a0a734..4de22cd4 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -30,7 +30,6 @@ import {MainDataPoller} from "./MainDataPoller";
 import {TemplatesPage} from "../templates/TemplatesPage";
 import {EventBus} from "../designer/utils/EventBus";
 import {Notification} from "../designer/utils/Notification";
-import CheckIcon from "@patternfly/react-icons/dist/esm/icons/check-icon";
 
 export function Main() {
 
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx 
b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
index 7dbfa64a..1fe73aab 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
@@ -50,7 +50,7 @@ export function MainDataPoller () {
             KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) 
=> {
                 setContainers(statuses);
             });
-            KaravanApi.getAllCamelStatuses(config.environment, (statuses: 
CamelStatus[]) => {
+            KaravanApi.getAllCamelContextStatuses(config.environment, 
(statuses: CamelStatus[]) => {
                 setCamels(statuses);
             });
             setLoading(false);
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx
index a70205f8..60c7fe03 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx
@@ -4,12 +4,13 @@ import {KaravanApi} from "../api/KaravanApi";
 import '../designer/karavan.css';
 import {useAppConfigStore, useProjectStore} from "../api/ProjectStore";
 import {shallow} from "zustand/shallow";
+import {CamelStatus} from "../api/ProjectModels";
 
-export function ProjectDataPoller () {
+export function ProjectDataPoller() {
 
     const [config] = useAppConfigStore((state) => [state.config], shallow)
-    const [project, setMemory, setJvm, setContext, refreshTrace, setTrace, 
setImages] = useProjectStore((s) =>
-        [s.project, s.setMemory, s.setJvm, s.setContext, s.refreshTrace, 
s.setTrace, s.setImages], shallow);
+    const [project, setCamelStatuses, setCamelTraces, refreshTrace, setImages] 
= useProjectStore((s) =>
+        [s.project, s.setCamelStatuses, s.setCamelTraces, s.refreshTrace, 
s.setImages], shallow);
 
     useEffect(() => {
         const interval = setInterval(() => onRefreshStatus(), 1000);
@@ -20,36 +21,22 @@ export function ProjectDataPoller () {
 
     function onRefreshStatus() {
         const projectId = project.projectId;
-        KaravanApi.getDevModeStatus(projectId, "memory", res => {
+        KaravanApi.getProjectCamelStatuses(projectId, config.environment, 
(res) => {
             if (res.status === 200) {
-                setMemory(JSON.parse(res.data.status));
+                setCamelStatuses(res.data);
             } else {
-                setMemory({});
-            }
-        })
-        KaravanApi.getDevModeStatus(projectId, "jvm", res => {
-            if (res.status === 200) {
-                setJvm(JSON.parse(res.data.status));
-            } else {
-                setJvm({});
-            }
-        })
-        KaravanApi.getDevModeStatus(projectId, "context", res => {
-            if (res.status === 200) {
-                setContext(JSON.parse(res.data.status));
-            } else {
-                setContext({});
+                setCamelStatuses([]);
             }
         })
         KaravanApi.getImages(project.projectId, (res: any) => {
             setImages(res)
         });
         if (refreshTrace) {
-            KaravanApi.getDevModeStatus(projectId, "trace", res => {
+            KaravanApi.getProjectCamelTraces(projectId, config.environment, 
res => {
                 if (res.status === 200) {
-                    setTrace(JSON.parse(res.data.status));
+                    setCamelTraces(res.data);
                 } else {
-                    setTrace({});
+                    setCamelTraces([]);
                 }
             })
         }
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index c932c5f3..9a39a090 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -1,5 +1,7 @@
 import React, {useEffect, useState} from 'react';
 import {
+    Flex,
+    FlexItem,
     PageSection,
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
index 437ce91b..9b07d27a 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPanel.tsx
@@ -15,16 +15,16 @@ import {ImagesPanel} from "./build/ImagesPanel";
 import {ContainerButtons} from "./container/ContainerButtons";
 import {ProjectContainerTab} from "./container/ProjectContainerTab";
 
-export function ProjectPanel () {
+export function ProjectPanel() {
 
     const [config] = useAppConfigStore((state) => [state.config], shallow)
-    const [project,tab, setTab] = useProjectStore((s) => [s.project, 
s.tabIndex, s.setTabIndex], shallow );
+    const [project, tab, setTab] = useProjectStore((s) => [s.project, 
s.tabIndex, s.setTabIndex], shallow);
 
     useEffect(() => {
         onRefresh();
     }, [project]);
 
-    function onRefresh () {
+    function onRefresh() {
         if (project.projectId) {
             ProjectService.refreshProjectData(project.projectId);
         }
@@ -46,18 +46,14 @@ export function ProjectPanel () {
                     <Tab eventKey="container" title="Container"/>
                 </Tabs>}
             </FlexItem>
+            {buildIn && tab === 'files' && <FlexItem><FilesTab/></FlexItem>}
             <FlexItem>
-                {buildIn && tab === 'files' && <FilesTab/>}
-                {!buildIn &&
-                    <>
-                        {tab === 'files' && <FilesTab/>}
-                        {tab === 'dashboard' && project && <DashboardTab/>}
-                        {tab === 'trace' && project && <TraceTab/>}
-                        {tab === 'build' && <ProjectBuildTab/>}
-                        {tab === 'build' && config.infrastructure !== 
'kubernetes' && <ImagesPanel/>}
-                        {tab === 'container' && <ProjectContainerTab/>}
-                    </>
-                }
+                {!buildIn && tab === 'files' && 
<FlexItem><FilesTab/></FlexItem>}
+                {!buildIn && tab === 'dashboard' && project && 
<FlexItem><DashboardTab/></FlexItem>}
+                {!buildIn && tab === 'trace' && project && 
<FlexItem><TraceTab/></FlexItem>}
+                {!buildIn && tab === 'build' && 
<FlexItem><ProjectBuildTab/></FlexItem>}
+                {!buildIn && tab === 'build' && config.infrastructure !== 
'kubernetes' && <FlexItem><ImagesPanel/></FlexItem>}
+                {!buildIn && tab === 'container' && 
<FlexItem><ProjectContainerTab/></FlexItem>}
             </FlexItem>
         </Flex>
     )
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
index f0eb688b..795385f3 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
@@ -17,7 +17,16 @@
 import React from 'react';
 import {
     Card,
-    CardBody, Flex, FlexItem, Divider, PageSection
+    CardBody,
+    Flex,
+    FlexItem,
+    Divider,
+    PageSection,
+    EmptyState,
+    EmptyStateVariant,
+    EmptyStateHeader,
+    EmptyStateIcon,
+    Bullseye, Panel
 } from '@patternfly/react-core';
 import '../../designer/karavan.css';
 import {InfoContainer} from "./InfoContainer";
@@ -25,37 +34,51 @@ import {InfoContext} from "./InfoContext";
 import {InfoMemory} from "./InfoMemory";
 import {useProjectStore, useStatusesStore} from "../../api/ProjectStore";
 import {shallow} from "zustand/shallow";
-import {ContainerStatus} from "../../api/ProjectModels";
+import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
 
-export function DashboardTab () {
+export function DashboardTab() {
 
-    const [project, memory, jvm, context] = useProjectStore((state) =>
-        [state.project, state.memory, state.jvm, state.context], shallow);
+    const [project, camelStatuses] = useProjectStore((state) =>
+        [state.project, state.camelStatuses], shallow);
     const [containers] = useStatusesStore((state) => [state.containers], 
shallow);
 
-    const containerStatus = containers.filter(c => c.containerName === 
project.projectId).at(0);
-    const showConsole = containerStatus?.state === 'running'
+    const camelContainers = containers
+        .filter(c => c.projectId === project.projectId && ['devmode', 
'project'].includes(c.type));
 
     return (
         <PageSection className="project-tab-panel" padding={{default: 
"padding"}}>
-            <Card className="project-development">
-                <CardBody>
-                    <Flex direction={{default: "row"}}
-                          justifyContent={{default: 
"justifyContentSpaceBetween"}}>
-                        <FlexItem flex={{default: "flex_1"}}>
-                            <InfoContainer containerStatus={containerStatus || 
new ContainerStatus()}/>
-                        </FlexItem>
-                        <Divider orientation={{default: "vertical"}}/>
-                        <FlexItem flex={{default: "flex_1"}}>
-                            <InfoMemory jvm={jvm} memory={memory} 
showConsole={showConsole}/>
-                        </FlexItem>
-                        <Divider orientation={{default: "vertical"}}/>
-                        <FlexItem flex={{default: "flex_1"}}>
-                            <InfoContext context={context} 
showConsole={showConsole}/>
-                        </FlexItem>
-                    </Flex>
-                </CardBody>
-            </Card>
+            <Panel isScrollable>
+                {camelContainers.map((containerStatus, index) => <Card 
className="project-development">
+                    <CardBody>
+                        <Flex direction={{default: "row"}}
+                              justifyContent={{default: 
"justifyContentSpaceBetween"}}>
+                            <FlexItem flex={{default: "flex_1"}}>
+                                <InfoContainer 
containerStatus={containerStatus}/>
+                            </FlexItem>
+                            <Divider orientation={{default: "vertical"}}/>
+                            <FlexItem flex={{default: "flex_1"}}>
+                                <InfoMemory containerStatus={containerStatus}/>
+                            </FlexItem>
+                            <Divider orientation={{default: "vertical"}}/>
+                            <FlexItem flex={{default: "flex_1"}}>
+                                <InfoContext 
containerStatus={containerStatus}/>
+                            </FlexItem>
+                        </Flex>
+                    </CardBody>
+                </Card>)}
+            </Panel>
+            {camelContainers.length === 0 &&
+                <Card className="project-development">
+                    <CardBody>
+                        <Bullseye>
+                            <EmptyState variant={EmptyStateVariant.sm}>
+                                <EmptyStateHeader titleText="No running 
containers"
+                                                  icon={<EmptyStateIcon 
icon={SearchIcon}/>} headingLevel="h2"/>
+                            </EmptyState>
+                        </Bullseye>
+                    </CardBody>
+                </Card>
+            }
         </PageSection>
     )
 }
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
index 7b498737..ae5b1aca 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContainer.tsx
@@ -1,5 +1,6 @@
 import React from 'react';
 import {
+    Badge,
     DescriptionList,
     DescriptionListDescription,
     DescriptionListGroup,
@@ -18,7 +19,7 @@ interface Props {
 
 export function InfoContainer (props: Props) {
 
-    function getPodInfoLabel(info: string) {
+    function getPodInfoLabel(info: React.ReactNode) {
         return (
             <Label icon={getIcon()} color={getColor()}>
                 {info}
@@ -44,7 +45,12 @@ export function InfoContainer (props: Props) {
             <DescriptionListGroup>
                 <DescriptionListTerm>Container</DescriptionListTerm>
                 <DescriptionListDescription>
-                    {getPodInfoLabel(containerStatus.containerName)}
+                    {getPodInfoLabel(
+                        <>
+                            {containerStatus.containerName}
+                            <Badge isRead>{containerStatus.type}</Badge>
+                        </>
+                    )}
                 </DescriptionListDescription>
             </DescriptionListGroup>
             <DescriptionListGroup>
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContext.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContext.tsx
index addceb43..dc6595c4 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContext.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoContext.tsx
@@ -10,21 +10,28 @@ import {
 import '../../designer/karavan.css';
 import DownIcon from 
"@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
 import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import {ContainerStatus} from "../../api/ProjectModels";
+import {useProjectStore} from "../../api/ProjectStore";
+import {shallow} from "zustand/shallow";
 
 
 interface Props {
-    context: any,
-    showConsole: boolean
+    containerStatus: ContainerStatus
 }
 
 export function InfoContext (props: Props) {
+    const [camelStatuses] = useProjectStore((state) => [state.camelStatuses], 
shallow);
+
+    const camelStatus = camelStatuses.filter(s => s.containerName === 
props.containerStatus.containerName).at(0);
+    const contextValue = camelStatus?.statuses?.filter(x => x.name === 
'context').at(0);
+    const context = contextValue ? JSON.parse(contextValue?.status || '') : {};
 
     function getContextInfo() {
         return (
             <LabelGroup numLabels={3}>
                 <Tooltip content="Name" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.name}
+                        {context?.context?.name}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -36,7 +43,7 @@ export function InfoContext (props: Props) {
             <LabelGroup numLabels={3}>
                 <Tooltip content="Version" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.version}
+                        {context?.context?.version}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -48,17 +55,17 @@ export function InfoContext (props: Props) {
             <LabelGroup numLabels={3}>
                 <Tooltip content="State" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.state}
+                        {context?.context?.state}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Phase" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.phase}
+                        {context?.context?.phase}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Uptime" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.uptime}
+                        {context?.context?.uptime}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -70,17 +77,17 @@ export function InfoContext (props: Props) {
             <LabelGroup numLabels={3}>
                 <Tooltip content="Total" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.statistics?.exchangesTotal}
+                        {context?.context?.statistics?.exchangesTotal}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Failed" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.statistics?.exchangesFailed}
+                        {context?.context?.statistics?.exchangesFailed}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Inflight" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.statistics?.exchangesInflight}
+                        {context?.context?.statistics?.exchangesInflight}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -92,22 +99,22 @@ export function InfoContext (props: Props) {
             <LabelGroup numLabels={4}>
                 <Tooltip content="Min" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.statistics?.minProcessingTime}
+                        {context?.context?.statistics?.minProcessingTime}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Mean" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        
{props.context?.context?.statistics?.meanProcessingTime}
+                        {context?.context?.statistics?.meanProcessingTime}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Max" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.context?.context?.statistics?.maxProcessingTime}
+                        {context?.context?.statistics?.maxProcessingTime}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Last" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        
{props.context?.context?.statistics?.lastProcessingTime}
+                        {context?.context?.statistics?.lastProcessingTime}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -123,7 +130,7 @@ export function InfoContext (props: Props) {
     }
 
     function getRunning(): boolean {
-        return props.context ? isRunning(props.context) : false;
+        return context ? isRunning(context) : false;
     }
 
 
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoMemory.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoMemory.tsx
index 74cc42c9..8d1ad077 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoMemory.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/InfoMemory.tsx
@@ -10,21 +10,30 @@ import {
 import '../../designer/karavan.css';
 import DownIcon from 
"@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
 import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import {ContainerStatus} from "../../api/ProjectModels";
+import {useProjectStore} from "../../api/ProjectStore";
+import {shallow} from "zustand/shallow";
 
 
 interface Props {
-    jvm: any,
-    memory: any,
-    showConsole: boolean
+    containerStatus: ContainerStatus
 }
 
 export function InfoMemory (props: Props) {
 
+    const [camelStatuses] = useProjectStore((state) => [state.camelStatuses], 
shallow);
+
+    const camelStatus = camelStatuses.filter(s => s.containerName === 
props.containerStatus.containerName).at(0);
+    const jvmValue = camelStatus?.statuses?.filter(x => x.name === 
'jvm').at(0);
+    const memoryValue = camelStatus?.statuses?.filter(x => x.name === 
'memory').at(0);
+    const jvm = jvmValue ? JSON.parse(jvmValue?.status || '') : {};
+    const memory = memoryValue ? JSON.parse(memoryValue?.status || '') : {};
+
     function getJvmInfo() {
         return (
             <LabelGroup numLabels={2}>
                 <Label icon={getIcon()} color={getColor()}>
-                    {props.jvm?.jvm?.vmVendor} {props.jvm?.jvm?.vmVersion}
+                    {jvm?.jvm?.vmVendor} {jvm?.jvm?.vmVersion}
                 </Label>
             </LabelGroup>
         )
@@ -35,17 +44,17 @@ export function InfoMemory (props: Props) {
             <LabelGroup numLabels={3}>
                 <Tooltip content="Init" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.heapMemoryInit}
+                        {memory?.memory?.heapMemoryInit}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Max" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.heapMemoryMax}
+                        {memory?.memory?.heapMemoryMax}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Used" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.heapMemoryUsed}
+                        {memory?.memory?.heapMemoryUsed}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -57,7 +66,7 @@ export function InfoMemory (props: Props) {
             <LabelGroup numLabels={2}>
                 <Tooltip content="Uptime" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.jvm?.jvm?.vmUptime}
+                        {jvm?.jvm?.vmUptime}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -69,7 +78,7 @@ export function InfoMemory (props: Props) {
             <LabelGroup numLabels={2}>
                 <Tooltip content="PID" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.jvm?.jvm?.pid}
+                        {jvm?.jvm?.pid}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -81,17 +90,17 @@ export function InfoMemory (props: Props) {
             <LabelGroup numLabels={3}>
                 <Tooltip content="Init" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.nonHeapMemoryInit}
+                        {memory?.memory?.nonHeapMemoryInit}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Max" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.nonHeapMemoryMax}
+                        {memory?.memory?.nonHeapMemoryMax}
                     </Label>
                 </Tooltip>
                 <Tooltip content="Used" position={"bottom"}>
                     <Label icon={getIcon()} color={getColor()}>
-                        {props.memory?.memory?.nonHeapMemoryUsed}
+                        {memory?.memory?.nonHeapMemoryUsed}
                     </Label>
                 </Tooltip>
             </LabelGroup>
@@ -107,7 +116,7 @@ export function InfoMemory (props: Props) {
     }
 
     function getRunning(): boolean {
-        return isRunning(props.jvm);
+        return isRunning(jvm);
     }
 
 
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
index 47dc999a..0aba226c 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesTab.tsx
@@ -6,7 +6,7 @@ import {
     EmptyState,
     EmptyStateVariant,
     EmptyStateIcon,
-    PageSection, PanelHeader, Panel, Tooltip, Label, EmptyStateHeader,
+    PageSection, PanelHeader, Panel, Tooltip, Label, EmptyStateHeader, 
PanelMain, PanelMainBody, Flex, FlexItem,
 } from '@patternfly/react-core';
 import '../../designer/karavan.css';
 import {
@@ -81,67 +81,69 @@ export function FilesTab () {
                     <FileToolbar/>
                 </PanelHeader>
             </Panel>
-            <Table aria-label="Files" variant={"compact"} className={"table"}>
-                <Thead>
-                    <Tr>
-                        <Th key='type' width={20}>Type</Th>
-                        <Th key='filename' width={40}>Filename</Th>
-                        <Th key='lastUpdate' width={30}>Updated</Th>
-                        <Th key='action'></Th>
-                    </Tr>
-                </Thead>
-                <Tbody>
-                    {files.map(file => {
-                        const type = getProjectFileType(file)
-                        return <Tr key={file.name}>
-                            <Td>
-                                <Badge>{type}</Badge>
-                            </Td>
-                            <Td>
-                                <Button style={{padding: '6px'}} 
variant={"link"}
-                                        onClick={e =>
-                                            useFileStore.setState({file: file, 
operation: "select"})
-                                }>
-                                    {file.name}
-                                </Button>
-                            </Td>
-                            <Td>
-                                {needCommit(file.lastUpdate) &&
-                                    <Tooltip content="Updated after last 
commit" position={"right"}>
-                                        <Label 
color="grey">{getDate(file.lastUpdate)}</Label>
-                                    </Tooltip>
-                                }
-                                {!needCommit(file.lastUpdate) && 
getDate(file.lastUpdate)}
-                            </Td>
-                            <Td modifier={"fitContent"}>
-                                {canDeleteFiles() &&
-                                    <Button style={{padding: '0'}} 
variant={"plain"}
-                                            
isDisabled={['application.properties', 
'project-compose.yaml'].includes(file.name)}
+            <div style={{height:"100%", overflow:"auto"}}>
+                <Table aria-label="Files" variant={"compact"} 
className={"table"}>
+                    <Thead>
+                        <Tr>
+                            <Th key='type' width={20}>Type</Th>
+                            <Th key='filename' width={40}>Filename</Th>
+                            <Th key='lastUpdate' width={30}>Updated</Th>
+                            <Th key='action'></Th>
+                        </Tr>
+                    </Thead>
+                    <Tbody>
+                        {files.map(file => {
+                            const type = getProjectFileType(file)
+                            return <Tr key={file.name}>
+                                <Td>
+                                    <Badge>{type}</Badge>
+                                </Td>
+                                <Td>
+                                    <Button style={{padding: '6px'}} 
variant={"link"}
                                             onClick={e =>
-                                                useFileStore.setState({file: 
file, operation: "delete"})
+                                                useFileStore.setState({file: 
file, operation: "select"})
                                     }>
-                                        <DeleteIcon/>
+                                        {file.name}
                                     </Button>
-                                }
-                                <Tooltip content="Download source" 
position={"bottom-end"}>
-                                    <Button size="sm" variant="plain" 
icon={<DownloadIcon/>} onClick={e => download(file)}/>
-                                </Tooltip>
-                            </Td>
-                        </Tr>
-                    })}
-                    {files.length === 0 &&
-                        <Tr>
-                            <Td colSpan={8}>
-                                <Bullseye>
-                                    <EmptyState variant={EmptyStateVariant.sm}>
-                                        <EmptyStateHeader titleText="No 
results found" icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2" />
-                                    </EmptyState>
-                                </Bullseye>
-                            </Td>
-                        </Tr>
-                    }
-                </Tbody>
-            </Table>
+                                </Td>
+                                <Td>
+                                    {needCommit(file.lastUpdate) &&
+                                        <Tooltip content="Updated after last 
commit" position={"right"}>
+                                            <Label 
color="grey">{getDate(file.lastUpdate)}</Label>
+                                        </Tooltip>
+                                    }
+                                    {!needCommit(file.lastUpdate) && 
getDate(file.lastUpdate)}
+                                </Td>
+                                <Td modifier={"fitContent"}>
+                                    {canDeleteFiles() &&
+                                        <Button style={{padding: '0'}} 
variant={"plain"}
+                                                
isDisabled={['application.properties', 
'project-compose.yaml'].includes(file.name)}
+                                                onClick={e =>
+                                                    
useFileStore.setState({file: file, operation: "delete"})
+                                        }>
+                                            <DeleteIcon/>
+                                        </Button>
+                                    }
+                                    <Tooltip content="Download source" 
position={"bottom-end"}>
+                                        <Button size="sm" variant="plain" 
icon={<DownloadIcon/>} onClick={e => download(file)}/>
+                                    </Tooltip>
+                                </Td>
+                            </Tr>
+                        })}
+                        {files.length === 0 &&
+                            <Tr>
+                                <Td colSpan={8}>
+                                    <Bullseye>
+                                        <EmptyState 
variant={EmptyStateVariant.sm}>
+                                            <EmptyStateHeader titleText="No 
results found" icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2" />
+                                        </EmptyState>
+                                    </Bullseye>
+                                </Td>
+                            </Tr>
+                        }
+                    </Tbody>
+                </Table>
+            </div>
             <CreateFileModal types={types}/>
             <UploadFileModal projectId={project.projectId} isOpen={operation 
=== 'upload'} />
             <DeleteFileModal />
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
index 1ee0a5ff..2cdf25e3 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
@@ -20,123 +20,104 @@ import {
     Button,
     EmptyState,
     EmptyStateIcon,
-    EmptyStateVariant, Flex, FlexItem,
+    EmptyStateVariant,
+    Flex,
+    FlexItem,
     Panel,
     PanelHeader,
     Text,
-    Switch, TextContent, TextVariants, PageSection, EmptyStateHeader,
+    Switch,
+    TextContent,
+    TextVariants,
+    PageSection,
+    EmptyStateHeader,
+    Card,
+    CardBody,
+    Divider,
+    Tabs,
+    Tab,
+    TabTitleText,
+    ToggleGroup, ToggleGroupItem,
 } from '@patternfly/react-core';
 import '../../designer/karavan.css';
 import {RunnerInfoTraceModal} from "./RunnerInfoTraceModal";
 import {
-       Tbody,
-       Td,
-       Th,
-       Thead,
-       Tr
+    Tbody,
+    Td,
+    Th,
+    Thead,
+    Tr
 } from '@patternfly/react-table';
 import {
-       Table
+    Table
 } from '@patternfly/react-table/deprecated';
 import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
-import {useProjectStore} from "../../api/ProjectStore";
+import {useProjectStore, useStatusesStore} from "../../api/ProjectStore";
 import {shallow} from "zustand/shallow";
+import {InfoContainer} from "../dashboard/InfoContainer";
+import {InfoMemory} from "../dashboard/InfoMemory";
+import {InfoContext} from "../dashboard/InfoContext";
+import {TraceTable} from "./TraceTable";
 
 
-export function TraceTab () {
+export function TraceTab() {
 
-    const [refreshTrace, setRefreshTrace, trace] = useProjectStore((state) =>
-        [state.refreshTrace, state.setRefreshTrace, state.trace], shallow);
-    const [nodes, setNodes] = useState([{}]);
-    const [isOpen, setIsOpen] = useState<boolean>(false);
-    const [exchangeId, setExchangeId] = useState<string>('');
+    const [project, refreshTrace, setRefreshTrace, camelStatuses] = 
useProjectStore((state) =>
+        [state.project, state.refreshTrace, state.setRefreshTrace, 
state.camelStatuses], shallow);
+    const [containers] = useStatusesStore((state) => [state.containers], 
shallow);
+    const [containerName, setContainerName] = useState<string>();
 
-    function closeModal() {
-        setIsOpen(false);
-    }
-
-    function getNodes(exchangeId: string): any[] {
-        const traces: any[] = trace?.trace?.traces || [];
-        return traces
-            .filter(t => t.message?.exchangeId === exchangeId)
-            .sort((a, b) => a.uid > b.uid ? 1 : -1);
-    }
-
-    function getNode(exchangeId: string): any {
-        const traces: any[] = trace?.trace?.traces || [];
-        return traces
-            .filter(t => t.message?.exchangeId === exchangeId)
-            .sort((a, b) => a.uid > b.uid ? 1 : -1)
-            .at(0);
-    }
-
-    const traces: any[] = (trace?.trace?.traces || []).sort((a: any, b: any) 
=> b.uid > a.uid ? 1 : -1);
-    const exchanges: any[] = Array.from(new Set((traces).map((item: any) => 
item?.message?.exchangeId)));
+    const camelContainers = containers
+        .filter(c => c.projectId === project.projectId && ['devmode', 
'project'].includes(c.type));
     return (
         <PageSection className="project-tab-panel" padding={{default: 
"padding"}}>
-            {isOpen && <RunnerInfoTraceModal isOpen={isOpen} 
exchangeId={exchangeId} nodes={nodes} onClose={closeModal}/>}
             <Panel>
                 <PanelHeader>
-                    <Flex direction={{default: "row"}} 
justifyContent={{default:"justifyContentFlexEnd"}}>
+                    <Flex direction={{default: "row"}} 
justifyContent={{default: "justifyContentSpaceBetween"}}>
                         <FlexItem>
-                            <TextContent>
-                                <Text component={TextVariants.h6}>Auto 
refresh</Text>
-                            </TextContent>
+                            <Flex direction={{default: "row"}}>
+                                <FlexItem>
+                                    <TextContent>
+                                        <Text 
component={TextVariants.h6}>Container</Text>
+                                    </TextContent>
+                                </FlexItem>
+                                <FlexItem>
+                                    <ToggleGroup>
+                                        {camelContainers.map((containerStatus, 
index) =>
+                                            <ToggleGroupItem
+                                                
text={containerStatus.containerName}
+                                                isSelected={containerName === 
containerStatus.containerName}
+                                                onChange={(_, selected) => {
+                                                    if (selected) {
+                                                        
setContainerName(containerStatus.containerName);
+                                                    }
+                                                }}
+                                            />
+                                        )}
+                                    </ToggleGroup>
+                                </FlexItem>
+                            </Flex>
                         </FlexItem>
                         <FlexItem>
-                            <Switch aria-label="refresh"
-                                    id="refresh"
-                                    isChecked={refreshTrace}
-                                     onChange={(_, checked) => 
setRefreshTrace(checked)}
-                            />
+                            <Flex direction={{default: "row"}}>
+                                <FlexItem>
+                                    <TextContent>
+                                        <Text component={TextVariants.h6}>Auto 
refresh</Text>
+                                    </TextContent>
+                                </FlexItem>
+                                <FlexItem>
+                                    <Switch aria-label="refresh"
+                                            id="refresh"
+                                            isChecked={refreshTrace}
+                                            onChange={(_, checked) => 
setRefreshTrace(checked)}
+                                    />
+                                </FlexItem>
+                            </Flex>
                         </FlexItem>
                     </Flex>
                 </PanelHeader>
             </Panel>
-            <Table aria-label="Files" variant={"compact"} className={"table"}>
-                <Thead>
-                    <Tr>
-                        <Th key='uid' width={30}>UID</Th>
-                        <Th key='exchangeId' width={40}>ExchangeId</Th>
-                        <Th key='timestamp' width={30}>Updated</Th>
-                    </Tr>
-                </Thead>
-                <Tbody>
-                    {exchanges.map(exchangeId => {
-                        const node = getNode(exchangeId);
-                        return <Tr key={node?.uid}>
-                            <Td>
-                                {node?.uid}
-                            </Td>
-                            <Td>
-                                <Button style={{padding: '0'}} variant={"link"}
-                                        onClick={e => {
-                                            setExchangeId(exchangeId);
-                                            setNodes(getNodes(exchangeId));
-                                            setIsOpen(true);
-                                        }}>
-                                    {exchangeId}
-                                </Button>
-                            </Td>
-                            <Td>
-                                {node ? new 
Date(node?.timestamp).toISOString() : ""}
-                            </Td>
-
-                        </Tr>
-                    })}
-                    {exchanges.length === 0 &&
-                        <Tr>
-                            <Td colSpan={8}>
-                                <Bullseye>
-                                    <EmptyState variant={EmptyStateVariant.sm}>
-                                        <EmptyStateHeader titleText="No 
results found" icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2" />
-                                    </EmptyState>
-                                </Bullseye>
-                            </Td>
-                        </Tr>
-                    }
-                </Tbody>
-            </Table>
+            <TraceTable containerName={containerName}/>
         </PageSection>
-    );
+    )
 }
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTable.tsx
similarity index 80%
copy from karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
copy to karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTable.tsx
index 1ee0a5ff..8977825a 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTable.tsx
@@ -24,7 +24,7 @@ import {
     Panel,
     PanelHeader,
     Text,
-    Switch, TextContent, TextVariants, PageSection, EmptyStateHeader,
+    Switch, TextContent, TextVariants, PageSection, EmptyStateHeader, Card, 
CardBody, Divider,
 } from '@patternfly/react-core';
 import '../../designer/karavan.css';
 import {RunnerInfoTraceModal} from "./RunnerInfoTraceModal";
@@ -41,12 +41,19 @@ import {
 import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
 import {useProjectStore} from "../../api/ProjectStore";
 import {shallow} from "zustand/shallow";
+import {InfoContainer} from "../dashboard/InfoContainer";
+import {InfoMemory} from "../dashboard/InfoMemory";
+import {InfoContext} from "../dashboard/InfoContext";
+import {ContainerStatus} from "../../api/ProjectModels";
 
+interface Props {
+    containerName?: string
+}
 
-export function TraceTab () {
+export function TraceTable (props: Props) {
 
-    const [refreshTrace, setRefreshTrace, trace] = useProjectStore((state) =>
-        [state.refreshTrace, state.setRefreshTrace, state.trace], shallow);
+    const [refreshTrace, camelTraces] = useProjectStore((state) =>
+        [state.refreshTrace, state.camelTraces], shallow);
     const [nodes, setNodes] = useState([{}]);
     const [isOpen, setIsOpen] = useState<boolean>(false);
     const [exchangeId, setExchangeId] = useState<string>('');
@@ -70,29 +77,15 @@ export function TraceTab () {
             .at(0);
     }
 
+    const camelStatus = camelTraces.filter(s => s.containerName === 
props.containerName).at(0);
+    const traceValue = camelStatus?.statuses?.filter(x => x.name === 
'trace').at(0);
+    const trace: any = traceValue ? JSON.parse(traceValue?.status || '') : {};
+
     const traces: any[] = (trace?.trace?.traces || []).sort((a: any, b: any) 
=> b.uid > a.uid ? 1 : -1);
     const exchanges: any[] = Array.from(new Set((traces).map((item: any) => 
item?.message?.exchangeId)));
     return (
-        <PageSection className="project-tab-panel" padding={{default: 
"padding"}}>
+        <>
             {isOpen && <RunnerInfoTraceModal isOpen={isOpen} 
exchangeId={exchangeId} nodes={nodes} onClose={closeModal}/>}
-            <Panel>
-                <PanelHeader>
-                    <Flex direction={{default: "row"}} 
justifyContent={{default:"justifyContentFlexEnd"}}>
-                        <FlexItem>
-                            <TextContent>
-                                <Text component={TextVariants.h6}>Auto 
refresh</Text>
-                            </TextContent>
-                        </FlexItem>
-                        <FlexItem>
-                            <Switch aria-label="refresh"
-                                    id="refresh"
-                                    isChecked={refreshTrace}
-                                     onChange={(_, checked) => 
setRefreshTrace(checked)}
-                            />
-                        </FlexItem>
-                    </Flex>
-                </PanelHeader>
-            </Panel>
             <Table aria-label="Files" variant={"compact"} className={"table"}>
                 <Thead>
                     <Tr>
@@ -137,6 +130,6 @@ export function TraceTab () {
                     }
                 </Tbody>
             </Table>
-        </PageSection>
+        </>
     );
 }
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx 
b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index 02ed39d7..c5d96a50 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -33,8 +33,6 @@ import {useProjectsStore, useProjectStore} from 
"../api/ProjectStore";
 import {MainToolbar} from "../designer/MainToolbar";
 import {Project, ProjectType} from "../api/ProjectModels";
 import {shallow} from "zustand/shallow";
-import {useParams} from "react-router-dom";
-import {KaravanApi} from "../api/KaravanApi";
 
 export function ProjectsPage () {
 
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx 
b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
index 2beb4ed4..94371de7 100644
--- a/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/templates/TemplatesPage.tsx
@@ -12,7 +12,7 @@ import {
     EmptyState,
     EmptyStateVariant,
     EmptyStateIcon,
-    EmptyStateHeader
+    EmptyStateHeader, Panel, PanelMain, PanelMainBody
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
diff --git 
a/karavan-web/karavan-app/src/test/java/org/apache/camel/karavan/infinispan/DataGridTest.java
 
b/karavan-web/karavan-app/src/test/java/org/apache/camel/karavan/infinispan/DataGridTest.java
index 930186cd..34d8ee93 100644
--- 
a/karavan-web/karavan-app/src/test/java/org/apache/camel/karavan/infinispan/DataGridTest.java
+++ 
b/karavan-web/karavan-app/src/test/java/org/apache/camel/karavan/infinispan/DataGridTest.java
@@ -33,9 +33,9 @@ public class DataGridTest {
 
     @Test
     public void testCamelStatuses() throws InterruptedException {
-        CamelStatus cs = new CamelStatus("test1", "container1", 
CamelStatus.Name.context, "", "dev");
-        infinispanService.saveCamelStatus(cs);
-        List<CamelStatus> list = 
infinispanService.getCamelStatusesByEnv("dev", CamelStatus.Name.context);
-        assertEquals(1, list.size());
+//        CamelStatus cs = new CamelStatus("test1", "container1", 
CamelStatus.Name.context, "", "dev");
+//        infinispanService.saveCamelStatus(cs);
+//        List<CamelStatus> list = 
infinispanService.getCamelStatusesByEnv("dev", CamelStatus.Name.context);
+//        assertEquals(1, list.size());
     }
 }


Reply via email to