You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2022/10/28 00:16:50 UTC

[camel-karavan] branch main updated (6019daf -> 17e5855)

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

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


    from 6019daf  Fix for minikube
     new 6b62e17  Bump versions for native compilation
     new 8073ff9  Redesigned status monitoring
     new 407a510  Bump version in karavan-core
     new 0072d05  Rename karavan.config to karavan.default
     new 7a6bb5b  Fix #501
     new 72707e7  Get DeploymentStatus fron new API
     new 441ac2a  Get PodStatus from new API
     new 17e5855  First version of Dashboard

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


Summary of changes:
 karavan-app/src/main/docker/Dockerfile.multistage  |   6 +-
 .../camel/karavan/api/ConfigurationResource.java   |  26 +-
 .../camel/karavan/api/KubernetesResource.java      | 203 ++++++++--------
 .../apache/camel/karavan/api/StatusResource.java   |  20 +-
 .../karavan/informer/DeploymentEventHandler.java   |  98 ++++++++
 .../PipelineRunEventHandler.java}                  |  70 ++++--
 .../camel/karavan/informer/PodEventHandler.java    |  90 +++++++
 .../karavan/informer/ServiceEventHandler.java      |  91 +++++++
 .../camel/karavan/model/DeploymentStatus.java      |  72 ++++--
 .../apache/camel/karavan/model/Environment.java    |  57 +++++
 .../org/apache/camel/karavan/model/GroupedKey.java |   2 -
 .../camel/karavan/model/KaravanConfiguration.java  |  24 --
 .../apache/camel/karavan/model/PipelineStatus.java |  19 +-
 .../org/apache/camel/karavan/model/PodStatus.java  |  51 +++-
 .../org/apache/camel/karavan/model/Project.java    |  12 +-
 .../camel/karavan/model/ProjectStoreSchema.java    |   2 +-
 .../apache/camel/karavan/model/ServiceStatus.java  | 111 +++++++++
 .../camel/karavan/service/GeneratorService.java    |  10 +-
 .../apache/camel/karavan/service/GitService.java   |   2 +-
 .../{KaravanService.java => ImportService.java}    |  25 +-
 .../camel/karavan/service/InfinispanService.java   | 150 +++++++++---
 .../camel/karavan/service/KaravanService.java      | 111 +++------
 .../camel/karavan/service/KubernetesService.java   | 147 ++++-------
 .../camel/karavan/service/StatusService.java       |  21 +-
 .../camel/karavan/watcher/DeploymentWatcher.java   |  59 -----
 .../apache/camel/karavan/watcher/PodWatcher.java   |  40 ---
 .../src/main/resources/application.properties      |  36 +--
 karavan-app/src/main/webapp/package-lock.json      |   6 +-
 karavan-app/src/main/webapp/src/Main.tsx           |  48 ++--
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx |  57 ++++-
 .../main/webapp/src/dashboard/DashboardPage.tsx    | 268 +++++++++++++++++++++
 karavan-app/src/main/webapp/src/index.css          |  50 +++-
 .../main/webapp/src/projects/ProjectDashboard.tsx  |   1 -
 .../src/main/webapp/src/projects/ProjectInfo.tsx   |  22 +-
 .../src/main/webapp/src/projects/ProjectModels.ts  |  19 +-
 .../src/main/webapp/src/projects/ProjectPage.tsx   |   3 +-
 .../src/main/webapp/src/projects/ProjectsPage.tsx  |  31 ++-
 karavan-core/package-lock.json                     |   4 +-
 38 files changed, 1422 insertions(+), 642 deletions(-)
 create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/informer/DeploymentEventHandler.java
 rename karavan-app/src/main/java/org/apache/camel/karavan/{watcher/PipelineRunWatcher.java => informer/PipelineRunEventHandler.java} (52%)
 create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/informer/PodEventHandler.java
 create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/informer/ServiceEventHandler.java
 create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/Environment.java
 delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/KaravanConfiguration.java
 create mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/model/ServiceStatus.java
 copy karavan-app/src/main/java/org/apache/camel/karavan/service/{KaravanService.java => ImportService.java} (84%)
 delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
 delete mode 100644 karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
 create mode 100644 karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx


[camel-karavan] 01/08: Bump versions for native compilation

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 6b62e17fff5be668dbb4172f13c13ad550f26f4e
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Oct 26 15:48:03 2022 -0400

    Bump versions for native compilation
---
 karavan-app/src/main/docker/Dockerfile.multistage | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/karavan-app/src/main/docker/Dockerfile.multistage b/karavan-app/src/main/docker/Dockerfile.multistage
index 56603bb..92f7f2f 100644
--- a/karavan-app/src/main/docker/Dockerfile.multistage
+++ b/karavan-app/src/main/docker/Dockerfile.multistage
@@ -14,7 +14,7 @@
 #  limitations under the License.
 
 ## Stage 1 : build with maven builder image with native capabilities
-FROM quay.io/quarkus/ubi-quarkus-native-image:21.3.0-java11 AS build-gen
+FROM quay.io/quarkus/ubi-quarkus-native-image:22.3.0-java11 AS build-gen
 
 ## rsync required for npm to build frontend
 USER root
@@ -54,10 +54,10 @@ RUN npm run build
 FROM build-gen as build-app
 COPY --chown=quarkus:quarkus --from=build-node /code/karavan-core/lib/ /code/karavan-core/lib/
 COPY --chown=quarkus:quarkus --from=build-node /code/karavan-core/node_modules/ /code/karavan-core/node_modules/
-RUN ./mvnw clean package -Pnative -f karavan-app
+RUN ./mvnw clean package -Pnative -f karavan-app -Dquarkus.profile=public
 
 ## Stage 4 : create the docker final image
-FROM quay.io/quarkus/quarkus-distroless-image:1.0
+FROM quay.io/quarkus/quarkus-distroless-image:2.0
 COPY --chown=nonroot --from=build-app /code/karavan-app/target/*-runner /deployments/application
 
 EXPOSE 8080


[camel-karavan] 08/08: First version of Dashboard

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 17e5855590bafd18dd80604d25389d2b852513b6
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 20:16:37 2022 -0400

    First version of Dashboard
---
 .../camel/karavan/api/ConfigurationResource.java   |  11 +-
 .../camel/karavan/api/KubernetesResource.java      |  19 ++
 .../apache/camel/karavan/api/StatusResource.java   |  14 +-
 .../DeploymentEventHandler.java                    |  19 +-
 .../PipelineRunEventHandler.java                   |   2 +-
 .../{watcher => informer}/PodEventHandler.java     |   8 +-
 .../karavan/informer/ServiceEventHandler.java      |  91 +++++++
 .../camel/karavan/model/DeploymentStatus.java      |  29 ++-
 .../camel/karavan/model/ProjectStoreSchema.java    |   2 +-
 .../apache/camel/karavan/model/ServiceStatus.java  | 111 +++++++++
 .../camel/karavan/service/InfinispanService.java   |  25 +-
 .../camel/karavan/service/KubernetesService.java   |  18 +-
 karavan-app/src/main/webapp/src/Main.tsx           |  47 ++--
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx |  24 +-
 .../main/webapp/src/dashboard/DashboardPage.tsx    | 268 +++++++++++++++++++++
 karavan-app/src/main/webapp/src/index.css          |  50 +++-
 .../main/webapp/src/projects/ProjectDashboard.tsx  |   1 -
 .../src/main/webapp/src/projects/ProjectInfo.tsx   |   3 -
 .../src/main/webapp/src/projects/ProjectModels.ts  |  12 +
 .../src/main/webapp/src/projects/ProjectsPage.tsx  |  21 +-
 20 files changed, 712 insertions(+), 63 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
index 7980e61..0c34dad 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
@@ -50,7 +50,16 @@ public class ConfigurationResource {
                 Map.of(
                         "version", version,
                         "environment", environment,
-                        "environments", infinispanService.getEnvironments().stream().map(e -> e.getName()).collect(Collectors.toList()),
+                        "environments", infinispanService.getEnvironments().stream()
+                                .map(e -> e.getName())
+                                        .sorted((o1, o2) -> {
+                                            if (o1.startsWith("dev") && o2.startsWith("test")) return -1;
+                                            if (o1.startsWith("test") && o2.startsWith("dev")) return 1;
+                                            if (o1.startsWith("test") && o2.startsWith("prod")) return -1;
+                                            if (o1.startsWith("prod") && o2.startsWith("test")) return 1;
+                                            return o1.compareTo(o2);
+                                        })
+                                .collect(Collectors.toList()),
                         "runtime", runtime
                 )
         ).build();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index ebe0cc1..d1553cb 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -22,6 +22,7 @@ import io.vertx.mutiny.core.eventbus.Message;
 import org.apache.camel.karavan.model.DeploymentStatus;
 import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
+import org.apache.camel.karavan.model.ServiceStatus;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -98,6 +99,15 @@ public class KubernetesResource {
         return Response.ok(kubernetesService.getContainerLog(name, kubernetesService.getNamespace())).build();
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/deployment")
+    public List<DeploymentStatus> getAllDeploymentStatuses() throws Exception {
+        return infinispanService.getDeploymentStatuses().stream()
+                .sorted(Comparator.comparing(DeploymentStatus::getName))
+                .collect(Collectors.toList());
+    }
+
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/deployment/{env}")
@@ -128,6 +138,15 @@ public class KubernetesResource {
         return Response.ok().build();
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/service")
+    public List<ServiceStatus> getAllServiceStatuses() throws Exception {
+        return infinispanService.getServiceStatuses().stream()
+                .sorted(Comparator.comparing(ServiceStatus::getName))
+                .collect(Collectors.toList());
+    }
+
     @GET
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/pod/{env}")
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
index f869b26..5f88aec 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
@@ -19,6 +19,7 @@ package org.apache.camel.karavan.api;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.CamelStatus;
 import org.apache.camel.karavan.model.DeploymentStatus;
+import org.apache.camel.karavan.model.Environment;
 import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.StatusService;
@@ -31,6 +32,7 @@ import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
+import java.util.Optional;
 
 @Path("/api/status")
 public class StatusResource {
@@ -59,12 +61,14 @@ public class StatusResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/deployment/{name}/{env}")
     public Response getDeploymentStatus(@PathParam("name") String name, @PathParam("env") String env) {
-        DeploymentStatus status = infinispanService.getDeploymentStatus(name, env);
-        if (status != null) {
-            return Response.ok(status).build();
-        } else {
-            return Response.noContent().build();
+        Optional<Environment> environment = infinispanService.getEnvironments().stream().filter(e -> e.getName().equals(env)).findFirst();
+        if (environment.isPresent()){
+            DeploymentStatus status = infinispanService.getDeploymentStatus(name, environment.get().getNamespace(), environment.get().getCluster());
+            if (status != null) {
+                return Response.ok(status).build();
+            }
         }
+        return Response.noContent().build();
     }
 
     @GET
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/informer/DeploymentEventHandler.java
similarity index 76%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/informer/DeploymentEventHandler.java
index b4f4323..7ba4793 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/informer/DeploymentEventHandler.java
@@ -1,8 +1,9 @@
-package org.apache.camel.karavan.watcher;
+package org.apache.camel.karavan.informer;
 
 import io.fabric8.kubernetes.api.model.apps.Deployment;
 import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import org.apache.camel.karavan.model.DeploymentStatus;
+import org.apache.camel.karavan.model.Environment;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
@@ -24,6 +25,14 @@ public class DeploymentEventHandler implements ResourceEventHandler<Deployment>
             LOGGER.info("onAdd " + deployment.getMetadata().getName());
             DeploymentStatus ds = getDeploymentStatus(deployment);
             infinispanService.saveDeploymentStatus(ds);
+            // TODO: Delete after UI design
+            infinispanService.saveEnvironment(new Environment("test", "test", "karavan-test", "test-pipeline"));
+            infinispanService.saveEnvironment(new Environment("prod", "prod", "karavan-prod", "prod-pipeline"));
+            DeploymentStatus ds1 = getDeploymentStatus(deployment);
+            ds1.setEnv("test");
+            ds1.setNamespace("karavan-test");
+            ds1.setCluster("demo.cluster");
+            infinispanService.saveDeploymentStatus(ds1);
         } catch (Exception e){
             LOGGER.error(e.getMessage());
         }
@@ -35,6 +44,11 @@ public class DeploymentEventHandler implements ResourceEventHandler<Deployment>
             LOGGER.info("onUpdate " + newDeployment.getMetadata().getName());
             DeploymentStatus ds = getDeploymentStatus(newDeployment);
             infinispanService.saveDeploymentStatus(ds);
+            // TODO: Delete after UI design
+            DeploymentStatus ds1 = getDeploymentStatus(newDeployment);
+            ds1.setEnv("test");
+            ds1.setCluster("demo.cluster");
+            infinispanService.saveDeploymentStatus(ds1);
         } catch (Exception e){
             LOGGER.error(e.getMessage());
         }
@@ -47,6 +61,7 @@ public class DeploymentEventHandler implements ResourceEventHandler<Deployment>
             DeploymentStatus ds = new DeploymentStatus(
                     deployment.getMetadata().getName(),
                     deployment.getMetadata().getNamespace(),
+                    kubernetesService.getCluster(),
                     kubernetesService.environment);
             infinispanService.deleteDeploymentStatus(ds);
         } catch (Exception e){
@@ -65,6 +80,7 @@ public class DeploymentEventHandler implements ResourceEventHandler<Deployment>
                     deployment.getMetadata().getName(),
                     deployment.getMetadata().getNamespace(),
                     kubernetesService.environment,
+                    kubernetesService.getCluster(),
                     imageName,
                     deployment.getSpec().getReplicas(),
                     deployment.getStatus().getReadyReplicas(),
@@ -75,6 +91,7 @@ public class DeploymentEventHandler implements ResourceEventHandler<Deployment>
             return new DeploymentStatus(
                     deployment.getMetadata().getName(),
                     deployment.getMetadata().getNamespace(),
+                    kubernetesService.getCluster(),
                     kubernetesService.environment);
         }
     }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/informer/PipelineRunEventHandler.java
similarity index 99%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/informer/PipelineRunEventHandler.java
index b5d59e9..3254e26 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/informer/PipelineRunEventHandler.java
@@ -1,4 +1,4 @@
-package org.apache.camel.karavan.watcher;
+package org.apache.camel.karavan.informer;
 
 import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRun;
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/informer/PodEventHandler.java
similarity index 91%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/informer/PodEventHandler.java
index 8d3af7c..4e68379 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/informer/PodEventHandler.java
@@ -1,4 +1,4 @@
-package org.apache.camel.karavan.watcher;
+package org.apache.camel.karavan.informer;
 
 import io.fabric8.kubernetes.api.model.Pod;
 import io.fabric8.kubernetes.api.model.PodCondition;
@@ -27,6 +27,9 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
             LOGGER.info("onAdd " + pod.getMetadata().getName());
             PodStatus ps = getPodStatus(pod);
             infinispanService.savePodStatus(ps);
+            // TODO: Delete after UI design
+            ps.setEnv("test");
+            infinispanService.savePodStatus(ps);
         } catch (Exception e){
             LOGGER.error(e.getMessage());
         }
@@ -38,6 +41,9 @@ public class PodEventHandler implements ResourceEventHandler<Pod> {
             LOGGER.info("onUpdate " + newPod.getMetadata().getName());
             PodStatus ps = getPodStatus(newPod);
             infinispanService.savePodStatus(ps);
+            // TODO: Delete after UI design
+            ps.setEnv("test");
+            infinispanService.savePodStatus(ps);
         } catch (Exception e){
             LOGGER.error(e.getMessage());
         }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/informer/ServiceEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/informer/ServiceEventHandler.java
new file mode 100644
index 0000000..dc7382a
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/informer/ServiceEventHandler.java
@@ -0,0 +1,91 @@
+package org.apache.camel.karavan.informer;
+
+import io.fabric8.kubernetes.api.model.Service;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
+import org.apache.camel.karavan.model.ServiceStatus;
+import org.apache.camel.karavan.model.Environment;
+import org.apache.camel.karavan.service.InfinispanService;
+import org.apache.camel.karavan.service.KubernetesService;
+import org.jboss.logging.Logger;
+
+public class ServiceEventHandler implements ResourceEventHandler<Service> {
+
+    private static final Logger LOGGER = Logger.getLogger(ServiceEventHandler.class.getName());
+    private InfinispanService infinispanService;
+    private KubernetesService kubernetesService;
+
+    public ServiceEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
+        this.infinispanService = infinispanService;
+        this.kubernetesService = kubernetesService;
+    }
+
+    @Override
+    public void onAdd(Service service) {
+        try {
+            LOGGER.info("onAdd " + service.getMetadata().getName());
+            ServiceStatus ds = getServiceStatus(service);
+            infinispanService.saveServiceStatus(ds);
+            // TODO: Delete after UI design
+            infinispanService.saveEnvironment(new Environment("test", "demo", "karavan-test", "test-pipeline"));
+            ServiceStatus ds1 = getServiceStatus(service);
+            ds1.setEnv("test");
+            ds1.setCluster("demo.cluster");
+            infinispanService.saveServiceStatus(ds1);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(Service oldService, Service newService) {
+        try {
+            LOGGER.info("onUpdate " + newService.getMetadata().getName());
+            ServiceStatus ds = getServiceStatus(newService);
+            infinispanService.saveServiceStatus(ds);
+            // TODO: Delete after UI design
+            ServiceStatus ds1 = getServiceStatus(newService);
+            ds1.setEnv("test");
+            ds1.setCluster("demo.cluster");
+            infinispanService.saveServiceStatus(ds1);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(Service service, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + service.getMetadata().getName());
+            ServiceStatus ds = new ServiceStatus(
+                    service.getMetadata().getName(),
+                    service.getMetadata().getNamespace(),
+                    kubernetesService.getCluster(),
+                    kubernetesService.environment);
+            infinispanService.deleteServiceStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    public ServiceStatus getServiceStatus(Service service) {
+        try {
+            return new ServiceStatus(
+                    service.getMetadata().getName(),
+                    service.getMetadata().getNamespace(),
+                    kubernetesService.environment,
+                    kubernetesService.getCluster(),
+                    service.getSpec().getPorts().get(0).getPort(),
+                    service.getSpec().getPorts().get(0).getTargetPort().getIntVal(),
+                    service.getSpec().getClusterIP(),
+                    service.getSpec().getType()
+            );
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage());
+            return new ServiceStatus(
+                    service.getMetadata().getName(),
+                    service.getMetadata().getNamespace(),
+                    kubernetesService.getCluster(),
+                    kubernetesService.environment);
+        }
+    }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
index f0baa9e..fe50512 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
@@ -1,6 +1,5 @@
 package org.apache.camel.karavan.model;
 
-import org.infinispan.protostream.annotations.ProtoDoc;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
@@ -13,17 +12,20 @@ public class DeploymentStatus {
     @ProtoField(number = 3)
     String env;
     @ProtoField(number = 4)
-    String image;
+    String cluster;
     @ProtoField(number = 5)
-    Integer replicas;
+    String image;
     @ProtoField(number = 6)
-    Integer readyReplicas;
+    Integer replicas;
     @ProtoField(number = 7)
+    Integer readyReplicas;
+    @ProtoField(number = 8)
     Integer unavailableReplicas;
 
-    public DeploymentStatus(String name, String namespace, String env) {
+    public DeploymentStatus(String name, String namespace, String cluster, String env) {
         this.name = name;
         this.namespace = namespace;
+        this.cluster = cluster;
         this.env = env;
         this.image = "";
         this.replicas = 0;
@@ -32,16 +34,21 @@ public class DeploymentStatus {
     }
 
     @ProtoFactory
-    public DeploymentStatus(String name, String namespace, String env, String image, Integer replicas, Integer readyReplicas, Integer unavailableReplicas) {
+    public DeploymentStatus(String name, String namespace, String env, String cluster, String image, Integer replicas, Integer readyReplicas, Integer unavailableReplicas) {
         this.name = name;
-        this.env = env;
         this.namespace = namespace;
+        this.env = env;
+        this.cluster = cluster;
         this.image = image;
         this.replicas = replicas;
         this.readyReplicas = readyReplicas;
         this.unavailableReplicas = unavailableReplicas;
     }
 
+    public String getId() {
+        return name + ":" + namespace + ":" + cluster;
+    }
+
     public String getName() {
         return name;
     }
@@ -97,4 +104,12 @@ public class DeploymentStatus {
     public void setUnavailableReplicas(Integer unavailableReplicas) {
         this.unavailableReplicas = unavailableReplicas;
     }
+
+    public String getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(String cluster) {
+        this.cluster = cluster;
+    }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
index 6a94007..c9b1e7a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
@@ -6,7 +6,7 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
 @AutoProtoSchemaBuilder(
         includeClasses = {
                 GroupedKey.class, Project.class, ProjectFile.class, PipelineStatus.class, CamelStatus.class, DeploymentStatus.class,
-                PodStatus.class, Environment.class
+                PodStatus.class, Environment.class, ServiceStatus.class
         },
         schemaPackageName = "karavan")
 public interface ProjectStoreSchema extends GeneratedSchema {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/ServiceStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/ServiceStatus.java
new file mode 100644
index 0000000..38dbde5
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/ServiceStatus.java
@@ -0,0 +1,111 @@
+package org.apache.camel.karavan.model;
+
+import org.infinispan.protostream.annotations.ProtoFactory;
+import org.infinispan.protostream.annotations.ProtoField;
+
+public class ServiceStatus {
+    public static final String CACHE = "service_statuses";
+    @ProtoField(number = 1)
+    String name;
+    @ProtoField(number = 2)
+    String namespace;
+    @ProtoField(number = 3)
+    String env;
+    @ProtoField(number = 4)
+    String cluster;
+    @ProtoField(number = 5)
+    Integer port;
+    @ProtoField(number = 6)
+    Integer targetPort;
+    @ProtoField(number = 7)
+    String clusterIP;
+    @ProtoField(number = 8)
+    String type;
+
+    @ProtoFactory
+    public ServiceStatus(String name, String namespace, String env, String cluster, Integer port, Integer targetPort, String clusterIP, String type) {
+        this.name = name;
+        this.namespace = namespace;
+        this.env = env;
+        this.cluster = cluster;
+        this.port = port;
+        this.targetPort = targetPort;
+        this.clusterIP = clusterIP;
+        this.type = type;
+    }
+
+    public ServiceStatus(String name, String namespace, String cluster, String env) {
+        this.name = name;
+        this.namespace = namespace;
+        this.env = env;
+        this.cluster = cluster;
+    }
+
+    public String getId() {
+        return name + ":" + namespace + ":" + cluster;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getEnv() {
+        return env;
+    }
+
+    public void setEnv(String env) {
+        this.env = env;
+    }
+
+    public String getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(String cluster) {
+        this.cluster = cluster;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Integer getTargetPort() {
+        return targetPort;
+    }
+
+    public void setTargetPort(Integer targetPort) {
+        this.targetPort = targetPort;
+    }
+
+    public String getClusterIP() {
+        return clusterIP;
+    }
+
+    public void setClusterIP(String clusterIP) {
+        this.clusterIP = clusterIP;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 3fddb8f..aa4026a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -25,6 +25,7 @@ import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.model.ProjectFile;
+import org.apache.camel.karavan.model.ServiceStatus;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.infinispan.Cache;
 import org.infinispan.client.hotrod.RemoteCache;
@@ -56,6 +57,7 @@ public class InfinispanService {
     BasicCache<GroupedKey, DeploymentStatus> deploymentStatuses;
     BasicCache<GroupedKey, PodStatus> podStatuses;
     BasicCache<GroupedKey, CamelStatus> camelStatuses;
+    BasicCache<GroupedKey, ServiceStatus> serviceStatuses;
     BasicCache<String, String> kamelets;
     BasicCache<String, Environment> environments;
 
@@ -95,6 +97,7 @@ public class InfinispanService {
             pipelineStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PipelineStatus.CACHE, builder.build());
             deploymentStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(DeploymentStatus.CACHE, builder.build());
             podStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PodStatus.CACHE, builder.build());
+            serviceStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(ServiceStatus.CACHE, builder.build());
             camelStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
             kamelets = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Kamelet.CACHE, builder.build());
 
@@ -107,6 +110,7 @@ public class InfinispanService {
             pipelineStatuses = cacheManager.administration().getOrCreateCache(PipelineStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PipelineStatus.CACHE)));
             deploymentStatuses = cacheManager.administration().getOrCreateCache(DeploymentStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, DeploymentStatus.CACHE)));
             podStatuses = cacheManager.administration().getOrCreateCache(PodStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PodStatus.CACHE)));
+            serviceStatuses = cacheManager.administration().getOrCreateCache(ServiceStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, ServiceStatus.CACHE)));
             camelStatuses = cacheManager.administration().getOrCreateCache(CamelStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, CamelStatus.CACHE)));
             kamelets = cacheManager.administration().getOrCreateCache(Kamelet.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Kamelet.CACHE)));
         }
@@ -180,16 +184,17 @@ public class InfinispanService {
         pipelineStatuses.remove(GroupedKey.create(status.getProjectId(), status.getEnv()));
     }
 
-    public DeploymentStatus getDeploymentStatus(String name, String env) {
-        return deploymentStatuses.get(GroupedKey.create(name, env));
+    public DeploymentStatus getDeploymentStatus(String name, String namespace, String cluster) {
+        String deploymentId = name + ":" + namespace + ":" + cluster;
+        return deploymentStatuses.get(GroupedKey.create(name, deploymentId));
     }
 
     public void saveDeploymentStatus(DeploymentStatus status) {
-        deploymentStatuses.put(GroupedKey.create(status.getName(), status.getEnv()), status);
+        deploymentStatuses.put(GroupedKey.create(status.getName(), status.getId()), status);
     }
 
     public void deleteDeploymentStatus(DeploymentStatus status) {
-        deploymentStatuses.remove(GroupedKey.create(status.getName(), status.getEnv()));
+        deploymentStatuses.remove(GroupedKey.create(status.getName(), status.getId()));
     }
 
     public List<DeploymentStatus> getDeploymentStatuses() {
@@ -210,6 +215,18 @@ public class InfinispanService {
         }
     }
 
+    public void saveServiceStatus(ServiceStatus status) {
+        serviceStatuses.put(GroupedKey.create(status.getName(), status.getId()), status);
+    }
+
+    public void deleteServiceStatus(ServiceStatus status) {
+        serviceStatuses.remove(GroupedKey.create(status.getName(), status.getId()));
+    }
+
+    public List<ServiceStatus> getServiceStatuses() {
+        return serviceStatuses.values().stream().collect(Collectors.toList());
+    }
+
     public List<PodStatus> getPodStatuses(String projectId, String env) {
         if (cacheManager == null) {
             QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) podStatuses);
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index b896013..c6fdea4 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -20,15 +20,12 @@ import io.fabric8.kubernetes.api.model.ObjectMeta;
 import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
 import io.fabric8.kubernetes.api.model.Pod;
 import io.fabric8.kubernetes.api.model.Secret;
+import io.fabric8.kubernetes.api.model.Service;
 import io.fabric8.kubernetes.api.model.apps.Deployment;
 import io.fabric8.kubernetes.client.DefaultKubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClient;
-import io.fabric8.kubernetes.client.Watch;
-import io.fabric8.kubernetes.client.dsl.Informable;
 import io.fabric8.kubernetes.client.dsl.LogWatch;
 import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
-import io.fabric8.kubernetes.client.informers.SharedInformerEventListener;
-import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
 import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
 import io.fabric8.tekton.client.DefaultTektonClient;
@@ -40,19 +37,18 @@ import io.fabric8.tekton.pipeline.v1beta1.PipelineRunBuilder;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpec;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRunSpecBuilder;
 import io.fabric8.tekton.pipeline.v1beta1.WorkspaceBindingBuilder;
-import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.mutiny.core.eventbus.EventBus;
+import org.apache.camel.karavan.informer.ServiceEventHandler;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.watcher.DeploymentEventHandler;
-import org.apache.camel.karavan.watcher.PipelineRunEventHandler;
-import org.apache.camel.karavan.watcher.PodEventHandler;
+import org.apache.camel.karavan.informer.DeploymentEventHandler;
+import org.apache.camel.karavan.informer.PipelineRunEventHandler;
+import org.apache.camel.karavan.informer.PodEventHandler;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.event.Observes;
 import javax.enterprise.inject.Produces;
 import javax.inject.Inject;
 import java.io.IOException;
@@ -110,6 +106,10 @@ public class KubernetesService {
             deploymentInformer.addEventHandlerWithResyncPeriod(new DeploymentEventHandler(infinispanService, this),30 * 1000L);
             informers.add(deploymentInformer);
 
+            SharedIndexInformer<Service> serviceInformer = kubernetesClient().services().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            serviceInformer.addEventHandlerWithResyncPeriod(new ServiceEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(serviceInformer);
+
             SharedIndexInformer<PipelineRun> pipelineRunInformer = tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
             pipelineRunInformer.addEventHandlerWithResyncPeriod(new PipelineRunEventHandler(infinispanService, this),30 * 1000L);
             informers.add(pipelineRunInformer);
diff --git a/karavan-app/src/main/webapp/src/Main.tsx b/karavan-app/src/main/webapp/src/Main.tsx
index 4d7acb5..f69f8d8 100644
--- a/karavan-app/src/main/webapp/src/Main.tsx
+++ b/karavan-app/src/main/webapp/src/Main.tsx
@@ -1,9 +1,7 @@
 import React from 'react';
 import {
     Page,
-    ModalVariant,
     Button,
-    Modal,
     Alert,
     AlertActionCloseButton,
     Flex,
@@ -13,7 +11,7 @@ import {
 } from '@patternfly/react-core';
 import {KaravanApi} from "./api/KaravanApi";
 import {SsoApi} from "./api/SsoApi";
-import {KameletApi, Kamelets} from "karavan-core/lib/api/KameletApi";
+import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import './designer/karavan.css';
 import {ConfigurationPage} from "./config/ConfigurationPage";
 import {KameletsPage} from "./kamelets/KameletsPage";
@@ -28,10 +26,12 @@ import {ProjectPage} from "./projects/ProjectPage";
 import UserIcon from "@patternfly/react-icons/dist/js/icons/user-icon";
 import ProjectsIcon from "@patternfly/react-icons/dist/js/icons/repository-icon";
 import KameletsIcon from "@patternfly/react-icons/dist/js/icons/registry-icon";
+import DashboardIcon from "@patternfly/react-icons/dist/js/icons/tachometer-alt-icon";
 import EipIcon from "@patternfly/react-icons/dist/js/icons/topology-icon";
 import ComponentsIcon from "@patternfly/react-icons/dist/js/icons/module-icon";
 import ConfigurationIcon from "@patternfly/react-icons/dist/js/icons/cogs-icon";
 import {MainLogin} from "./MainLogin";
+import {DashboardPage} from "./dashboard/DashboardPage";
 
 class ToastMessage {
     id: string = ''
@@ -124,7 +124,7 @@ export class Main extends React.Component<Props, State> {
 
     getData() {
         KaravanApi.getConfiguration((config: any) => {
-            this.setState({ config: config });
+            this.setState({config: config});
         });
         this.updateKamelets();
         this.updateComponents();
@@ -157,16 +157,18 @@ export class Main extends React.Component<Props, State> {
 
     pageNav = () => {
         const pages: MenuItem[] = [
-            // new MenuItem("dashboard", "Dashboard", <TachometerAltIcon/>),
+            new MenuItem("dashboard", "Dashboard", <DashboardIcon/>),
             new MenuItem("projects", "Projects", <ProjectsIcon/>),
             new MenuItem("eip", "Enterprise Integration Patterns", <EipIcon/>),
             new MenuItem("kamelets", "Kamelets", <KameletsIcon/>),
             new MenuItem("components", "Components", <ComponentsIcon/>),
             new MenuItem("configuration", "Configuration", <ConfigurationIcon/>)
         ]
-        return (<Flex className="nav-buttons" direction={{default: "column"}} style={{height:"100%"}} spaceItems={{default:"spaceItemsNone"}}>
-            <FlexItem alignSelf={{default:"alignSelfCenter"}}>
-                <Tooltip className="logo-tooltip" content={"Apache Camel Karavan " + this.state.config.version} position={"right"}>
+        return (<Flex className="nav-buttons" direction={{default: "column"}} style={{height: "100%"}}
+                      spaceItems={{default: "spaceItemsNone"}}>
+            <FlexItem alignSelf={{default: "alignSelfCenter"}}>
+                <Tooltip className="logo-tooltip" content={"Apache Camel Karavan " + this.state.config.version}
+                         position={"right"}>
                     {Icon()}
                 </Tooltip>
             </FlexItem>
@@ -180,11 +182,11 @@ export class Main extends React.Component<Props, State> {
                     </Tooltip>
                 </FlexItem>
             )}
-            <FlexItem flex={{default:"flex_2"}} alignSelf={{default:"alignSelfCenter"}}>
+            <FlexItem flex={{default: "flex_2"}} alignSelf={{default: "alignSelfCenter"}}>
                 <Divider/>
             </FlexItem>
             {KaravanApi.authType !== 'public' &&
-                <FlexItem alignSelf={{default:"alignSelfCenter"}}>
+                <FlexItem alignSelf={{default: "alignSelfCenter"}}>
                     <Popover
                         aria-label="Current user"
                         position={"right-end"}
@@ -194,7 +196,7 @@ export class Main extends React.Component<Props, State> {
                         shouldOpen={tip => this.setState({showUser: true})}
                         headerContent={<div>{KaravanApi.me.userName}</div>}
                         bodyContent={
-                            <Flex direction={{default:"row"}}>
+                            <Flex direction={{default: "row"}}>
                                 {KaravanApi.me.roles && Array.isArray(KaravanApi.me.roles)
                                     && KaravanApi.me.roles
                                         .filter((r: string) => ['administrator', 'developer', 'viewer'].includes(r))
@@ -221,20 +223,28 @@ export class Main extends React.Component<Props, State> {
     getMain() {
         return (
             <>
-                <Flex direction={{default:"row"}} style={{width: "100%", height:"100%"}} alignItems={{default:"alignItemsStretch"}} spaceItems={{ default: 'spaceItemsNone' }}>
+                <Flex direction={{default: "row"}} style={{width: "100%", height: "100%"}}
+                      alignItems={{default: "alignItemsStretch"}} spaceItems={{default: 'spaceItemsNone'}}>
                     <FlexItem>
                         {this.pageNav()}
                     </FlexItem>
-                    <FlexItem flex={{default:"flex_2"}} style={{height:"100%"}}>
+                    <FlexItem flex={{default: "flex_2"}} style={{height: "100%"}}>
                         {this.state.pageId === 'projects' &&
                             <ProjectsPage key={this.state.request}
                                           onSelect={this.onProjectSelect}
                                           toast={this.toast}
                                           config={this.state.config}/>}
-                        {this.state.pageId === 'project' && this.state.project && <ProjectPage project={this.state.project} config={this.state.config}/>}
+                        {this.state.pageId === 'project' && this.state.project &&
+                            <ProjectPage project={this.state.project} config={this.state.config}/>}
+                        {this.state.pageId === 'dashboard' && <DashboardPage key={this.state.request}
+                                                                             onSelect={this.onProjectSelect}
+                                                                             toast={this.toast}
+                                                                             config={this.state.config}/>}
                         {this.state.pageId === 'configuration' && <ConfigurationPage/>}
-                        {this.state.pageId === 'kamelets' && <KameletsPage dark={false} onRefresh={this.updateKamelets}/>}
-                        {this.state.pageId === 'components' && <ComponentsPage dark={false} onRefresh={this.updateComponents}/>}
+                        {this.state.pageId === 'kamelets' &&
+                            <KameletsPage dark={false} onRefresh={this.updateKamelets}/>}
+                        {this.state.pageId === 'components' &&
+                            <ComponentsPage dark={false} onRefresh={this.updateComponents}/>}
                         {this.state.pageId === 'eip' && <EipPage dark={false}/>}
                     </FlexItem>
                 </Flex>
@@ -246,11 +256,12 @@ export class Main extends React.Component<Props, State> {
         return (
             <Page className="karavan">
                 {KaravanApi.authType === undefined && <Bullseye className="loading-page">
-                    <Spinner className="spinner" isSVG diameter="140px" aria-label="Loading..." />
+                    <Spinner className="spinner" isSVG diameter="140px" aria-label="Loading..."/>
                     <div className="logo-placeholder">{Icon()}</div>
                 </Bullseye>}
                 {(KaravanApi.isAuthorized || KaravanApi.authType === 'public') && this.getMain()}
-                {!KaravanApi.isAuthorized && KaravanApi.authType === 'basic' && <MainLogin config={this.state.config} onLogin={this.onLogin}/>}
+                {!KaravanApi.isAuthorized && KaravanApi.authType === 'basic' &&
+                    <MainLogin config={this.state.config} onLogin={this.onLogin}/>}
                 {this.state.alerts.map((e: ToastMessage) => (
                     <Alert key={e.id} className="main-alert" variant={e.variant} title={e.title}
                            timeout={e.variant === "success" ? 1000 : 2000}
diff --git a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index ad3b9a6..b2cb1af 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -5,7 +5,7 @@ import {
     PipelineStatus,
     PodStatus,
     Project,
-    ProjectFile
+    ProjectFile, ServiceStatus
 } from "../projects/ProjectModels";
 import {Buffer} from 'buffer';
 import {SsoApi} from "./SsoApi";
@@ -297,6 +297,28 @@ export class KaravanApi {
         });
     }
 
+    static async getAllServiceStatuses(after: (statuses: ServiceStatus[]) => void) {
+        instance.get('/api/kubernetes/service')
+            .then(res => {
+                if (res.status === 200) {
+                    after(res.data);
+                }
+            }).catch(err => {
+            console.log(err);
+        });
+    }
+
+    static async getAllDeploymentStatuses(after: (statuses: DeploymentStatus[]) => void) {
+        instance.get('/api/kubernetes/deployment')
+            .then(res => {
+                if (res.status === 200) {
+                    after(res.data);
+                }
+            }).catch(err => {
+            console.log(err);
+        });
+    }
+
     static async getDeploymentStatuses(env: string, after: (statuses: DeploymentStatus[]) => void) {
         instance.get('/api/kubernetes/deployment/' + env)
             .then(res => {
diff --git a/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx b/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx
new file mode 100644
index 0000000..d893bf7
--- /dev/null
+++ b/karavan-app/src/main/webapp/src/dashboard/DashboardPage.tsx
@@ -0,0 +1,268 @@
+import React from 'react';
+import {
+    Badge,
+    Button,
+    Flex,
+    FlexItem, HelperText, HelperTextItem, Label, LabelGroup,
+    OverflowMenu,
+    OverflowMenuContent,
+    OverflowMenuGroup,
+    OverflowMenuItem,
+    PageSection,
+    Text,
+    TextContent,
+    TextInput,
+    Toolbar,
+    ToolbarContent,
+    ToolbarItem, Tooltip
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {MainToolbar} from "../MainToolbar";
+import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
+import {DeploymentStatus, Project, ServiceStatus} from "../projects/ProjectModels";
+import {TableComposable, TableVariant, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
+import {camelIcon, CamelUi} from "../designer/utils/CamelUi";
+import {KaravanApi} from "../api/KaravanApi";
+import Icon from "../Logo";
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+
+interface Props {
+    config: any,
+    onSelect: (project: Project) => void
+    toast: (title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'default') => void
+}
+
+interface State {
+    projects: Project[],
+    deploymentStatuses: DeploymentStatus[],
+    serviceStatuses: ServiceStatus[],
+    isCreateModalOpen: boolean,
+    isDeleteModalOpen: boolean,
+    isCopy: boolean,
+    projectToCopy?: Project,
+    projectToDelete?: Project,
+    filter: string,
+    name: string,
+    description: string,
+    projectId: string,
+}
+
+export class DashboardPage extends React.Component<Props, State> {
+
+    public state: State = {
+        projects: [],
+        deploymentStatuses: [],
+        serviceStatuses: [],
+        isCreateModalOpen: false,
+        isDeleteModalOpen: false,
+        isCopy: false,
+        filter: '',
+        name: '',
+        description: '',
+        projectId: '',
+    };
+    interval: any;
+
+    componentDidMount() {
+        this.interval = setInterval(() => this.onGetProjects(), 1300);
+    }
+
+    componentWillUnmount() {
+        clearInterval(this.interval);
+    }
+
+    onGetProjects = () => {
+        KaravanApi.getConfiguration((config: any) => {
+            KaravanApi.getProjects((projects: Project[]) => {
+                this.setState({projects: projects})
+            });
+            KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => {
+                this.setState({deploymentStatuses: statuses});
+            });
+            KaravanApi.getAllServiceStatuses((statuses: ServiceStatus[]) => {
+                this.setState({serviceStatuses: statuses});
+            });
+        });
+
+    }
+
+    tools = () => (<Toolbar id="toolbar-group-types">
+        <ToolbarContent>
+            <ToolbarItem>
+                <Button variant="link" icon={<RefreshIcon/>} onClick={e => this.onGetProjects()}/>
+            </ToolbarItem>
+            <ToolbarItem>
+                <TextInput className="text-field" type="search" id="search" name="search"
+                           autoComplete="off" placeholder="Search by name"
+                           value={this.state.filter}
+                           onChange={e => this.setState({filter: e})}/>
+            </ToolbarItem>
+        </ToolbarContent>
+    </Toolbar>);
+
+    title = () => (<TextContent>
+        <Text component="h1">Dashboard</Text>
+    </TextContent>);
+
+    getEnvironments(): string []{
+        return this.props.config.environments && Array.isArray(this.props.config.environments) ? Array.from(this.props.config.environments) : [];
+    }
+
+    getDeploymentEnvironments(name: string): [string, boolean] [] {
+        const deps = this.state.deploymentStatuses;
+        return this.getEnvironments().map(e => {
+            const env: string = e as string;
+            const dep = deps.find(d => d.name === name && d.env === env);
+            const deployed: boolean = dep !== undefined && dep.replicas > 0 && dep.replicas === dep.readyReplicas;
+            return [env, deployed];
+        });
+    }
+
+    getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {
+        const deps = this.state.deploymentStatuses;
+        return this.getEnvironments().map(e => {
+            const env: string = e as string;
+            const dep = deps.find(d => d.name === name && d.env === env);
+            return [env, dep];
+        });
+    }
+
+    getServiceByEnvironments(name: string): [string, ServiceStatus | undefined] [] {
+        const services = this.state.serviceStatuses;
+        return this.getEnvironments().map(e => {
+            const env: string = e as string;
+            const service = services.find(d => d.name === name && d.env === env);
+            return [env, service];
+        });
+    }
+
+    getProject(name: string): Project | undefined {
+        return this.state.projects.filter(p => p.name === name)?.at(0);
+    }
+
+    isKaravan(name: string): boolean {
+        return this.state.projects.findIndex(p => p.projectId === name) > 0;
+    }
+
+    getReplicasPanel(deploymentStatus?: DeploymentStatus) {
+        if (deploymentStatus) {
+            const readyReplicas = deploymentStatus.readyReplicas ? deploymentStatus.readyReplicas : 0;
+            const ok = (deploymentStatus && readyReplicas > 0
+                && (deploymentStatus.unavailableReplicas === 0 || deploymentStatus.unavailableReplicas === undefined || deploymentStatus.unavailableReplicas === null)
+                && deploymentStatus?.replicas === readyReplicas);
+            return (
+                <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
+                    <FlexItem>
+                        <LabelGroup numLabels={3}>
+                            <Tooltip content={"Ready Replicas / Replicas"} position={"left"}>
+                                <Label className="table-label" icon={ok ? <UpIcon/> : <DownIcon/>}
+                                       color={ok ? "green" : "grey"}>{"Replicas: " + readyReplicas + " / " + deploymentStatus.replicas}</Label>
+                            </Tooltip>
+                            {deploymentStatus.unavailableReplicas > 0 &&
+                                <Tooltip content={"Unavailable replicas"} position={"right"}>
+                                    <Label icon={<DownIcon/>} color={"red"}>{deploymentStatus.unavailableReplicas}</Label>
+                                </Tooltip>
+                            }
+                        </LabelGroup>
+                    </FlexItem>
+                </Flex>
+            )
+        } else {
+            return (<Label icon={<DownIcon/>} color={"grey"}>n/a</Label>);
+        }
+    }
+
+    render() {
+        const deployments = Array.from(new Set(this.state.deploymentStatuses.filter(d => d.name.toLowerCase().includes(this.state.filter)).map(d => d.name)));
+        return (
+            <PageSection className="kamelet-section dashboard-page" padding={{default: 'noPadding'}}>
+                <PageSection className="tools-section" padding={{default: 'noPadding'}}>
+                    <MainToolbar title={this.title()} tools={this.tools()}/>
+                </PageSection>
+                <PageSection isFilled className="kamelets-page">
+                    <TableComposable aria-label="Projects" variant={TableVariant.compact}>
+                        <Thead>
+                            <Tr>
+                                <Th key='type'>Type</Th>
+                                <Th key='name'>Deployment</Th>
+                                <Th key='description'>Project/Description</Th>
+                                <Th key='environment'>Environment</Th>
+                                <Th key='namespace'>Namespace</Th>
+                                <Th key='replicas'>Replicas</Th>
+                                <Th key='services'>Services</Th>
+                                <Th key='camel'>Camel Health</Th>
+                                {/*<Th key='action'></Th>*/}
+                            </Tr>
+                        </Thead>
+                        <Tbody>
+                            {deployments.map(deployment => (
+                                <Tr key={deployment}>
+                                    <Td  style={{verticalAlign:"middle"}}>
+                                        {this.isKaravan(deployment) ? Icon("icon") : CamelUi.getIconFromSource(camelIcon)}
+                                    </Td>
+                                    <Td  style={{ verticalAlign:"middle"}}>
+                                        <Button style={{padding: '6px'}} variant={"link"}>{deployment}</Button>
+                                    </Td>
+                                    <Td  style={{verticalAlign:"middle"}}>
+                                        <HelperText>
+                                            <HelperTextItem>{this.getProject(deployment)?.name || ""}</HelperTextItem>
+                                            <HelperTextItem>{this.getProject(deployment)?.description || ""}</HelperTextItem>
+                                        </HelperText>
+                                    </Td>
+                                    <Td  >
+                                        <Flex direction={{default: "column"}}>
+                                            {this.getDeploymentEnvironments(deployment).map(value => (
+                                                <FlexItem className="badge-flex-item" key={value[0]}><Badge className="badge"
+                                                    isRead={!value[1]}>{value[0]}</Badge></FlexItem>
+                                            ))}
+                                        </Flex>
+                                    </Td>
+                                    <Td >
+                                        <Flex direction={{default: "column"}}>
+                                            {this.getDeploymentByEnvironments(deployment).map(value => (
+                                                <FlexItem className="badge-flex-item" key={value[0]}>
+                                                    <Label variant={"outline"}>{value[1]?.namespace || "n/a"}</Label>
+                                                </FlexItem>
+                                            ))}
+                                        </Flex>
+                                    </Td>
+                                    <Td >
+                                        <Flex direction={{default: "column"}}>
+                                            {this.getDeploymentByEnvironments(deployment).map(value => (
+                                                <FlexItem className="badge-flex-item" key={value[0]}>{this.getReplicasPanel(value[1])}</FlexItem>
+                                            ))}
+                                        </Flex>
+                                    </Td>
+                                    <Td>
+                                        <Flex direction={{default: "column"}}>
+                                            {this.getServiceByEnvironments(deployment).map(value => (
+                                                <FlexItem className="badge-flex-item" key={value[0]}>
+                                                    <Label variant={"outline"}>{value[1] ? (value[1]?.port + " -> " + value[1]?.targetPort) : "n/a"}</Label>
+                                                </FlexItem>
+                                            ))}
+                                        </Flex>
+                                    </Td>
+                                    <Td modifier={"fitContent"}>
+                                        <Flex direction={{default: "column"}}>
+                                            {this.getServiceByEnvironments(deployment).map(value => (
+                                                <FlexItem key={value[0]}>
+                                                    <LabelGroup numLabels={4} className="camel-label-group">
+                                                        <Label className="table-label" icon={false ? <UpIcon/> : <DownIcon/>}>{"Context"}</Label>
+                                                        <Label className="table-label" icon={false ? <UpIcon/> : <DownIcon/>}>{"Consumer"}</Label>
+                                                        <Label className="table-label" icon={false ? <UpIcon/> : <DownIcon/>}>{"Routes"}</Label>
+                                                        <Label className="table-label" icon={false ? <UpIcon/> : <DownIcon/>}>{"Registry"}</Label>
+                                                    </LabelGroup>
+                                                </FlexItem>
+                                            ))}
+                                        </Flex>
+                                    </Td>
+                                </Tr>
+                            ))}
+                        </Tbody>
+                    </TableComposable>
+                </PageSection>
+            </PageSection>
+        )
+    }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/webapp/src/index.css b/karavan-app/src/main/webapp/src/index.css
index 9ccffd9..f170c70 100644
--- a/karavan-app/src/main/webapp/src/index.css
+++ b/karavan-app/src/main/webapp/src/index.css
@@ -111,6 +111,19 @@
   margin: auto;
 }
 
+.karavan .projects-page .badge {
+  font-size: 14px;
+  font-weight: 400;
+  padding: 4px 8px 4px 8px;
+}
+
+.karavan .projects-page .runtime-badge {
+  min-width: 18px;
+  font-size: 14px;
+  font-weight: 400;
+  padding: 2px 7px 2px 7px;
+}
+
 .karavan .projects-page .pf-m-link {
   font-size: 14px;
 }
@@ -205,11 +218,6 @@
   padding: 0;
 }
 
-.karavan .runtime-badge {
-  min-width: 18px;
-  padding: 0;
-}
-
 .create-file-form .pf-c-form__group {
     grid-template-columns: 80px 1fr !important;
 }
@@ -222,6 +230,38 @@
   overflow-wrap: anywhere;
 }
 
+/*Dashboard*/
+.karavan .dashboard-page .pf-m-link {
+  font-size: 14px;
+}
+
+.karavan .dashboard-page .icon {
+  height: 28px;
+  width: 28px;
+  margin: auto;
+}
+
+.karavan .dashboard-page .badge {
+  font-size: 14px;
+  font-weight: 400;
+  padding: 4px 8px 4px 8px;
+}
+
+.karavan .dashboard-page .table-label {
+  font-size: 14px;
+  padding: 2px 6px 2px 4px;
+}
+
+.karavan .dashboard-page .badge-flex-item {
+  margin-bottom: 3px;
+  margin-top: 3px;
+}
+
+.karavan .dashboard-page .camel-label-group .pf-c-label-group__list {
+    flex-wrap: nowrap;
+}
+
+
 .karavan .loading-page .spinner {
   position: absolute;
 }
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
index b3dffe3..0fb9f80 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectDashboard.tsx
@@ -8,7 +8,6 @@ import {
 import '../designer/karavan.css';
 import {KaravanApi} from "../api/KaravanApi";
 import {DeploymentStatus, Project, ProjectFileTypes} from "./ProjectModels";
-import {ChartDonutThreshold} from "@patternfly/react-charts";
 
 interface Props {
     project: Project,
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index acbb7b2..d8e25fd 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -40,7 +40,6 @@ interface State {
     deleteEntity?: 'pod' | 'deployment',
     deleteEntityName?: string,
     deleteEntityEnv?: string,
-    environments: string[],
     environment: string,
     key?: string,
 }
@@ -54,8 +53,6 @@ export class ProjectInfo extends React.Component<Props, State> {
         isBuilding: false,
         isRolling: false,
         showDeleteConfirmation: false,
-        environments: this.props.config.environments && Array.isArray(this.props.config.environments)
-            ? Array.from(this.props.config.environments) : [],
         environment: this.props.config.environment
     };
     interval: any;
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectModels.ts b/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
index 2f6eeb9..455182e 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
@@ -24,12 +24,24 @@ export class DeploymentStatus {
     name: string = '';
     env: string = '';
     namespace: string = '';
+    cluster: string = '';
     image: string = '';
     replicas: number = 0;
     readyReplicas: number = 0;
     unavailableReplicas: number = 0;
 }
 
+export class ServiceStatus {
+    name: string = '';
+    env: string = '';
+    namespace: string = '';
+    cluster: string = '';
+    port: string = '';
+    targetPort: string = '';
+    clusterIP: string = '';
+    type: string = '';
+}
+
 export class PodStatus {
     name: string = '';
     phase: string = '';
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
index 744c19f..3f7560c 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
@@ -214,15 +214,22 @@ export class ProjectsPage extends React.Component<Props, State> {
         )
     }
 
-    isDeployed(projectId: string): boolean{
-        const ds = this.state.deploymentStatuses.find(ds => ds.name === projectId);
-        return ds ? (ds.replicas > 0 && ds.replicas === ds.readyReplicas) : false;
+    getEnvironments(): string []{
+        return this.props.config.environments && Array.isArray(this.props.config.environments) ? Array.from(this.props.config.environments) : [];
+    }
+
+    getDeploymentByEnvironments(name: string): [string, DeploymentStatus | undefined] [] {
+        const deps = this.state.deploymentStatuses;
+        return this.getEnvironments().map(e => {
+            const env: string = e as string;
+            const dep = deps.find(d => d.name === name && d.env === env);
+            return [env, dep];
+        });
     }
 
     render() {
         const runtime = this.props.config?.runtime ? this.props.config.runtime : "QUARKUS";
         const projects = this.state.projects.filter(p => p.name.toLowerCase().includes(this.state.filter) || p.description.toLowerCase().includes(this.state.filter));
-        const environment: string = this.props.config.environment;
         return (
             <PageSection className="kamelet-section projects-page" padding={{default: 'noPadding'}}>
                 <PageSection className="tools-section" padding={{default: 'noPadding'}}>
@@ -263,7 +270,11 @@ export class ProjectsPage extends React.Component<Props, State> {
                                     </Td>
                                     <Td noPadding style={{width:"180px"}}>
                                         <Flex direction={{default: "row"}}>
-                                            <FlexItem key={"dev"}><Badge isRead={!this.isDeployed(project.projectId)}>{"dev"}</Badge></FlexItem>
+                                            {this.getDeploymentByEnvironments(project.projectId).map(value => (
+                                                <FlexItem className="badge-flex-item" key={value[0]}>
+                                                    <Badge className="badge"isRead={!value[1]}>{value[0]}</Badge>
+                                                </FlexItem>
+                                            ))}
                                         </Flex>
                                     </Td>
                                     <Td isActionCell>


[camel-karavan] 02/08: Redesigned status monitoring

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 8073ff981e52b6669d190aed12a950de9a18228f
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Oct 26 20:22:46 2022 -0400

    Redesigned status monitoring
---
 .../camel/karavan/api/ConfigurationResource.java   |  17 ++-
 .../camel/karavan/api/KubernetesResource.java      | 165 ++++++++-------------
 .../apache/camel/karavan/api/StatusResource.java   |   8 +-
 .../camel/karavan/model/DeploymentStatus.java      |  64 ++++----
 .../apache/camel/karavan/model/Environment.java    |  57 +++++++
 .../org/apache/camel/karavan/model/GroupedKey.java |   2 -
 .../camel/karavan/model/KaravanConfiguration.java  |  24 ---
 .../apache/camel/karavan/model/PipelineStatus.java |  19 ++-
 .../org/apache/camel/karavan/model/PodStatus.java  |  17 ++-
 .../org/apache/camel/karavan/model/Project.java    |  12 +-
 .../camel/karavan/model/ProjectStoreSchema.java    |   2 +-
 .../apache/camel/karavan/service/GitService.java   |   2 +-
 .../{KaravanService.java => ImportService.java}    |  23 +--
 .../camel/karavan/service/InfinispanService.java   |  99 +++++++++----
 .../camel/karavan/service/KaravanService.java      | 108 +++-----------
 .../camel/karavan/service/KubernetesService.java   | 131 +++++++---------
 .../camel/karavan/service/StatusService.java       |  21 ++-
 .../camel/karavan/watcher/DeploymentWatcher.java   |  59 +++++---
 .../camel/karavan/watcher/PipelineRunWatcher.java  |   7 +-
 .../apache/camel/karavan/watcher/PodWatcher.java   |  12 +-
 .../src/main/resources/application.properties      |  28 +---
 karavan-app/src/main/webapp/package-lock.json      |   6 +-
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx |   4 +-
 .../src/main/webapp/src/projects/ProjectInfo.tsx   |   2 +-
 24 files changed, 422 insertions(+), 467 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
index 9d0b9ed..cf17e9b 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
@@ -16,7 +16,7 @@
  */
 package org.apache.camel.karavan.api;
 
-import org.apache.camel.karavan.model.KaravanConfiguration;
+import org.apache.camel.karavan.service.InfinispanService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 
 import javax.inject.Inject;
@@ -34,8 +34,14 @@ public class ConfigurationResource {
     @ConfigProperty(name = "karavan.version")
     String version;
 
+    @ConfigProperty(name = "karavan.environment")
+    String environment;
+
+    @ConfigProperty(name = "karavan.config.runtime")
+    String runtime;
+
     @Inject
-    KaravanConfiguration configuration;
+    InfinispanService infinispanService;
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
@@ -43,10 +49,9 @@ public class ConfigurationResource {
         return Response.ok(
                 Map.of(
                         "version", version,
-                        "environments", configuration.environments().stream()
-                                        .filter(e -> e.active())
-                                .map(e -> e.name()).collect(Collectors.toList()),
-                        "runtime", configuration.runtime()
+                        "environment", environment,
+                        "environments", infinispanService.getEnvironments().stream().map(e -> e.getName()).collect(Collectors.toList()),
+                        "runtime", runtime
                 )
         ).build();
     }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index e7586a8..a817434 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -17,27 +17,28 @@
 package org.apache.camel.karavan.api;
 
 import io.smallrye.mutiny.Multi;
-import io.vertx.core.json.JsonObject;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import io.vertx.mutiny.core.eventbus.Message;
-import org.apache.camel.karavan.model.KaravanConfiguration;
+import org.apache.camel.karavan.model.DeploymentStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import javax.inject.Inject;
 import javax.ws.rs.Consumes;
 import javax.ws.rs.DELETE;
 import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
 import javax.ws.rs.POST;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import java.util.Optional;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
 
 @Path("/api/kubernetes")
 public class KubernetesResource {
@@ -51,162 +52,124 @@ public class KubernetesResource {
     @Inject
     KubernetesService kubernetesService;
 
-    @Inject
-    KaravanConfiguration configuration;
+    @ConfigProperty(name = "karavan.environment")
+    String environment;
+
+    @ConfigProperty(name = "karavan.pipeline")
+    String pipeline;
+
 
     private static final Logger LOGGER = Logger.getLogger(KubernetesResource.class.getName());
 
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/{environment}")
-    public Project createPipeline(@PathParam("environment") String environment, Project project) throws Exception {
+    @Path("/pipeline/{env}")
+    public Project createPipeline(@PathParam("env") String env, Project project) throws Exception {
         Project p = infinispanService.getProject(project.getProjectId());
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            kubernetesService.createPipelineRun(project, env.get().pipeline(), env.get().namespace());
-            p.setDeployed(true); // TODO:  Replace this update by updating from Pipeline
-            infinispanService.saveProject(p); // TODO:  Replace this update by updating from Pipeline
-        }
+        kubernetesService.createPipelineRun(project, pipeline, kubernetesService.getNamespace());
+//            p.setDeployed(true); // TODO:  Replace this update by updating from Pipeline
+//        infinispanService.saveProject(p); // TODO:  Replace this update by updating from Pipeline
         return p;
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/{environment}/{name}")
-    public Response getPipeline(@PathParam("environment") String environment,
-                        @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getPipelineRun(name, env.get().namespace())).build();
-        } else {
-            return Response.noContent().build();
-        }
+    @Path("/pipeline/{env}/{name}")
+    public Response getPipeline(@PathParam("env") String env,
+                                @PathParam("name") String name) throws Exception {
+        return Response.ok(kubernetesService.getPipelineRun(name, kubernetesService.getNamespace())).build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/log/{environment}/{name}")
-    public Response getPipelineLog(@PathParam("environment") String environment,
-                        @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getPipelineRunLog(name, env.get().namespace())).build();
-        } else {
-            return Response.noContent().build();
-        }
+    @Path("/pipeline/log/{env}/{name}")
+    public Response getPipelineLog(@PathParam("env") String env,
+                                   @PathParam("name") String name) throws Exception {
+        return Response.ok(kubernetesService.getPipelineRunLog(name, kubernetesService.getNamespace())).build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/container/log/{environment}/{name}")
-    public Response getContainerLog(@PathParam("environment") String environment,
-                                   @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getContainerLog(name, env.get().namespace())).build();
-        } else {
-            return Response.noContent().build();
-        }
+    @Path("/container/log/{env}/{name}")
+    public Response getContainerLog(@PathParam("env") String env,
+                                    @PathParam("name") String name) throws Exception {
+        return Response.ok(kubernetesService.getContainerLog(name, kubernetesService.getNamespace())).build();
+    }
+
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/deployment/")
+    public List<DeploymentStatus> getAll() throws Exception {
+        return infinispanService.getDeploymentStatuses().stream()
+                .sorted(Comparator.comparing(DeploymentStatus::getName))
+                .collect(Collectors.toList());
     }
 
     @POST
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/deployment/rollout/{environment}/{name}")
-    public Response rollout(@PathParam("environment") String environment, @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            kubernetesService.rolloutDeployment(name, env.get().namespace());
-            return Response.ok().build();
-        }
-        return Response.noContent().build();
+    @Path("/deployment/rollout/{env}/{name}")
+    public Response rollout(@PathParam("env") String env, @PathParam("name") String name) throws Exception {
+        kubernetesService.rolloutDeployment(name, kubernetesService.getNamespace());
+        return Response.ok().build();
     }
 
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/deployment/{environment}/{name}")
-    public Response deleteDeployment(@PathParam("environment") String environment, @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            kubernetesService.deleteDeployment(name, env.get().namespace());
+    @Path("/deployment/{env}/{name}")
+    public Response deleteDeployment(@PathParam("env") String env, @PathParam("name") String name) throws Exception {
+        kubernetesService.deleteDeployment(name, kubernetesService.getNamespace());
 //            Project p = infinispanService.getProject(name); // TODO: p.setDeployed(false) than karavan keeps pod/camel statuses up forever
 //            p.setDeployed(false);
 //            infinispanService.saveProject(p);
-            return Response.ok().build();
-        }
-        return Response.noContent().build();
+        return Response.ok().build();
     }
 
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
-    @Path("/pod/{environment}/{name}")
-    public Response deletePod(@PathParam("environment") String environment, @PathParam("name") String name) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            kubernetesService.deletePod(name, env.get().namespace());
-            return Response.ok().build();
-        }
-        return Response.noContent().build();
+    @Path("/pod/{env}/{name}")
+    public Response deletePod(@PathParam("env") String env, @PathParam("name") String name) throws Exception {
+        kubernetesService.deletePod(name, kubernetesService.getNamespace());
+        return Response.ok().build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/imagetag/{environment}/{projectId}")
-    public Response getProjectImageTags(@PathParam("environment") String environment, @PathParam("projectId") String projectId) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getProjectImageTags(projectId, env.get().namespace())).build();
-        }
-        return Response.noContent().build();
+    @Path("/imagetag/{env}/{projectId}")
+    public Response getProjectImageTags(@PathParam("env") String env, @PathParam("projectId") String projectId) throws Exception {
+        return Response.ok(kubernetesService.getProjectImageTags(projectId, kubernetesService.getNamespace())).build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/configmap/{environment}")
-    public Response getConfigMaps(@PathParam("environment") String environment) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getConfigMaps(env.get().namespace())).build();
-        }
-        return Response.noContent().build();
+    @Path("/configmap/{env}")
+    public Response getConfigMaps(@PathParam("env") String env) throws Exception {
+        return Response.ok(kubernetesService.getConfigMaps(kubernetesService.getNamespace())).build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/secret/{environment}")
-    public Response getSecrets(@PathParam("environment") String environment) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getSecrets(env.get().namespace())).build();
-        }
-        return Response.noContent().build();
+    @Path("/secret/{env}")
+    public Response getSecrets(@PathParam("env") String env) throws Exception {
+        return Response.ok(kubernetesService.getSecrets(kubernetesService.getNamespace())).build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/service/{environment}")
-    public Response getServices(@PathParam("environment") String environment) throws Exception {
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-            return Response.ok(kubernetesService.getServices(env.get().namespace())).build();
-        }
-        return Response.noContent().build();
+    @Path("/service/{env}")
+    public Response getServices(@PathParam("env") String env) throws Exception {
+        return Response.ok(kubernetesService.getServices(kubernetesService.getNamespace())).build();
     }
 
     // TODO: implement log watch
     @GET
-    @Path("/container/log/watch/{environment}/{name}")
+    @Path("/container/log/watch/{env}/{name}")
     @Produces(MediaType.SERVER_SENT_EVENTS)
-    public Multi<String> getContainerLogWatch(@PathParam("environment") String environment, @PathParam("name") String name){
+    public Multi<String> getContainerLogWatch(@PathParam("env") String env, @PathParam("name") String name) {
         LOGGER.info("Start sourcing");
-        Optional<KaravanConfiguration.Environment> env = configuration.environments().stream().filter(e -> e.name().equals(environment)).findFirst();
-        if (env.isPresent()) {
-//            eventBus.publish(podName + "-" + namespace, new String(is.readNBytes(i)));
-//            kubernetesService.startContainerLogWatch(name, env.get().namespace());
-        }
-        return eventBus.<String>consumer(name + "-" + env.get().namespace()).toMulti().map(Message::body);
+        return eventBus.<String>consumer(name + "-" + kubernetesService.getNamespace()).toMulti().map(Message::body);
     }
 }
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
index b68aaac..f869b26 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
@@ -19,7 +19,6 @@ package org.apache.camel.karavan.api;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.CamelStatus;
 import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.KaravanConfiguration;
 import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.StatusService;
@@ -27,7 +26,6 @@ import org.jboss.logging.Logger;
 
 import javax.inject.Inject;
 import javax.ws.rs.GET;
-import javax.ws.rs.HeaderParam;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.Produces;
@@ -59,9 +57,9 @@ public class StatusResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment/{projectId}")
-    public Response getDeploymentStatus(@PathParam("projectId") String projectId) {
-        DeploymentStatus status = infinispanService.getDeploymentStatus(projectId);
+    @Path("/deployment/{name}/{env}")
+    public Response getDeploymentStatus(@PathParam("name") String name, @PathParam("env") String env) {
+        DeploymentStatus status = infinispanService.getDeploymentStatus(name, env);
         if (status != null) {
             return Response.ok(status).build();
         } else {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
index 732bdb1..c366be1 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
@@ -3,50 +3,66 @@ package org.apache.camel.karavan.model;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
-import java.util.ArrayList;
-import java.util.List;
-
 public class DeploymentStatus {
     public static final String CACHE = "deployment_statuses";
     @ProtoField(number = 1)
-    String projectId;
+    String name;
     @ProtoField(number = 2)
-    String image;
+    String namespace;
     @ProtoField(number = 3)
-    Integer replicas;
+    String env;
     @ProtoField(number = 4)
-    Integer readyReplicas;
+    String image;
     @ProtoField(number = 5)
+    Integer replicas;
+    @ProtoField(number = 6)
+    Integer readyReplicas;
+    @ProtoField(number = 7)
     Integer unavailableReplicas;
-    @ProtoField(number = 6, collectionImplementation = ArrayList.class)
-    List<PodStatus> podStatuses;
-
 
-    public DeploymentStatus(String projectId) {
-        this.projectId = projectId;
+    public DeploymentStatus(String name, String namespace, String env) {
+        this.name = name;
+        this.namespace = namespace;
+        this.env = env;
         this.image = "";
         this.replicas = 0;
         this.readyReplicas = 0;
         this.unavailableReplicas = 0;
-        this.podStatuses = new ArrayList<>(0);
     }
 
     @ProtoFactory
-    public DeploymentStatus(String projectId, String image, Integer replicas, Integer readyReplicas, Integer unavailableReplicas, List<PodStatus> podStatuses) {
-        this.projectId = projectId;
+    public DeploymentStatus(String name, String namespace, String env, String image, Integer replicas, Integer readyReplicas, Integer unavailableReplicas) {
+        this.name = name;
+        this.env = env;
+        this.namespace = namespace;
         this.image = image;
         this.replicas = replicas;
         this.readyReplicas = readyReplicas;
         this.unavailableReplicas = unavailableReplicas;
-        this.podStatuses = podStatuses;
     }
 
-    public String getProjectId() {
-        return projectId;
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
     }
 
-    public void setProjectId(String projectId) {
-        this.projectId = projectId;
+    public String getEnv() {
+        return env;
+    }
+
+    public void setEnv(String env) {
+        this.env = env;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
     }
 
     public String getImage() {
@@ -80,12 +96,4 @@ public class DeploymentStatus {
     public void setUnavailableReplicas(Integer unavailableReplicas) {
         this.unavailableReplicas = unavailableReplicas;
     }
-
-    public List<PodStatus> getPodStatuses() {
-        return podStatuses;
-    }
-
-    public void setPodStatuses(List<PodStatus> podStatuses) {
-        this.podStatuses = podStatuses;
-    }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/Environment.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/Environment.java
new file mode 100644
index 0000000..e37fbdf
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/Environment.java
@@ -0,0 +1,57 @@
+package org.apache.camel.karavan.model;
+
+import org.infinispan.protostream.annotations.ProtoFactory;
+import org.infinispan.protostream.annotations.ProtoField;
+
+public class Environment {
+    public static final String CACHE = "environments";
+
+    @ProtoField(number = 1)
+    String name;
+    @ProtoField(number = 2)
+    String cluster;
+    @ProtoField(number = 3)
+    String namespace;
+    @ProtoField(number = 4)
+    String pipeline;
+
+    @ProtoFactory
+    public Environment(String name, String cluster, String namespace, String pipeline) {
+        this.name = name;
+        this.cluster = cluster;
+        this.namespace = namespace;
+        this.pipeline = pipeline;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getCluster() {
+        return cluster;
+    }
+
+    public void setCluster(String cluster) {
+        this.cluster = cluster;
+    }
+
+    public String getNamespace() {
+        return namespace;
+    }
+
+    public void setNamespace(String namespace) {
+        this.namespace = namespace;
+    }
+
+    public String getPipeline() {
+        return pipeline;
+    }
+
+    public void setPipeline(String pipeline) {
+        this.pipeline = pipeline;
+    }
+}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/GroupedKey.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/GroupedKey.java
index c657309..a50e5ce 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/GroupedKey.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/GroupedKey.java
@@ -3,8 +3,6 @@ package org.apache.camel.karavan.model;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
-import java.util.Objects;
-
 public class GroupedKey {
 
 
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/KaravanConfiguration.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/KaravanConfiguration.java
deleted file mode 100644
index 5d028c3..0000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/KaravanConfiguration.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package org.apache.camel.karavan.model;
-
-import io.smallrye.config.ConfigMapping;
-
-import java.util.List;
-
-@ConfigMapping(prefix = "karavan.config")
-public interface KaravanConfiguration {
-
-    String groupId();
-    String imageGroup();
-    String runtime();
-    String runtimeVersion();
-    Long statusThreshold();
-    List<Environment> environments();
-
-    interface Environment {
-        String name();
-        String cluster();
-        String namespace();
-        String pipeline();
-        Boolean active();
-    }
-}
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/PipelineStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/PipelineStatus.java
index 8f6f807..b80c379 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/PipelineStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/PipelineStatus.java
@@ -15,21 +15,22 @@ public class PipelineStatus {
     String startTime;
     @ProtoField(number = 6)
     String completionTime;
+    @ProtoField(number = 7)
+    String env;
 
     @ProtoFactory
-    public PipelineStatus(String projectId, String pipelineName, String result, String startTime, String completionTime) {
+    public PipelineStatus(String projectId, String pipelineName, String result, String startTime, String completionTime, String env) {
         this.projectId = projectId;
         this.pipelineName = pipelineName;
         this.result = result;
         this.startTime = startTime;
         this.completionTime = completionTime;
+        this.env = env;
     }
 
-    public PipelineStatus(String projectId) {
+    public PipelineStatus(String projectId, String env) {
         this.projectId = projectId;
-    }
-
-    public PipelineStatus() {
+        this.env = env;
     }
 
     public String getProjectId() {
@@ -71,4 +72,12 @@ public class PipelineStatus {
     public void setCompletionTime(String completionTime) {
         this.completionTime = completionTime;
     }
+
+    public String getEnv() {
+        return env;
+    }
+
+    public void setEnv(String env) {
+        this.env = env;
+    }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
index 7d9c9a4..8c70909 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
@@ -4,6 +4,7 @@ import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
 public class PodStatus {
+    public static final String CACHE = "pod_statuses";
     @ProtoField(number = 1)
     String name;
     @ProtoField(number = 2)
@@ -14,22 +15,26 @@ public class PodStatus {
     String reason;
     @ProtoField(number = 5)
     String deployment;
+    @ProtoField(number = 6)
+    String env;
 
-    public PodStatus() {
+    public PodStatus(String env) {
         this.name = "";
         this.started = false;
         this.ready = false;
         this.reason = "";
         this.deployment = "";
+        this.env = "";
     }
 
     @ProtoFactory
-    public PodStatus(String name, Boolean started, Boolean ready, String reason, String deployment) {
+    public PodStatus(String name, Boolean started, Boolean ready, String reason, String deployment, String env) {
         this.name = name;
         this.started = started;
         this.ready = ready;
         this.reason = reason;
         this.deployment = deployment;
+        this.env = env;
     }
 
     public String getName() {
@@ -71,4 +76,12 @@ public class PodStatus {
     public void setDeployment(String deployment) {
         this.deployment = deployment;
     }
+
+    public String getEnv() {
+        return env;
+    }
+
+    public void setEnv(String env) {
+        this.env = env;
+    }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/Project.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/Project.java
index 844e07a..898b0ab 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/Project.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/Project.java
@@ -17,8 +17,6 @@ public class Project {
     Project.CamelRuntime runtime;
     @ProtoField(number = 5)
     String lastCommit;
-    @ProtoField(number = 6)
-    Boolean deployed;
 
     public enum CamelRuntime {
         @ProtoEnumValue(number = 0, name = "Quarkus")
@@ -30,13 +28,12 @@ public class Project {
     }
 
     @ProtoFactory
-    public Project(String projectId, String name, String description, CamelRuntime runtime, String lastCommit, Boolean deployed) {
+    public Project(String projectId, String name, String description, CamelRuntime runtime, String lastCommit) {
         this.projectId = projectId;
         this.name = name;
         this.description = description;
         this.runtime = runtime;
         this.lastCommit = lastCommit;
-        this.deployed = deployed;
     }
 
     public Project(String projectId, String name, String description, CamelRuntime runtime) {
@@ -89,11 +86,4 @@ public class Project {
         this.lastCommit = lastCommit;
     }
 
-    public Boolean getDeployed() {
-        return deployed;
-    }
-
-    public void setDeployed(Boolean deployed) {
-        this.deployed = deployed;
-    }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
index 5e8d3d5..6a94007 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/ProjectStoreSchema.java
@@ -6,7 +6,7 @@ import org.infinispan.protostream.annotations.AutoProtoSchemaBuilder;
 @AutoProtoSchemaBuilder(
         includeClasses = {
                 GroupedKey.class, Project.class, ProjectFile.class, PipelineStatus.class, CamelStatus.class, DeploymentStatus.class,
-                PodStatus.class
+                PodStatus.class, Environment.class
         },
         schemaPackageName = "karavan")
 public interface ProjectStoreSchema extends GeneratedSchema {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
index 1c12dc1..6780c94 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/GitService.java
@@ -76,7 +76,7 @@ public class GitService {
         String propertiesPrefix = "karavan." + name + "-";
         String branch = ConfigProvider.getConfig().getValue(propertiesPrefix + "git-branch", String.class);
         if (kubernetesService.inKubernetes()){
-            LOGGER.info("inKubernetes " + kubernetesService.currentNamespace);
+            LOGGER.info("inKubernetes " + kubernetesService.getNamespace());
             String kubernetesPrefix = name + "-";
             Secret secret =  kubernetesService.getKaravanSecret();
             String uri = new String(Base64.getDecoder().decode(secret.getData().get(kubernetesPrefix + "git-repository").getBytes(StandardCharsets.UTF_8)));
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
similarity index 85%
copy from karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
copy to karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
index 33b2ac0..c83a121 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
@@ -16,18 +16,14 @@
  */
 package org.apache.camel.karavan.service;
 
-import io.quarkus.runtime.StartupEvent;
 import io.quarkus.vertx.ConsumeEvent;
 import io.smallrye.mutiny.tuples.Tuple2;
-import io.vertx.core.eventbus.EventBus;
-import org.apache.camel.karavan.model.KaravanConfiguration;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.model.ProjectFile;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
-import javax.enterprise.event.Observes;
 import javax.inject.Inject;
 import java.util.Arrays;
 import java.util.List;
@@ -36,12 +32,11 @@ import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
 @ApplicationScoped
-public class KaravanService {
+public class ImportService {
 
-    private static final Logger LOGGER = Logger.getLogger(KaravanService.class.getName());
-    public static final String START_WATCHERS = "start-watchers";
+    private static final Logger LOGGER = Logger.getLogger(ImportService.class.getName());
     public static final String IMPORT_PROJECTS = "import-projects";
-    public static final String LOAD_CUSTOM_KAMELETS = "load-custom-kamelets";
+    public static final String IMPORT_KAMELETS = "import-kamelets";
 
     @Inject
     InfinispanService infinispanService;
@@ -52,13 +47,6 @@ public class KaravanService {
     @ConfigProperty(name = "karavan.config.runtime")
     String runtime;
 
-    @Inject
-    KaravanConfiguration configuration;
-
-    void onStart(@Observes StartupEvent ev) {
-        infinispanService.start();
-    }
-
     @ConsumeEvent(value = IMPORT_PROJECTS, blocking = true)
     void importProjects(String data) {
         LOGGER.info("Import projects from Git");
@@ -67,7 +55,7 @@ public class KaravanService {
             repo.forEach(p -> {
                 String folderName = p.getItem1();
                 String name = Arrays.stream(folderName.split("-")).map(s -> capitalize(s)).collect(Collectors.joining(" "));
-                Project project = new Project(folderName, name, name, Project.CamelRuntime.valueOf(runtime.toUpperCase()), "", false);
+                Project project = new Project(folderName, name, name, Project.CamelRuntime.valueOf(runtime.toUpperCase()), "");
                 infinispanService.saveProject(project);
 
                 AtomicReference<ProjectFile> properties = new AtomicReference<>();
@@ -89,10 +77,9 @@ public class KaravanService {
         } catch (Exception e) {
             LOGGER.error("Error during project import", e);
         }
-        loadCustomKamelets("");
     }
 
-    @ConsumeEvent(value = LOAD_CUSTOM_KAMELETS, blocking = true)
+    @ConsumeEvent(value = IMPORT_KAMELETS, blocking = true)
     void loadCustomKamelets(String data) {
         LOGGER.info("Load custom Kamelets from Git");
         try {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 136f130..88db2e3 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -16,13 +16,13 @@
  */
 package org.apache.camel.karavan.service;
 
-import io.quarkus.runtime.configuration.ProfileManager;
-import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.CamelStatus;
 import org.apache.camel.karavan.model.DeploymentStatus;
+import org.apache.camel.karavan.model.Environment;
 import org.apache.camel.karavan.model.GroupedKey;
 import org.apache.camel.karavan.model.Kamelet;
 import org.apache.camel.karavan.model.PipelineStatus;
+import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.model.ProjectFile;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
@@ -51,16 +51,13 @@ import java.util.stream.Collectors;
 public class InfinispanService {
 
     BasicCache<GroupedKey, Project> projects;
-
     BasicCache<GroupedKey, ProjectFile> files;
-
     BasicCache<GroupedKey, PipelineStatus> pipelineStatuses;
-
-    BasicCache<GroupedKey, DeploymentStatus> deploymentStatus;
-
-    BasicCache<GroupedKey, CamelStatus> camelStatus;
-
+    BasicCache<GroupedKey, DeploymentStatus> deploymentStatuses;
+    BasicCache<GroupedKey, PodStatus> podStatuses;
+    BasicCache<GroupedKey, CamelStatus> camelStatuses;
     BasicCache<String, String> kamelets;
+    BasicCache<String, Environment> environments;
 
     @Inject
     RemoteCacheManager cacheManager;
@@ -68,9 +65,6 @@ public class InfinispanService {
     @Inject
     GeneratorService generatorService;
 
-    @Inject
-    EventBus bus;
-
     @ConfigProperty(name = "karavan.config.runtime")
     String runtime;
 
@@ -95,26 +89,25 @@ public class InfinispanService {
                     .shared(false)
                     .preload(true)
                     .fetchPersistentState(true);
+            environments = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Environment.CACHE, builder.build());
             projects = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Project.CACHE, builder.build());
             files = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(ProjectFile.CACHE, builder.build());
             pipelineStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PipelineStatus.CACHE, builder.build());
-            deploymentStatus = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(DeploymentStatus.CACHE, builder.build());
-            camelStatus = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
+            deploymentStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(DeploymentStatus.CACHE, builder.build());
+            podStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PodStatus.CACHE, builder.build());
+            camelStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
             kamelets = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Kamelet.CACHE, builder.build());
         } else {
             LOGGER.info("InfinispanService is starting in remote mode");
+            environments = cacheManager.administration().getOrCreateCache(Environment.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Environment.CACHE)));
             projects = cacheManager.administration().getOrCreateCache(Project.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Project.CACHE)));
             files = cacheManager.administration().getOrCreateCache(ProjectFile.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, ProjectFile.CACHE)));
-            pipelineStatuses = cacheManager.administration().getOrCreateCache(ProjectFile.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PipelineStatus.CACHE)));
-            deploymentStatus = cacheManager.administration().getOrCreateCache(ProjectFile.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, DeploymentStatus.CACHE)));
-            camelStatus = cacheManager.administration().getOrCreateCache(ProjectFile.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, CamelStatus.CACHE)));
+            pipelineStatuses = cacheManager.administration().getOrCreateCache(PipelineStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PipelineStatus.CACHE)));
+            deploymentStatuses = cacheManager.administration().getOrCreateCache(DeploymentStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, DeploymentStatus.CACHE)));
+            podStatuses = cacheManager.administration().getOrCreateCache(PodStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, PodStatus.CACHE)));
+            camelStatuses = cacheManager.administration().getOrCreateCache(CamelStatus.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, CamelStatus.CACHE)));
             kamelets = cacheManager.administration().getOrCreateCache(Kamelet.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Kamelet.CACHE)));
         }
-        if (getProjects().isEmpty()) {
-            LOGGER.info("No projects found in the Data Grid");
-            bus.publish(KaravanService.IMPORT_PROJECTS, "");
-        }
-        bus.publish(KaravanService.START_WATCHERS, "");
     }
 
     public List<Project> getProjects() {
@@ -171,23 +164,64 @@ public class InfinispanService {
     }
 
     public void savePipelineStatus(PipelineStatus status) {
-        pipelineStatuses.put(GroupedKey.create(status.getProjectId(), status.getProjectId()), status);
+        pipelineStatuses.put(GroupedKey.create(status.getProjectId(), status.getEnv()), status);
     }
 
-    public DeploymentStatus getDeploymentStatus(String projectId) {
-        return deploymentStatus.get(GroupedKey.create(projectId, projectId));
+    public DeploymentStatus getDeploymentStatus(String name, String env) {
+        return deploymentStatuses.get(GroupedKey.create(name, env));
     }
 
     public void saveDeploymentStatus(DeploymentStatus status) {
-        deploymentStatus.put(GroupedKey.create(status.getProjectId(), status.getProjectId()), status);
+        deploymentStatuses.put(GroupedKey.create(status.getName(), status.getEnv()), status);
+    }
+
+    public void deleteDeploymentStatus(DeploymentStatus status) {
+        deploymentStatuses.remove(GroupedKey.create(status.getName(), status.getEnv()));
+    }
+
+    public List<DeploymentStatus> getDeploymentStatuses() {
+        return deploymentStatuses.values().stream().collect(Collectors.toList());
+    }
+
+    public List<DeploymentStatus> getDeploymentStatuses(String env) {
+        if (cacheManager == null) {
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            return queryFactory.<DeploymentStatus>create("FROM org.apache.camel.karavan.model.DeploymentStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        } else {
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            return queryFactory.<DeploymentStatus>create("FROM karavan.DeploymentStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        }
+    }
+
+    public List<PodStatus> getPodStatuses(String projectId, String env) {
+        if (cacheManager == null) {
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            return queryFactory.<PodStatus>create("FROM org.apache.camel.karavan.model.PodStatus WHERE deployment = :deployment AND env = :env")
+                    .setParameter("deployment", projectId)
+                    .setParameter("env", env)
+                    .execute().list();
+        } else {
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            return queryFactory.<PodStatus>create("FROM karavan.PodStatus WHERE deployment = :deployment AND env = :env")
+                    .setParameter("deployment", projectId)
+                    .setParameter("env", env)
+                    .execute().list();
+        }
     }
 
+    public void savePodStatus(PodStatus status) {
+        podStatuses.put(GroupedKey.create(status.getDeployment(), status.getName()), status);
+    }
     public CamelStatus getCamelStatus(String projectId) {
-        return camelStatus.get(GroupedKey.create(projectId, projectId));
+        return camelStatuses.get(GroupedKey.create(projectId, projectId));
     }
 
     public void saveCamelStatus(CamelStatus status) {
-        camelStatus.put(GroupedKey.create(status.getProjectId(), status.getProjectId()), status);
+        camelStatuses.put(GroupedKey.create(status.getProjectId(), status.getProjectId()), status);
     }
 
     public List<String> getKameletNames() {
@@ -201,4 +235,13 @@ public class InfinispanService {
     public void saveKamelet(String name, String yaml) {
         kamelets.put(name, yaml);
     }
+
+    public List<Environment> getEnvironments() {
+        return environments.values().stream().collect(Collectors.toList());
+    }
+
+    public void saveEnvironment(Environment environment) {
+        environments.put(environment.getName(), environment);
+    }
+
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 33b2ac0..717e7c5 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -17,119 +17,57 @@
 package org.apache.camel.karavan.service;
 
 import io.quarkus.runtime.StartupEvent;
-import io.quarkus.vertx.ConsumeEvent;
-import io.smallrye.mutiny.tuples.Tuple2;
 import io.vertx.core.eventbus.EventBus;
-import org.apache.camel.karavan.model.KaravanConfiguration;
-import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.model.ProjectFile;
+import org.apache.camel.karavan.model.Environment;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.enterprise.event.Observes;
 import javax.inject.Inject;
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
 
 @ApplicationScoped
 public class KaravanService {
 
     private static final Logger LOGGER = Logger.getLogger(KaravanService.class.getName());
-    public static final String START_WATCHERS = "start-watchers";
-    public static final String IMPORT_PROJECTS = "import-projects";
-    public static final String LOAD_CUSTOM_KAMELETS = "load-custom-kamelets";
 
     @Inject
     InfinispanService infinispanService;
 
     @Inject
-    GitService gitService;
-
-    @ConfigProperty(name = "karavan.config.runtime")
-    String runtime;
+    KubernetesService kubernetesService;
 
     @Inject
-    KaravanConfiguration configuration;
+    EventBus bus;
+
+    @ConfigProperty(name = "karavan.environment")
+    String environment;
+
+    @ConfigProperty(name = "karavan.pipeline")
+    String pipeline;
 
     void onStart(@Observes StartupEvent ev) {
         infinispanService.start();
+        setEnvironment();
+        initialImport();
+        startInformers();
     }
 
-    @ConsumeEvent(value = IMPORT_PROJECTS, blocking = true)
-    void importProjects(String data) {
-        LOGGER.info("Import projects from Git");
-        try {
-            List<Tuple2<String, Map<String, String>>> repo = gitService.readProjectsFromRepository();
-            repo.forEach(p -> {
-                String folderName = p.getItem1();
-                String name = Arrays.stream(folderName.split("-")).map(s -> capitalize(s)).collect(Collectors.joining(" "));
-                Project project = new Project(folderName, name, name, Project.CamelRuntime.valueOf(runtime.toUpperCase()), "", false);
-                infinispanService.saveProject(project);
-
-                AtomicReference<ProjectFile> properties = new AtomicReference<>();
-                p.getItem2().forEach((key, value) -> {
-                    ProjectFile file = new ProjectFile(key, value, folderName);
-                    infinispanService.saveProjectFile(file);
-                    if (isApplicationProperties(file)) {
-                        properties.set(file);
-                    }
-                });
-                // update project
-                if (properties != null){
-                    project.setDescription(getProjectDescription(properties.get()));
-                    project.setName(getProjectName(properties.get()));
-                    infinispanService.saveProject(project);
-                }
-
-            });
-        } catch (Exception e) {
-            LOGGER.error("Error during project import", e);
-        }
-        loadCustomKamelets("");
+    void setEnvironment() {
+        String cluster = kubernetesService.getCluster();
+        String namespace = kubernetesService.getNamespace();
+        infinispanService.saveEnvironment(new Environment(environment, cluster, namespace, pipeline));
     }
 
-    @ConsumeEvent(value = LOAD_CUSTOM_KAMELETS, blocking = true)
-    void loadCustomKamelets(String data) {
-        LOGGER.info("Load custom Kamelets from Git");
-        try {
-            List<Tuple2<String, String>> repo = gitService.readKameletsFromRepository();
-            repo.forEach(p -> {
-                String name = p.getItem1();
-                String yaml = p.getItem2();
-                infinispanService.saveKamelet(name, yaml);
-            });
-        } catch (Exception e) {
-            LOGGER.error("Error during project import", e);
+    void initialImport() {
+        if (infinispanService.getProjects().isEmpty()) {
+            LOGGER.info("No projects found in the Data Grid");
+            bus.publish(ImportService.IMPORT_PROJECTS, "");
         }
+        bus.publish(ImportService.IMPORT_KAMELETS, "");
     }
 
-    private static String capitalize(String str) {
-        if(str == null || str.isEmpty()) {
-            return str;
-        }
-        return str.substring(0, 1).toUpperCase() + str.substring(1);
-    }
-
-    private static boolean isApplicationProperties(ProjectFile file) {
-        return file.getName().equalsIgnoreCase("application.properties");
-    }
-
-    private static String getProperty(ProjectFile file, String property) {
-        String prefix = property + "=";
-        return  Arrays.stream(file.getCode().split(System.lineSeparator())).filter(s -> s.startsWith(prefix))
-                .findFirst().orElseGet(() -> "")
-                .replace(prefix, "");
-    }
-
-    private static String getProjectDescription(ProjectFile file) {
-        return getProperty(file, "camel.jbang.project-description");
-    }
-
-    private static String getProjectName(ProjectFile file) {
-        return getProperty(file, "camel.jbang.project-name");
+    void startInformers() {
+        bus.publish(KubernetesService.START_WATCHERS, "");
     }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 20bac71..626eb93 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -40,9 +40,7 @@ import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.KaravanConfiguration;
 import org.apache.camel.karavan.model.PipelineRunLog;
-import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.watcher.DeploymentWatcher;
 import org.apache.camel.karavan.watcher.PipelineRunWatcher;
@@ -61,22 +59,17 @@ import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Optional;
 import java.util.stream.Collectors;
 
-import static org.apache.camel.karavan.service.KaravanService.START_WATCHERS;
 
 @ApplicationScoped
 public class KubernetesService {
 
-    @Inject
-    EventBus eventBus;
-
-    @ConfigProperty(name = "kubernetes.namespace", defaultValue = "localhost")
-    String currentNamespace;
+    private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
+    public static final String START_WATCHERS = "start-watchers";
 
     @Inject
-    KaravanConfiguration config;
+    EventBus eventBus;
 
     @Inject
     InfinispanService infinispanService;
@@ -96,36 +89,33 @@ public class KubernetesService {
         return kubernetesClient().adapt(OpenShiftClient.class);
     }
 
-    private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
+    @ConfigProperty(name = "karavan.environment")
+    public
+    String environment;
 
     private List<Watch> watches = new ArrayList<>();
 
     @ConsumeEvent(value = START_WATCHERS, blocking = true)
     void start(String data) {
         LOGGER.info("Start KubernetesService");
-        Optional<KaravanConfiguration.Environment> env = config.environments().stream()
-                .filter(environment -> environment.name().equals("dev")).findFirst();
-        if (env.isPresent()) {
-            String labelName = getRuntimeLabel();
-            try {
-                watches.add(kubernetesClient().apps().deployments().inNamespace(currentNamespace).withLabel(labelName, "camel")
-                        .watch(new DeploymentWatcher(infinispanService, this)));
-            } catch (Exception e) {
-                LOGGER.error(e.getMessage());
-            }
-            try {
-                watches.add(kubernetesClient().pods().inNamespace(currentNamespace).withLabel(labelName, "camel")
-                        .watch(new PodWatcher(infinispanService, this)));
-            } catch (Exception e){
-                LOGGER.error(e.getMessage());
-            }
-            try {
-                watches.add(tektonClient().v1beta1().pipelineRuns().inNamespace(currentNamespace)
-                        .watch(new PipelineRunWatcher(infinispanService)));
-            } catch (Exception e) {
-                LOGGER.error(e.getMessage());
-            }
-
+        String labelName = getRuntimeLabel();
+        try {
+            watches.add(kubernetesClient().apps().deployments().inNamespace(getNamespace()).withLabel(labelName, "camel")
+                    .watch(new DeploymentWatcher(infinispanService, this)));
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
+        }
+        try {
+            watches.add(kubernetesClient().pods().inNamespace(getNamespace()).withLabel(labelName, "camel")
+                    .watch(new PodWatcher(infinispanService, this)));
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+        try {
+            watches.add(tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace())
+                    .watch(new PipelineRunWatcher(infinispanService, this)));
+        } catch (Exception e) {
+            LOGGER.error(e.getMessage());
         }
     }
 
@@ -242,49 +232,27 @@ public class KubernetesService {
         }
     }
 
-    public DeploymentStatus getDeploymentStatus(String name, Deployment deployment) {
-        try {
-            String dsImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
-            String imageName = dsImage.startsWith("image-registry.openshift-image-registry.svc")
-                    ? dsImage.replace("image-registry.openshift-image-registry.svc:5000/", "")
-                    : dsImage;
-
-            List<PodStatus> podStatuses = getDeploymentPodsStatuses(name, deployment.getMetadata().getNamespace());
-
-            return new DeploymentStatus(
-                    name,
-                    imageName,
-                    deployment.getSpec().getReplicas(),
-                    deployment.getStatus().getReadyReplicas(),
-                    deployment.getStatus().getUnavailableReplicas(),
-                    podStatuses
-            );
-        } catch (Exception ex) {
-            LOGGER.error(ex.getMessage());
-            return new DeploymentStatus(name);
-        }
-    }
 
-    public List<PodStatus> getDeploymentPodsStatuses(String name, String namespace) {
-        try {
-            String labelName = getRuntimeLabel();
-            List<Pod> pods = kubernetesClient().pods().inNamespace(namespace)
-                    .withLabel("app.kubernetes.io/name", name)
-                    .withLabel(labelName, "camel")
-                    .list().getItems();
-
-            return pods.stream().map(pod -> new PodStatus(
-                    pod.getMetadata().getName(),
-                    pod.getStatus().getContainerStatuses().get(0).getStarted(),
-                    pod.getStatus().getContainerStatuses().get(0).getReady(),
-                    getPodReason(pod),
-                    pod.getMetadata().getLabels().get("app.kubernetes.io/name")
-            )).collect(Collectors.toList());
-        } catch (Exception ex) {
-            LOGGER.error(ex.getMessage());
-            return List.of();
-        }
-    }
+//    public List<PodStatus> getDeploymentPodsStatuses(String name, String namespace) {
+//        try {
+//            String labelName = getRuntimeLabel();
+//            List<Pod> pods = kubernetesClient().pods().inNamespace(namespace)
+//                    .withLabel("app.kubernetes.io/name", name)
+//                    .withLabel(labelName, "camel")
+//                    .list().getItems();
+//
+//            return pods.stream().map(pod -> new PodStatus(
+//                    pod.getMetadata().getName(),
+//                    pod.getStatus().getContainerStatuses().get(0).getStarted(),
+//                    pod.getStatus().getContainerStatuses().get(0).getReady(),
+//                    getPodReason(pod),
+//                    pod.getMetadata().getLabels().get("app.kubernetes.io/name")
+//            )).collect(Collectors.toList());
+//        } catch (Exception ex) {
+//            LOGGER.error(ex.getMessage());
+//            return List.of();
+//        }
+//    }
 
     public Deployment getDeployment(String name, String namespace) {
         try {
@@ -370,7 +338,7 @@ public class KubernetesService {
     }
 
     public Secret getKaravanSecret() {
-        return kubernetesClient().secrets().inNamespace(currentNamespace).withName("karavan").get();
+        return kubernetesClient().secrets().inNamespace(getNamespace()).withName("karavan").get();
     }
 
     public String getRuntimeLabel() {
@@ -381,7 +349,14 @@ public class KubernetesService {
         return kubernetesClient().isAdaptable(OpenShiftClient.class);
     }
 
+    public String getCluster() {
+        return kubernetesClient().getMasterUrl().getHost();
+    }
+    public String getNamespace() {
+        return kubernetesClient().getNamespace();
+    }
+
     public boolean inKubernetes() {
-        return !Objects.equals(currentNamespace, "localhost");
+        return !Objects.equals(getNamespace(), "localhost");
     }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
index 33cc888..a103326 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/StatusService.java
@@ -24,7 +24,7 @@ import io.vertx.mutiny.core.buffer.Buffer;
 import io.vertx.mutiny.ext.web.client.HttpResponse;
 import io.vertx.mutiny.ext.web.client.WebClient;
 import org.apache.camel.karavan.model.CamelStatus;
-import org.apache.camel.karavan.model.KaravanConfiguration;
+import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
@@ -45,8 +45,8 @@ public class StatusService {
     @Inject
     KubernetesService kubernetesService;
 
-    @Inject
-    KaravanConfiguration configuration;
+    @ConfigProperty(name = "karavan.camel-status-threshold")
+    int threshold;
 
     private long lastCollect = 0;
 
@@ -65,21 +65,18 @@ public class StatusService {
 
     @ConsumeEvent(value = CMD_COLLECT_STATUSES, blocking = true, ordered = true)
     public void collectStatuses(String projectId) throws Exception {
-        if ((System.currentTimeMillis() - lastCollect) > configuration.statusThreshold()) {
+        if ((System.currentTimeMillis() - lastCollect) > threshold) {
             collectStatusesForProject(projectId);
             lastCollect = System.currentTimeMillis();
         }
     }
 
     private void collectStatusesForProject(String projectId) {
-        configuration.environments().stream().filter(e -> e.active()).forEach(e -> {
-            String url = ProfileManager.getActiveProfile().equals("dev")
-                    ? String.format("http://%s-%s.%s/q/health", projectId, e.namespace(), e.cluster())
-                    : String.format("http://%s.%s.%s/q/health", projectId, e.namespace(), e.cluster());
-            CamelStatus cs = getCamelStatus(projectId, url);
-            infinispanService.saveCamelStatus(cs);
-        });
-
+        String url = ProfileManager.getActiveProfile().equals("dev")
+                ? String.format("http://%s-%s.%s/q/health", projectId, kubernetesService.getNamespace(), kubernetesService.getCluster())
+                : String.format("http://%s.%s.%s/q/health", projectId, kubernetesService.getNamespace(), kubernetesService.getCluster());
+        CamelStatus cs = getCamelStatus(projectId, url);
+        infinispanService.saveCamelStatus(cs);
     }
 
     private CamelStatus getCamelStatus(String projectId, String url) {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
index 8f635f3..3177e1e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
@@ -26,29 +26,42 @@ public class DeploymentWatcher implements Watcher<Deployment> {
     @Override
     public void eventReceived(Watcher.Action action, Deployment deployment) {
         LOGGER.info(action.name() + " " + deployment.getMetadata().getName());
-        Project project = infinispanService.getProject(deployment.getMetadata().getName());
-        if (project != null) {
-            switch (action.name()) {
-                case "ADDED":
-                    project.setDeployed(true);
-                    infinispanService.saveProject(project);
-                    DeploymentStatus s = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
-                    infinispanService.saveDeploymentStatus(s);
-                    break;
-                case "MODIFIED":
-                    if (!project.getDeployed()) {
-                        project.setDeployed(true);
-                        infinispanService.saveProject(project);
-                    }
-                    DeploymentStatus ds = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
-                    infinispanService.saveDeploymentStatus(ds);
-                    break;
-                case "DELETED":
-                    project.setDeployed(false);
-                    infinispanService.saveProject(project);
-                    infinispanService.saveDeploymentStatus(new DeploymentStatus(project.getProjectId()));
-                    break;
-            }
+        DeploymentStatus ds = getDeploymentStatus(deployment);
+        switch (action.name()) {
+            case "ADDED":
+                infinispanService.saveDeploymentStatus(ds);
+                break;
+            case "MODIFIED":
+                infinispanService.saveDeploymentStatus(ds);
+                break;
+            case "DELETED":
+                infinispanService.deleteDeploymentStatus(ds);
+                break;
+        }
+    }
+
+    public DeploymentStatus getDeploymentStatus(Deployment deployment) {
+        try {
+            String dsImage = deployment.getSpec().getTemplate().getSpec().getContainers().get(0).getImage();
+            String imageName = dsImage.startsWith("image-registry.openshift-image-registry.svc")
+                    ? dsImage.replace("image-registry.openshift-image-registry.svc:5000/", "")
+                    : dsImage;
+
+            return new DeploymentStatus(
+                    deployment.getMetadata().getName(),
+                    deployment.getMetadata().getNamespace(),
+                    kubernetesService.environment,
+                    imageName,
+                    deployment.getSpec().getReplicas(),
+                    deployment.getStatus().getReadyReplicas(),
+                    deployment.getStatus().getUnavailableReplicas()
+            );
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage());
+            return new DeploymentStatus(
+                    deployment.getMetadata().getName(),
+                    deployment.getMetadata().getNamespace(),
+                    kubernetesService.environment);
         }
     }
 
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
index df966a3..1e1ba3a 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
@@ -6,6 +6,7 @@ import io.fabric8.tekton.pipeline.v1beta1.PipelineRun;
 import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
+import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
 
 import java.time.Instant;
@@ -15,9 +16,11 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
 
     private static final Logger LOGGER = Logger.getLogger(PipelineRunWatcher.class.getName());
     private InfinispanService infinispanService;
+    private KubernetesService kubernetesService;
 
-    public PipelineRunWatcher(InfinispanService infinispanService) {
+    public PipelineRunWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
         this.infinispanService = infinispanService;
+        this.kubernetesService = kubernetesService;
     }
 
     @Override
@@ -28,7 +31,7 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
             Project project = infinispanService.getProject(projectId);
             if (project != null && List.of("MODIFIED", "ADDED").contains(action.name())) {
                 PipelineStatus pipelineStatus = infinispanService.getPipelineStatus(projectId);
-                if (pipelineStatus == null) pipelineStatus = new PipelineStatus(project.getProjectId());
+                if (pipelineStatus == null) pipelineStatus = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
 
                 if (pipelineRun.getStatus() != null) {
                     LOGGER.info(action.name()+ " " + pipelineRun.getMetadata().getName() + " " + pipelineRun.getStatus().getConditions().get(0).getReason());
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
index 23fb200..99e0982 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
@@ -25,12 +25,12 @@ public class PodWatcher implements Watcher<Pod> {
     public void eventReceived(Action action, Pod pod) {
         LOGGER.info(action.name() + " " + pod.getMetadata().getName());
         String name = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
-        Project project = infinispanService.getProject(name);
-        Deployment deployment = kubernetesService.getDeployment(name, pod.getMetadata().getNamespace());
-        if (project != null && deployment != null) {
-            DeploymentStatus s = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
-            infinispanService.saveDeploymentStatus(s);
-        }
+//        Project project = infinispanService.getProject(name);
+//        Deployment deployment = kubernetesService.getDeployment(name, pod.getMetadata().getNamespace());
+//        if (project != null && deployment != null) {
+//            DeploymentStatus s = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
+//            infinispanService.saveDeploymentStatus(s);
+//        }
     }
 
     @Override
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index a0f2b84..6c1a38c 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -1,4 +1,7 @@
 karavan.version=3.18.5
+karavan.environment=dev
+karavan.pipeline=karavan-pipeline-build-quarkus
+karavan.camel-status-threshold=2000
 
 # Git repository Configuration
 karavan.projects-git-repository=${GIT_REPOSITORY}
@@ -12,34 +15,11 @@ karavan.kamelets-git-username=${GIT_USERNAME}
 karavan.kamelets-git-password=${GIT_TOKEN}
 karavan.kamelets-git-branch=main
 
-# Projects configuration
+# Projects default configuration
 karavan.config.group-id=org.camel.karavan.demo
 karavan.config.image-group=karavan
 karavan.config.runtime=QUARKUS
 karavan.config.runtime-version=2.13.3.Final
-karavan.config.status-threshold=2000
-
-karavan.config.environments[0].name=dev
-karavan.config.environments[0].namespace=karavan
-karavan.config.environments[0].pipeline=karavan-quarkus
-karavan.config.environments[0].cluster=svc.cluster.local
-karavan.config.environments[0].active=true
-
-karavan.config.environments[1].name=test
-karavan.config.environments[1].namespace=test
-karavan.config.environments[1].pipeline=karavan-quarkus
-karavan.config.environments[1].cluster=svc.cluster.local
-karavan.config.environments[1].active=false
-
-karavan.config.environments[2].name=prod
-karavan.config.environments[2].namespace=prod
-karavan.config.environments[2].pipeline=karavan-quarkus
-karavan.config.environments[2].cluster=svc.cluster.local
-karavan.config.environments[2].active=false
-
-%dev.karavan.config.environments[0].cluster=apps.home.myocp.net 
-%dev.karavan.config.environments[1].cluster=apps.home.myocp.net
-%dev.karavan.config.environments[2].cluster=apps.home.myocp.net
 
 # Infinispan Server address
 #quarkus.infinispan-client.server-list=localhost:12345
diff --git a/karavan-app/src/main/webapp/package-lock.json b/karavan-app/src/main/webapp/package-lock.json
index 81e84ae..6af2d60 100644
--- a/karavan-app/src/main/webapp/package-lock.json
+++ b/karavan-app/src/main/webapp/package-lock.json
@@ -47,7 +47,8 @@
         "@types/js-yaml": "^4.0.5",
         "@types/uuid": "^8.3.4",
         "typescript": "^4.5.5",
-        "uuid": "8.3.2"
+        "uuid": "8.3.2",
+        "yaml": "^2.1.3"
       },
       "devDependencies": {
         "@types/chai": "^4.3.0",
@@ -24573,7 +24574,8 @@
         "mocha": "^9.2.0",
         "ts-node": "^10.4.0",
         "typescript": "^4.5.5",
-        "uuid": "8.3.2"
+        "uuid": "8.3.2",
+        "yaml": "^2.1.3"
       }
     },
     "keycloak-js": {
diff --git a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index 0d400b2..50379ba 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -160,8 +160,8 @@ export class KaravanApi {
         });
     }
 
-    static async getProjectDeploymentStatus(projectId: string, after: (status: DeploymentStatus) => void) {
-        instance.get('/api/status/deployment/' + projectId)
+    static async getProjectDeploymentStatus(projectId: string, env: string, after: (status: DeploymentStatus) => void) {
+        instance.get('/api/status/deployment/' + projectId + "/" + env)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index 24eed8e..16ce1a3 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -85,7 +85,7 @@ export class ProjectInfo extends React.Component<Props, State> {
                 this.setState({key: Math.random().toString(), pipelineStatus: status});
                 // console.log(status);
             });
-            KaravanApi.getProjectDeploymentStatus(this.props.project.projectId, (status: DeploymentStatus) => {
+            KaravanApi.getProjectDeploymentStatus(this.props.project.projectId, this.state.environment, (status: DeploymentStatus) => {
                 this.setState({key: Math.random().toString(), deploymentStatus: status});
                 // console.log(status);
             });


[camel-karavan] 05/08: Fix #501

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 7a6bb5bc96cda3b0567c2c8a45ff7e5bb4e88db2
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 10:10:49 2022 -0400

    Fix #501
---
 .../camel/karavan/api/KubernetesResource.java      | 16 +++-
 .../camel/karavan/model/DeploymentStatus.java      |  1 +
 .../org/apache/camel/karavan/model/PodStatus.java  | 42 +++++++----
 .../camel/karavan/service/InfinispanService.java   | 40 +++++++++-
 .../camel/karavan/service/KaravanService.java      |  9 ++-
 .../camel/karavan/service/KubernetesService.java   | 85 +++++++++-------------
 ...entWatcher.java => DeploymentEventHandler.java} | 63 +++++++++-------
 ...unWatcher.java => PipelineRunEventHandler.java} | 65 ++++++++++++-----
 .../camel/karavan/watcher/PodEventHandler.java     | 84 +++++++++++++++++++++
 .../apache/camel/karavan/watcher/PodWatcher.java   | 40 ----------
 10 files changed, 287 insertions(+), 158 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index a817434..c79fc51 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -20,6 +20,7 @@ import io.smallrye.mutiny.Multi;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import io.vertx.mutiny.core.eventbus.Message;
 import org.apache.camel.karavan.model.DeploymentStatus;
+import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
@@ -99,9 +100,9 @@ public class KubernetesResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/deployment/")
-    public List<DeploymentStatus> getAll() throws Exception {
-        return infinispanService.getDeploymentStatuses().stream()
+    @Path("/deployment/{env}")
+    public List<DeploymentStatus> getDeploymentStatusesByEnv(@PathParam("env") String env) throws Exception {
+        return infinispanService.getDeploymentStatuses(env).stream()
                 .sorted(Comparator.comparing(DeploymentStatus::getName))
                 .collect(Collectors.toList());
     }
@@ -127,6 +128,15 @@ public class KubernetesResource {
         return Response.ok().build();
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/pod/{env}")
+    public List<PodStatus> getPodStatusesByEnv(@PathParam("env") String env) throws Exception {
+        return infinispanService.getPodStatuses(env).stream()
+                .sorted(Comparator.comparing(PodStatus::getName))
+                .collect(Collectors.toList());
+    }
+
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
index c366be1..f0baa9e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/DeploymentStatus.java
@@ -1,5 +1,6 @@
 package org.apache.camel.karavan.model;
 
+import org.infinispan.protostream.annotations.ProtoDoc;
 import org.infinispan.protostream.annotations.ProtoFactory;
 import org.infinispan.protostream.annotations.ProtoField;
 
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
index 8c70909..e24f9ea 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/PodStatus.java
@@ -8,29 +8,33 @@ public class PodStatus {
     @ProtoField(number = 1)
     String name;
     @ProtoField(number = 2)
-    Boolean started;
+    String phase;
     @ProtoField(number = 3)
-    Boolean ready;
+    Boolean initialized;
     @ProtoField(number = 4)
-    String reason;
+    Boolean ready;
     @ProtoField(number = 5)
-    String deployment;
+    String reason;
     @ProtoField(number = 6)
+    String deployment;
+    @ProtoField(number = 7)
     String env;
 
-    public PodStatus(String env) {
-        this.name = "";
-        this.started = false;
+    public PodStatus(String name, String deployment, String env) {
+        this.name = name;
+        this.phase = "";
+        this.initialized = false;
         this.ready = false;
         this.reason = "";
-        this.deployment = "";
-        this.env = "";
+        this.deployment = deployment;
+        this.env = env;
     }
 
     @ProtoFactory
-    public PodStatus(String name, Boolean started, Boolean ready, String reason, String deployment, String env) {
+    public PodStatus(String name, String phase, Boolean initialized, Boolean ready, String reason, String deployment, String env) {
         this.name = name;
-        this.started = started;
+        this.phase = phase;
+        this.initialized = initialized;
         this.ready = ready;
         this.reason = reason;
         this.deployment = deployment;
@@ -45,12 +49,20 @@ public class PodStatus {
         this.name = name;
     }
 
-    public Boolean getStarted() {
-        return started;
+    public String getPhase() {
+        return phase;
+    }
+
+    public void setPhase(String phase) {
+        this.phase = phase;
+    }
+
+    public Boolean getInitialized() {
+        return initialized;
     }
 
-    public void setStarted(Boolean started) {
-        this.started = started;
+    public void setInitialized(Boolean initialized) {
+        this.initialized = initialized;
     }
 
     public Boolean getReady() {
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 9a0fd03..3fddb8f 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -97,6 +97,8 @@ public class InfinispanService {
             podStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(PodStatus.CACHE, builder.build());
             camelStatuses = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(CamelStatus.CACHE, builder.build());
             kamelets = cacheManager.administration().withFlags(CacheContainerAdmin.AdminFlag.VOLATILE).getOrCreateCache(Kamelet.CACHE, builder.build());
+
+            cleanStatuses();
         } else {
             LOGGER.info("InfinispanService is starting in remote mode");
             environments = cacheManager.administration().getOrCreateCache(Environment.CACHE, new XMLStringConfiguration(String.format(CACHE_CONFIG, Environment.CACHE)));
@@ -110,6 +112,13 @@ public class InfinispanService {
         }
     }
 
+    private void cleanStatuses() {
+        deploymentStatuses.clear();
+        podStatuses.clear();
+        pipelineStatuses.clear();
+    }
+
+
     public List<Project> getProjects() {
         return projects.values().stream().collect(Collectors.toList());
     }
@@ -167,6 +176,10 @@ public class InfinispanService {
         pipelineStatuses.put(GroupedKey.create(status.getProjectId(), status.getEnv()), status);
     }
 
+    public void deletePipelineStatus(PipelineStatus status) {
+        pipelineStatuses.remove(GroupedKey.create(status.getProjectId(), status.getEnv()));
+    }
+
     public DeploymentStatus getDeploymentStatus(String name, String env) {
         return deploymentStatuses.get(GroupedKey.create(name, env));
     }
@@ -185,12 +198,12 @@ public class InfinispanService {
 
     public List<DeploymentStatus> getDeploymentStatuses(String env) {
         if (cacheManager == null) {
-            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) deploymentStatuses);
             return queryFactory.<DeploymentStatus>create("FROM org.apache.camel.karavan.model.DeploymentStatus WHERE env = :env")
                     .setParameter("env", env)
                     .execute().list();
         } else {
-            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) deploymentStatuses);
             return queryFactory.<DeploymentStatus>create("FROM karavan.DeploymentStatus WHERE env = :env")
                     .setParameter("env", env)
                     .execute().list();
@@ -199,13 +212,13 @@ public class InfinispanService {
 
     public List<PodStatus> getPodStatuses(String projectId, String env) {
         if (cacheManager == null) {
-            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) files);
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) podStatuses);
             return queryFactory.<PodStatus>create("FROM org.apache.camel.karavan.model.PodStatus WHERE deployment = :deployment AND env = :env")
                     .setParameter("deployment", projectId)
                     .setParameter("env", env)
                     .execute().list();
         } else {
-            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) files);
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) podStatuses);
             return queryFactory.<PodStatus>create("FROM karavan.PodStatus WHERE deployment = :deployment AND env = :env")
                     .setParameter("deployment", projectId)
                     .setParameter("env", env)
@@ -213,9 +226,28 @@ public class InfinispanService {
         }
     }
 
+    public List<PodStatus> getPodStatuses(String env) {
+        if (cacheManager == null) {
+            QueryFactory queryFactory = org.infinispan.query.Search.getQueryFactory((Cache<?, ?>) podStatuses);
+            return queryFactory.<PodStatus>create("FROM org.apache.camel.karavan.model.PodStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        } else {
+            QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) podStatuses);
+            return queryFactory.<PodStatus>create("FROM karavan.PodStatus WHERE env = :env")
+                    .setParameter("env", env)
+                    .execute().list();
+        }
+    }
+
     public void savePodStatus(PodStatus status) {
         podStatuses.put(GroupedKey.create(status.getDeployment(), status.getName()), status);
     }
+
+    public void deletePodStatus(PodStatus status) {
+        podStatuses.remove(GroupedKey.create(status.getDeployment(), status.getName()));
+    }
+
     public CamelStatus getCamelStatus(String projectId) {
         return camelStatuses.get(GroupedKey.create(projectId, projectId));
     }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
index 717e7c5..f5d2451 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KaravanService.java
@@ -16,6 +16,7 @@
  */
 package org.apache.camel.karavan.service;
 
+import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.runtime.StartupEvent;
 import io.vertx.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.Environment;
@@ -47,12 +48,18 @@ public class KaravanService {
     String pipeline;
 
     void onStart(@Observes StartupEvent ev) {
+        LOGGER.info("Start Karavan");
         infinispanService.start();
         setEnvironment();
         initialImport();
         startInformers();
     }
 
+    void onStop(@Observes ShutdownEvent ev) {
+        LOGGER.info("Stop Karavan");
+        bus.publish(KubernetesService.STOP_INFORMERS, "");
+    }
+
     void setEnvironment() {
         String cluster = kubernetesService.getCluster();
         String namespace = kubernetesService.getNamespace();
@@ -68,6 +75,6 @@ public class KaravanService {
     }
 
     void startInformers() {
-        bus.publish(KubernetesService.START_WATCHERS, "");
+        bus.publish(KubernetesService.START_INFORMERS, "");
     }
 }
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 735b47e..b896013 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -24,7 +24,11 @@ import io.fabric8.kubernetes.api.model.apps.Deployment;
 import io.fabric8.kubernetes.client.DefaultKubernetesClient;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.Watch;
+import io.fabric8.kubernetes.client.dsl.Informable;
 import io.fabric8.kubernetes.client.dsl.LogWatch;
+import io.fabric8.kubernetes.client.informers.SharedIndexInformer;
+import io.fabric8.kubernetes.client.informers.SharedInformerEventListener;
+import io.fabric8.kubernetes.client.informers.SharedInformerFactory;
 import io.fabric8.openshift.api.model.ImageStream;
 import io.fabric8.openshift.client.OpenShiftClient;
 import io.fabric8.tekton.client.DefaultTektonClient;
@@ -41,9 +45,9 @@ import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.mutiny.core.eventbus.EventBus;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.watcher.DeploymentWatcher;
-import org.apache.camel.karavan.watcher.PipelineRunWatcher;
-import org.apache.camel.karavan.watcher.PodWatcher;
+import org.apache.camel.karavan.watcher.DeploymentEventHandler;
+import org.apache.camel.karavan.watcher.PipelineRunEventHandler;
+import org.apache.camel.karavan.watcher.PodEventHandler;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.jboss.logging.Logger;
 
@@ -65,7 +69,8 @@ import java.util.stream.Collectors;
 public class KubernetesService {
 
     private static final Logger LOGGER = Logger.getLogger(KubernetesService.class.getName());
-    public static final String START_WATCHERS = "start-watchers";
+    public static final String START_INFORMERS = "start-informers";
+    public static final String STOP_INFORMERS = "stop-informers";
 
     @Inject
     EventBus eventBus;
@@ -92,35 +97,36 @@ public class KubernetesService {
     public
     String environment;
 
-    private List<Watch> watches = new ArrayList<>();
+    List<SharedIndexInformer> informers = new ArrayList<>(3);
 
-    @ConsumeEvent(value = START_WATCHERS, blocking = true)
-    void start(String data) {
-        LOGGER.info("Start KubernetesService");
-        String labelName = getRuntimeLabel();
+    @ConsumeEvent(value = START_INFORMERS, blocking = true)
+    void startInformers(String data) {
+        LOGGER.info("Start Kubernetes Informers");
         try {
-            watches.add(kubernetesClient().apps().deployments().inNamespace(getNamespace()).withLabel(labelName, "camel")
-                    .watch(new DeploymentWatcher(infinispanService, this)));
-        } catch (Exception e) {
-            LOGGER.error(e.getMessage());
-        }
-        try {
-            watches.add(kubernetesClient().pods().inNamespace(getNamespace()).withLabel(labelName, "camel")
-                    .watch(new PodWatcher(infinispanService, this)));
-        } catch (Exception e){
-            LOGGER.error(e.getMessage());
-        }
-        try {
-            watches.add(tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace())
-                    .watch(new PipelineRunWatcher(infinispanService, this)));
+            stopInformers(null);
+            String runtimeLabel = getRuntimeLabel();
+
+            SharedIndexInformer<Deployment> deploymentInformer = kubernetesClient().apps().deployments().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            deploymentInformer.addEventHandlerWithResyncPeriod(new DeploymentEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(deploymentInformer);
+
+            SharedIndexInformer<PipelineRun> pipelineRunInformer = tektonClient().v1beta1().pipelineRuns().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            pipelineRunInformer.addEventHandlerWithResyncPeriod(new PipelineRunEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(pipelineRunInformer);
+
+            SharedIndexInformer<Pod> podRunInformer = kubernetesClient().pods().inNamespace(getNamespace()).withLabel(runtimeLabel, "camel").inform();
+            podRunInformer.addEventHandlerWithResyncPeriod(new PodEventHandler(infinispanService, this),30 * 1000L);
+            informers.add(podRunInformer);
+
         } catch (Exception e) {
-            LOGGER.error(e.getMessage());
+            LOGGER.error("Error starting informers: " + e.getMessage());
         }
     }
 
-    void onStop(@Observes ShutdownEvent ev) {
-        LOGGER.info("Stop KubernetesService");
-        watches.forEach(watch -> watch.close());
+    @ConsumeEvent(value = STOP_INFORMERS, blocking = true)
+    void stopInformers(String data) {
+        LOGGER.info("Stop Kubernetes Informers");
+        informers.forEach(informer -> informer.close());
     }
 
     public String createPipelineRun(Project project, String pipelineName, String namespace) throws Exception {
@@ -128,7 +134,8 @@ public class KubernetesService {
 
         Map<String, String> labels = Map.of(
                 "karavan-project-id", project.getProjectId(),
-                "tekton.dev/pipeline", pipelineName
+                "tekton.dev/pipeline", pipelineName,
+                getRuntimeLabel(), "camel"
         );
 
         ObjectMeta meta = new ObjectMetaBuilder()
@@ -231,28 +238,6 @@ public class KubernetesService {
         }
     }
 
-
-//    public List<PodStatus> getDeploymentPodsStatuses(String name, String namespace) {
-//        try {
-//            String labelName = getRuntimeLabel();
-//            List<Pod> pods = kubernetesClient().pods().inNamespace(namespace)
-//                    .withLabel("app.kubernetes.io/name", name)
-//                    .withLabel(labelName, "camel")
-//                    .list().getItems();
-//
-//            return pods.stream().map(pod -> new PodStatus(
-//                    pod.getMetadata().getName(),
-//                    pod.getStatus().getContainerStatuses().get(0).getStarted(),
-//                    pod.getStatus().getContainerStatuses().get(0).getReady(),
-//                    getPodReason(pod),
-//                    pod.getMetadata().getLabels().get("app.kubernetes.io/name")
-//            )).collect(Collectors.toList());
-//        } catch (Exception ex) {
-//            LOGGER.error(ex.getMessage());
-//            return List.of();
-//        }
-//    }
-
     public Deployment getDeployment(String name, String namespace) {
         try {
             return kubernetesClient().apps().deployments().inNamespace(namespace).withName(name).get();
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
similarity index 53%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
index 3177e1e..b4f4323 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/DeploymentEventHandler.java
@@ -1,42 +1,56 @@
 package org.apache.camel.karavan.watcher;
 
-import io.fabric8.kubernetes.client.Watcher;
 import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.PodStatus;
-import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
 
-import java.util.List;
+public class DeploymentEventHandler implements ResourceEventHandler<Deployment> {
 
-public class DeploymentWatcher implements Watcher<Deployment> {
-
-    private static final Logger LOGGER = Logger.getLogger(DeploymentWatcher.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(DeploymentEventHandler.class.getName());
     private InfinispanService infinispanService;
     private KubernetesService kubernetesService;
 
-    public DeploymentWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
+    public DeploymentEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
         this.infinispanService = infinispanService;
         this.kubernetesService = kubernetesService;
     }
 
     @Override
-    public void eventReceived(Watcher.Action action, Deployment deployment) {
-        LOGGER.info(action.name() + " " + deployment.getMetadata().getName());
-        DeploymentStatus ds = getDeploymentStatus(deployment);
-        switch (action.name()) {
-            case "ADDED":
-                infinispanService.saveDeploymentStatus(ds);
-                break;
-            case "MODIFIED":
-                infinispanService.saveDeploymentStatus(ds);
-                break;
-            case "DELETED":
-                infinispanService.deleteDeploymentStatus(ds);
-                break;
+    public void onAdd(Deployment deployment) {
+        try {
+            LOGGER.info("onAdd " + deployment.getMetadata().getName());
+            DeploymentStatus ds = getDeploymentStatus(deployment);
+            infinispanService.saveDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(Deployment oldDeployment, Deployment newDeployment) {
+        try {
+            LOGGER.info("onUpdate " + newDeployment.getMetadata().getName());
+            DeploymentStatus ds = getDeploymentStatus(newDeployment);
+            infinispanService.saveDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(Deployment deployment, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + deployment.getMetadata().getName());
+            DeploymentStatus ds = new DeploymentStatus(
+                    deployment.getMetadata().getName(),
+                    deployment.getMetadata().getNamespace(),
+                    kubernetesService.environment);
+            infinispanService.deleteDeploymentStatus(ds);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
         }
     }
 
@@ -64,9 +78,4 @@ public class DeploymentWatcher implements Watcher<Deployment> {
                     kubernetesService.environment);
         }
     }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
 }
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
similarity index 56%
rename from karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
rename to karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
index 1e1ba3a..b5d59e9 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunWatcher.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PipelineRunEventHandler.java
@@ -1,7 +1,6 @@
 package org.apache.camel.karavan.watcher;
 
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
 import io.fabric8.tekton.pipeline.v1beta1.PipelineRun;
 import org.apache.camel.karavan.model.PipelineStatus;
 import org.apache.camel.karavan.model.Project;
@@ -10,31 +9,65 @@ import org.apache.camel.karavan.service.KubernetesService;
 import org.jboss.logging.Logger;
 
 import java.time.Instant;
-import java.util.List;
 
-public class PipelineRunWatcher implements Watcher<PipelineRun> {
+public class PipelineRunEventHandler implements ResourceEventHandler<PipelineRun> {
 
-    private static final Logger LOGGER = Logger.getLogger(PipelineRunWatcher.class.getName());
+    private static final Logger LOGGER = Logger.getLogger(PipelineRunEventHandler.class.getName());
     private InfinispanService infinispanService;
     private KubernetesService kubernetesService;
 
-    public PipelineRunWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
+    public PipelineRunEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
         this.infinispanService = infinispanService;
         this.kubernetesService = kubernetesService;
     }
 
     @Override
-    public void eventReceived(Action action, PipelineRun pipelineRun) {
-        LOGGER.info(action.name() + " " + pipelineRun.getMetadata().getName());
+    public void onAdd(PipelineRun pipelineRun) {
+        try {
+            LOGGER.info("onAdd " + pipelineRun.getMetadata().getName());
+            PipelineStatus ps = getPipelineStatus(pipelineRun);
+            if (ps != null) infinispanService.savePipelineStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(PipelineRun oldPipelineRun, PipelineRun newPipelineRun) {
+        try {
+            LOGGER.info("onUpdate " + newPipelineRun.getMetadata().getName());
+            PipelineStatus ps = getPipelineStatus(newPipelineRun);
+            if (ps != null) infinispanService.savePipelineStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(PipelineRun pipelineRun, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + pipelineRun.getMetadata().getName());
+            String projectId = pipelineRun.getMetadata().getLabels().get("karavan-project-id");
+            if (projectId != null) {
+                Project project = infinispanService.getProject(projectId);
+                if (project != null) {
+                    PipelineStatus ps = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
+                    infinispanService.deletePipelineStatus(ps);
+                }
+            }
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    public PipelineStatus getPipelineStatus( PipelineRun pipelineRun) {
         String projectId = pipelineRun.getMetadata().getLabels().get("karavan-project-id");
         if (projectId != null) {
             Project project = infinispanService.getProject(projectId);
-            if (project != null && List.of("MODIFIED", "ADDED").contains(action.name())) {
-                PipelineStatus pipelineStatus = infinispanService.getPipelineStatus(projectId);
-                if (pipelineStatus == null) pipelineStatus = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
+            if (project != null) {
+                PipelineStatus pipelineStatus = new PipelineStatus(project.getProjectId(), kubernetesService.environment);
 
                 if (pipelineRun.getStatus() != null) {
-                    LOGGER.info(action.name()+ " " + pipelineRun.getMetadata().getName() + " " + pipelineRun.getStatus().getConditions().get(0).getReason());
                     Instant runStartTime = Instant.parse(pipelineRun.getStatus().getStartTime());
                     Instant savedStartTime = pipelineStatus.getStartTime() != null
                             ? Instant.parse(pipelineStatus.getStartTime())
@@ -52,9 +85,10 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
                     pipelineStatus.setStartTime(null);
                     pipelineStatus.setCompletionTime(null);
                 }
-                infinispanService.savePipelineStatus(pipelineStatus);
+                return pipelineStatus;
             }
         }
+        return null;
     }
 
     private Long getPipelineRunDuration(PipelineRun pipelineRun) {
@@ -69,9 +103,4 @@ public class PipelineRunWatcher implements Watcher<PipelineRun> {
             return 0L;
         }
     }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
 }
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
new file mode 100644
index 0000000..8d3af7c
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodEventHandler.java
@@ -0,0 +1,84 @@
+package org.apache.camel.karavan.watcher;
+
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.PodCondition;
+import io.fabric8.kubernetes.client.informers.ResourceEventHandler;
+import org.apache.camel.karavan.model.PodStatus;
+import org.apache.camel.karavan.service.InfinispanService;
+import org.apache.camel.karavan.service.KubernetesService;
+import org.jboss.logging.Logger;
+
+import java.util.Optional;
+
+public class PodEventHandler implements ResourceEventHandler<Pod> {
+
+    private static final Logger LOGGER = Logger.getLogger(PodEventHandler.class.getName());
+    private InfinispanService infinispanService;
+    private KubernetesService kubernetesService;
+
+    public PodEventHandler(InfinispanService infinispanService, KubernetesService kubernetesService) {
+        this.infinispanService = infinispanService;
+        this.kubernetesService = kubernetesService;
+    }
+
+    @Override
+    public void onAdd(Pod pod) {
+        try {
+            LOGGER.info("onAdd " + pod.getMetadata().getName());
+            PodStatus ps = getPodStatus(pod);
+            infinispanService.savePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onUpdate(Pod oldPod, Pod newPod) {
+        try {
+            LOGGER.info("onUpdate " + newPod.getMetadata().getName());
+            PodStatus ps = getPodStatus(newPod);
+            infinispanService.savePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+    @Override
+    public void onDelete(Pod pod, boolean deletedFinalStateUnknown) {
+        try {
+            LOGGER.info("onDelete " + pod.getMetadata().getName());
+            String deployment = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
+            PodStatus ps = new PodStatus(
+                    pod.getMetadata().getName(),
+                    deployment,
+                    kubernetesService.environment);
+            infinispanService.deletePodStatus(ps);
+        } catch (Exception e){
+            LOGGER.error(e.getMessage());
+        }
+    }
+
+
+    public PodStatus getPodStatus(Pod pod) {
+        String deployment = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
+        try {
+            Optional<PodCondition> initialized = pod.getStatus().getConditions().stream().filter(c -> c.getType().equals("Initialized")).findFirst();
+            Optional<PodCondition> ready = pod.getStatus().getConditions().stream().filter(c -> c.getType().equals("Initialized")).findFirst();
+            return new PodStatus(
+                    pod.getMetadata().getName(),
+                    pod.getStatus().getPhase(),
+                    initialized.isEmpty() ? false : initialized.get().getStatus().equals("True"),
+                    ready.isEmpty() ? false : ready.get().getStatus().equals("True"),
+                    pod.getStatus().getReason(),
+                    deployment,
+                    kubernetesService.environment
+            );
+        } catch (Exception ex) {
+            LOGGER.error(ex.getMessage());
+            return new PodStatus(
+                    pod.getMetadata().getName(),
+                    deployment,
+                    kubernetesService.environment);
+        }
+    }
+}
\ No newline at end of file
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java b/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
deleted file mode 100644
index 99e0982..0000000
--- a/karavan-app/src/main/java/org/apache/camel/karavan/watcher/PodWatcher.java
+++ /dev/null
@@ -1,40 +0,0 @@
-package org.apache.camel.karavan.watcher;
-
-import io.fabric8.kubernetes.api.model.Pod;
-import io.fabric8.kubernetes.api.model.apps.Deployment;
-import io.fabric8.kubernetes.client.Watcher;
-import io.fabric8.kubernetes.client.WatcherException;
-import org.apache.camel.karavan.model.DeploymentStatus;
-import org.apache.camel.karavan.model.Project;
-import org.apache.camel.karavan.service.InfinispanService;
-import org.apache.camel.karavan.service.KubernetesService;
-import org.jboss.logging.Logger;
-
-public class PodWatcher implements Watcher<Pod> {
-
-    private static final Logger LOGGER = Logger.getLogger(PodWatcher.class.getName());
-    private InfinispanService infinispanService;
-    private KubernetesService kubernetesService;
-
-    public PodWatcher(InfinispanService infinispanService, KubernetesService kubernetesService) {
-        this.infinispanService = infinispanService;
-        this.kubernetesService = kubernetesService;
-    }
-
-    @Override
-    public void eventReceived(Action action, Pod pod) {
-        LOGGER.info(action.name() + " " + pod.getMetadata().getName());
-        String name = pod.getMetadata().getLabels().get("app.kubernetes.io/name");
-//        Project project = infinispanService.getProject(name);
-//        Deployment deployment = kubernetesService.getDeployment(name, pod.getMetadata().getNamespace());
-//        if (project != null && deployment != null) {
-//            DeploymentStatus s = kubernetesService.getDeploymentStatus(project.getProjectId(), deployment);
-//            infinispanService.saveDeploymentStatus(s);
-//        }
-    }
-
-    @Override
-    public void onClose(WatcherException cause) {
-
-    }
-}
\ No newline at end of file


[camel-karavan] 03/08: Bump version in karavan-core

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 407a5104936489bd9f7d8afa36225e1d0fc5cd18
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Oct 26 20:23:15 2022 -0400

    Bump version in karavan-core
---
 karavan-core/package-lock.json | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/karavan-core/package-lock.json b/karavan-core/package-lock.json
index da78f8a..0331029 100644
--- a/karavan-core/package-lock.json
+++ b/karavan-core/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "karavan-core",
-  "version": "3.18.4",
+  "version": "3.18.5",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "karavan-core",
-      "version": "3.18.4",
+      "version": "3.18.5",
       "license": "Apache-2.0",
       "dependencies": {
         "@types/js-yaml": "^4.0.5",


[camel-karavan] 06/08: Get DeploymentStatus fron new API

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 72707e7c2de18d51c8fb207e4c4f253c0698e2b9
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 10:29:25 2022 -0400

    Get DeploymentStatus fron new API
---
 karavan-app/src/main/webapp/src/Main.tsx           |  3 +-
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx | 11 +++++
 .../src/main/webapp/src/projects/ProjectInfo.tsx   | 48 +++++++++++-----------
 .../src/main/webapp/src/projects/ProjectModels.ts  |  7 ++--
 .../src/main/webapp/src/projects/ProjectPage.tsx   |  3 +-
 .../src/main/webapp/src/projects/ProjectsPage.tsx  | 20 ++++++---
 6 files changed, 55 insertions(+), 37 deletions(-)

diff --git a/karavan-app/src/main/webapp/src/Main.tsx b/karavan-app/src/main/webapp/src/Main.tsx
index adea4ca..4d7acb5 100644
--- a/karavan-app/src/main/webapp/src/Main.tsx
+++ b/karavan-app/src/main/webapp/src/Main.tsx
@@ -32,7 +32,6 @@ import EipIcon from "@patternfly/react-icons/dist/js/icons/topology-icon";
 import ComponentsIcon from "@patternfly/react-icons/dist/js/icons/module-icon";
 import ConfigurationIcon from "@patternfly/react-icons/dist/js/icons/cogs-icon";
 import {MainLogin} from "./MainLogin";
-import {Thenable} from "monaco-editor";
 
 class ToastMessage {
     id: string = ''
@@ -125,7 +124,7 @@ export class Main extends React.Component<Props, State> {
 
     getData() {
         KaravanApi.getConfiguration((config: any) => {
-            this.setState({ config: config })
+            this.setState({ config: config });
         });
         this.updateKamelets();
         this.updateComponents();
diff --git a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index 50379ba..d05e95b 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -290,6 +290,17 @@ export class KaravanApi {
         });
     }
 
+    static async getDeploymentStatuses(env: string, after: (statuses: DeploymentStatus[]) => void) {
+        instance.get('/api/kubernetes/deployment/' + env)
+            .then(res => {
+                if (res.status === 200) {
+                    after(res.data);
+                }
+            }).catch(err => {
+            console.log(err);
+        });
+    }
+
     static async rolloutDeployment(name: string, environment: string, after: (res: AxiosResponse<any>) => void) {
         instance.post('/api/kubernetes/deployment/rollout/' + environment + '/' + name, "")
             .then(res => {
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index 16ce1a3..0148cab 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -263,34 +263,34 @@ export class ProjectInfo extends React.Component<Props, State> {
     }
 
     getPodsPanel(deploymentStatus: DeploymentStatus, env: string) {
-        const podStatuses = deploymentStatus.podStatuses;
+        // const podStatuses = deploymentStatus.podStatuses;
         return (
             <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
                 <FlexItem>
                     <LabelGroup numLabels={3}>
-                        {(podStatuses === undefined || podStatuses.length === 0) && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}
-                        {podStatuses.map(pod => {
-                                const running = pod.started && pod.ready;
-                                return (
-                                    <Tooltip key={pod.name} content={running ? "Running" : pod.reason}>
-                                        <Label icon={running ? <UpIcon/> : <DownIcon/>} color={running ? "green" : "red"}>
-                                            <Button variant="link"
-                                                    onClick={e => this.props.showLog?.call(this, 'container', pod.name, env)}>
-                                                {pod.name}
-                                            </Button>
-                                            <Tooltip content={"Delete Pod"}>
-                                                <Button icon={<DeleteIcon/>} variant="link" onClick={e => this.setState({
-                                                    showDeleteConfirmation: true,
-                                                    deleteEntity: "pod",
-                                                    deleteEntityEnv: env,
-                                                    deleteEntityName: pod.name
-                                                })}></Button>
-                                            </Tooltip>
-                                        </Label>
-                                    </Tooltip>
-                                )
-                            }
-                        )}
+                        {/*{(podStatuses === undefined || podStatuses.length === 0) && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}*/}
+                        {/*{podStatuses.map(pod => {*/}
+                        {/*        const running = pod.started && pod.ready;*/}
+                        {/*        return (*/}
+                        {/*            <Tooltip key={pod.name} content={running ? "Running" : pod.reason}>*/}
+                        {/*                <Label icon={running ? <UpIcon/> : <DownIcon/>} color={running ? "green" : "red"}>*/}
+                        {/*                    <Button variant="link"*/}
+                        {/*                            onClick={e => this.props.showLog?.call(this, 'container', pod.name, env)}>*/}
+                        {/*                        {pod.name}*/}
+                        {/*                    </Button>*/}
+                        {/*                    <Tooltip content={"Delete Pod"}>*/}
+                        {/*                        <Button icon={<DeleteIcon/>} variant="link" onClick={e => this.setState({*/}
+                        {/*                            showDeleteConfirmation: true,*/}
+                        {/*                            deleteEntity: "pod",*/}
+                        {/*                            deleteEntityEnv: env,*/}
+                        {/*                            deleteEntityName: pod.name*/}
+                        {/*                        })}></Button>*/}
+                        {/*                    </Tooltip>*/}
+                        {/*                </Label>*/}
+                        {/*            </Tooltip>*/}
+                        {/*        )*/}
+                        {/*    }*/}
+                        {/*)}*/}
                     </LabelGroup>
                 </FlexItem>
                 <FlexItem>{env === "dev" && this.rolloutButton()}</FlexItem>
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectModels.ts b/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
index 16ae793..2f6eeb9 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
+++ b/karavan-app/src/main/webapp/src/projects/ProjectModels.ts
@@ -3,7 +3,6 @@ export class Project {
     name: string = '';
     description: string = '';
     lastCommit: string = '';
-    deployed: boolean = false;
 
     public constructor(projectId: string, name: string, description: string, lastCommit: string);
     public constructor(init?: Partial<Project>);
@@ -22,16 +21,18 @@ export class Project {
 }
 
 export class DeploymentStatus {
-    projectId: string = '';
+    name: string = '';
+    env: string = '';
+    namespace: string = '';
     image: string = '';
     replicas: number = 0;
     readyReplicas: number = 0;
     unavailableReplicas: number = 0;
-    podStatuses: PodStatus[] = []
 }
 
 export class PodStatus {
     name: string = '';
+    phase: string = '';
     started: boolean = false;
     ready: boolean = false;
     reason: string = '';
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
index 8d2a38b..cc3a708 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectPage.tsx
@@ -83,8 +83,7 @@ export class ProjectPage extends React.Component<Props, State> {
         tab: "details",
         environments: this.props.config.environments && Array.isArray(this.props.config.environments)
             ? Array.from(this.props.config.environments) : [],
-        environment: this.props.config.environments && Array.isArray(this.props.config.environments)
-            ? this.props.config.environments[0] : ''
+        environment: this.props.config.environment
     };
 
     componentDidMount() {
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
index 0b290d8..744c19f 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectsPage.tsx
@@ -29,7 +29,7 @@ import '../designer/karavan.css';
 import {MainToolbar} from "../MainToolbar";
 import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
 import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
-import {Project} from "./ProjectModels";
+import {DeploymentStatus, Project} from "./ProjectModels";
 import {TableComposable, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
 import SearchIcon from '@patternfly/react-icons/dist/esm/icons/search-icon';
@@ -45,6 +45,7 @@ interface Props {
 
 interface State {
     projects: Project[],
+    deploymentStatuses: DeploymentStatus[],
     isCreateModalOpen: boolean,
     isDeleteModalOpen: boolean,
     isCopy: boolean,
@@ -60,6 +61,7 @@ export class ProjectsPage extends React.Component<Props, State> {
 
     public state: State = {
         projects: [],
+        deploymentStatuses: [],
         isCreateModalOpen: false,
         isDeleteModalOpen: false,
         isCopy: false,
@@ -71,7 +73,7 @@ export class ProjectsPage extends React.Component<Props, State> {
     interval: any;
 
     componentDidMount() {
-        this.interval = setInterval(() => this.onGetProjects(), 700);
+        this.interval = setInterval(() => this.onGetProjects(), 1300);
     }
 
     componentWillUnmount() {
@@ -112,6 +114,9 @@ export class ProjectsPage extends React.Component<Props, State> {
             KaravanApi.getProjects((projects: Project[]) => {
                 this.setState({ projects: projects })
             });
+            KaravanApi.getDeploymentStatuses(config.environment, (statuses: DeploymentStatus[]) => {
+                this.setState({ deploymentStatuses: statuses });
+            });
         });
 
     }
@@ -209,12 +214,15 @@ export class ProjectsPage extends React.Component<Props, State> {
         )
     }
 
+    isDeployed(projectId: string): boolean{
+        const ds = this.state.deploymentStatuses.find(ds => ds.name === projectId);
+        return ds ? (ds.replicas > 0 && ds.replicas === ds.readyReplicas) : false;
+    }
+
     render() {
         const runtime = this.props.config?.runtime ? this.props.config.runtime : "QUARKUS";
         const projects = this.state.projects.filter(p => p.name.toLowerCase().includes(this.state.filter) || p.description.toLowerCase().includes(this.state.filter));
-        const environments: string[] = this.props.config.environments && Array.isArray(this.props.config.environments)
-            ? Array.from(this.props.config.environments)
-            : [];
+        const environment: string = this.props.config.environment;
         return (
             <PageSection className="kamelet-section projects-page" padding={{default: 'noPadding'}}>
                 <PageSection className="tools-section" padding={{default: 'noPadding'}}>
@@ -255,7 +263,7 @@ export class ProjectsPage extends React.Component<Props, State> {
                                     </Td>
                                     <Td noPadding style={{width:"180px"}}>
                                         <Flex direction={{default: "row"}}>
-                                            <FlexItem key={"dev"}><Badge isRead={!project.deployed}>{"dev"}</Badge></FlexItem>
+                                            <FlexItem key={"dev"}><Badge isRead={!this.isDeployed(project.projectId)}>{"dev"}</Badge></FlexItem>
                                         </Flex>
                                     </Td>
                                     <Td isActionCell>


[camel-karavan] 07/08: Get PodStatus from new API

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 441ac2ae32ed31b255c444a74c201d8823186d2a
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 10:39:16 2022 -0400

    Get PodStatus from new API
---
 .../camel/karavan/api/KubernetesResource.java      |  9 ++++
 karavan-app/src/main/webapp/src/api/KaravanApi.tsx | 20 +++++++-
 .../src/main/webapp/src/projects/ProjectInfo.tsx   | 59 ++++++++++++----------
 3 files changed, 60 insertions(+), 28 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
index c79fc51..ebe0cc1 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/KubernetesResource.java
@@ -137,6 +137,15 @@ public class KubernetesResource {
                 .collect(Collectors.toList());
     }
 
+    @GET
+    @Produces(MediaType.APPLICATION_JSON)
+    @Path("/pod/{projectId}/{env}")
+    public List<PodStatus> getPodStatusesByProjectAndEnv(@PathParam("projectId") String projectId, @PathParam("env") String env) throws Exception {
+        return infinispanService.getPodStatuses(projectId, env).stream()
+                .sorted(Comparator.comparing(PodStatus::getName))
+                .collect(Collectors.toList());
+    }
+
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
diff --git a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
index d05e95b..ad3b9a6 100644
--- a/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webapp/src/api/KaravanApi.tsx
@@ -1,5 +1,12 @@
 import axios, {AxiosResponse} from "axios";
-import {CamelStatus, DeploymentStatus, PipelineStatus, Project, ProjectFile} from "../projects/ProjectModels";
+import {
+    CamelStatus,
+    DeploymentStatus,
+    PipelineStatus,
+    PodStatus,
+    Project,
+    ProjectFile
+} from "../projects/ProjectModels";
 import {Buffer} from 'buffer';
 import {SsoApi} from "./SsoApi";
 
@@ -319,6 +326,17 @@ export class KaravanApi {
         });
     }
 
+    static async getProjectPodStatuses(project: string, env: string, after: (statuses: PodStatus[]) => void) {
+        instance.get('/api/kubernetes/pod/' + project + "/" + env)
+            .then(res => {
+                if (res.status === 200) {
+                    after(res.data);
+                }
+            }).catch(err => {
+            console.log(err);
+        });
+    }
+
     static async deletePod(environment: string, name: string, after: (res: AxiosResponse<any>) => void) {
         instance.delete('/api/kubernetes/pod/' + environment + '/' + name)
             .then(res => {
diff --git a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
index 0148cab..acbb7b2 100644
--- a/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
+++ b/karavan-app/src/main/webapp/src/projects/ProjectInfo.tsx
@@ -11,7 +11,7 @@ import {
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {KaravanApi} from "../api/KaravanApi";
-import {DeploymentStatus, Project, PipelineStatus, CamelStatus} from "./ProjectModels";
+import {DeploymentStatus, Project, PipelineStatus, CamelStatus, PodStatus} from "./ProjectModels";
 import BuildIcon from "@patternfly/react-icons/dist/esm/icons/build-icon";
 import RolloutIcon from "@patternfly/react-icons/dist/esm/icons/process-automation-icon";
 import PushIcon from "@patternfly/react-icons/dist/esm/icons/code-branch-icon";
@@ -31,6 +31,7 @@ interface State {
     project?: Project,
     pipelineStatus?: PipelineStatus,
     deploymentStatus?: DeploymentStatus,
+    podStatuses: PodStatus[],
     camelStatus?: CamelStatus,
     isPushing: boolean,
     isBuilding: boolean,
@@ -48,14 +49,14 @@ export class ProjectInfo extends React.Component<Props, State> {
 
     public state: State = {
         project: this.props.project,
+        podStatuses: [],
         isPushing: false,
         isBuilding: false,
         isRolling: false,
         showDeleteConfirmation: false,
         environments: this.props.config.environments && Array.isArray(this.props.config.environments)
             ? Array.from(this.props.config.environments) : [],
-        environment: this.props.config.environments && Array.isArray(this.props.config.environments)
-            ? this.props.config.environments[0] : ''
+        environment: this.props.config.environment
     };
     interval: any;
 
@@ -89,6 +90,10 @@ export class ProjectInfo extends React.Component<Props, State> {
                 this.setState({key: Math.random().toString(), deploymentStatus: status});
                 // console.log(status);
             });
+            KaravanApi.getProjectPodStatuses(this.props.project.projectId, this.state.environment, (statuses: PodStatus[]) => {
+                this.setState({key: Math.random().toString(), podStatuses: statuses});
+                // console.log(status);
+            });
             KaravanApi.getProjectCamelStatus(this.props.project.projectId, (status: CamelStatus) => {
                 this.setState({key: Math.random().toString(), camelStatus: status});
                 // console.log(status);
@@ -263,34 +268,34 @@ export class ProjectInfo extends React.Component<Props, State> {
     }
 
     getPodsPanel(deploymentStatus: DeploymentStatus, env: string) {
-        // const podStatuses = deploymentStatus.podStatuses;
+        const podStatuses = this.state.podStatuses;
         return (
             <Flex justifyContent={{default: "justifyContentSpaceBetween"}} alignItems={{default: "alignItemsCenter"}}>
                 <FlexItem>
                     <LabelGroup numLabels={3}>
-                        {/*{(podStatuses === undefined || podStatuses.length === 0) && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}*/}
-                        {/*{podStatuses.map(pod => {*/}
-                        {/*        const running = pod.started && pod.ready;*/}
-                        {/*        return (*/}
-                        {/*            <Tooltip key={pod.name} content={running ? "Running" : pod.reason}>*/}
-                        {/*                <Label icon={running ? <UpIcon/> : <DownIcon/>} color={running ? "green" : "red"}>*/}
-                        {/*                    <Button variant="link"*/}
-                        {/*                            onClick={e => this.props.showLog?.call(this, 'container', pod.name, env)}>*/}
-                        {/*                        {pod.name}*/}
-                        {/*                    </Button>*/}
-                        {/*                    <Tooltip content={"Delete Pod"}>*/}
-                        {/*                        <Button icon={<DeleteIcon/>} variant="link" onClick={e => this.setState({*/}
-                        {/*                            showDeleteConfirmation: true,*/}
-                        {/*                            deleteEntity: "pod",*/}
-                        {/*                            deleteEntityEnv: env,*/}
-                        {/*                            deleteEntityName: pod.name*/}
-                        {/*                        })}></Button>*/}
-                        {/*                    </Tooltip>*/}
-                        {/*                </Label>*/}
-                        {/*            </Tooltip>*/}
-                        {/*        )*/}
-                        {/*    }*/}
-                        {/*)}*/}
+                        {(podStatuses === undefined || podStatuses.length === 0) && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}
+                        {podStatuses.map(pod => {
+                                const running = pod.phase === 'Running'
+                                return (
+                                    <Tooltip key={pod.name} content={running ? "Running" : pod.phase}>
+                                        <Label icon={running ? <UpIcon/> : <DownIcon/>} color={running ? "green" : "red"}>
+                                            <Button variant="link"
+                                                    onClick={e => this.props.showLog?.call(this, 'container', pod.name, env)}>
+                                                {pod.name}
+                                            </Button>
+                                            <Tooltip content={"Delete Pod"}>
+                                                <Button icon={<DeleteIcon/>} variant="link" onClick={e => this.setState({
+                                                    showDeleteConfirmation: true,
+                                                    deleteEntity: "pod",
+                                                    deleteEntityEnv: env,
+                                                    deleteEntityName: pod.name
+                                                })}></Button>
+                                            </Tooltip>
+                                        </Label>
+                                    </Tooltip>
+                                )
+                            }
+                        )}
                     </LabelGroup>
                 </FlexItem>
                 <FlexItem>{env === "dev" && this.rolloutButton()}</FlexItem>


[camel-karavan] 04/08: Rename karavan.config to karavan.default

Posted by ma...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

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

commit 0072d05c7700d9884b3de30d574f78ff9763f353
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Thu Oct 27 08:31:03 2022 -0400

    Rename karavan.config to karavan.default
---
 .../org/apache/camel/karavan/api/ConfigurationResource.java    |  2 +-
 .../org/apache/camel/karavan/service/GeneratorService.java     | 10 ++++------
 .../java/org/apache/camel/karavan/service/ImportService.java   |  2 +-
 .../org/apache/camel/karavan/service/InfinispanService.java    |  2 +-
 .../org/apache/camel/karavan/service/KubernetesService.java    |  1 -
 karavan-app/src/main/resources/application.properties          |  8 ++++----
 6 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
index cf17e9b..7980e61 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/ConfigurationResource.java
@@ -37,7 +37,7 @@ public class ConfigurationResource {
     @ConfigProperty(name = "karavan.environment")
     String environment;
 
-    @ConfigProperty(name = "karavan.config.runtime")
+    @ConfigProperty(name = "karavan.default.runtime")
     String runtime;
 
     @Inject
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
index 9c7d931..70e0485 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/GeneratorService.java
@@ -30,24 +30,22 @@ import org.yaml.snakeyaml.Yaml;
 import org.yaml.snakeyaml.constructor.SafeConstructor;
 
 import javax.enterprise.context.ApplicationScoped;
-import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.nio.file.Paths;
 import java.util.Map;
 
 @ApplicationScoped
 public class GeneratorService {
 
-    @ConfigProperty(name = "karavan.config.group-id")
+    @ConfigProperty(name = "karavan.default.group-id")
     String groupId;
 
-    @ConfigProperty(name = "karavan.config.image-group")
+    @ConfigProperty(name = "karavan.default.image-group")
     String imageGroup;
 
-    @ConfigProperty(name = "karavan.config.runtime")
+    @ConfigProperty(name = "karavan.default.runtime")
     String runtime;
 
-    @ConfigProperty(name = "karavan.config.runtime-version")
+    @ConfigProperty(name = "karavan.default.runtime-version")
     String runtimeVersion;
 
     private static final Logger LOGGER = Logger.getLogger(GeneratorService.class.getName());
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
index c83a121..33d59f4 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/ImportService.java
@@ -44,7 +44,7 @@ public class ImportService {
     @Inject
     GitService gitService;
 
-    @ConfigProperty(name = "karavan.config.runtime")
+    @ConfigProperty(name = "karavan.default.runtime")
     String runtime;
 
     @ConsumeEvent(value = IMPORT_PROJECTS, blocking = true)
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
index 88db2e3..9a0fd03 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/InfinispanService.java
@@ -65,7 +65,7 @@ public class InfinispanService {
     @Inject
     GeneratorService generatorService;
 
-    @ConfigProperty(name = "karavan.config.runtime")
+    @ConfigProperty(name = "karavan.default.runtime")
     String runtime;
 
     private static final String CACHE_CONFIG = "<distributed-cache name=\"%s\">"
diff --git a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
index 626eb93..735b47e 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/service/KubernetesService.java
@@ -39,7 +39,6 @@ import io.fabric8.tekton.pipeline.v1beta1.WorkspaceBindingBuilder;
 import io.quarkus.runtime.ShutdownEvent;
 import io.quarkus.vertx.ConsumeEvent;
 import io.vertx.mutiny.core.eventbus.EventBus;
-import org.apache.camel.karavan.model.DeploymentStatus;
 import org.apache.camel.karavan.model.PipelineRunLog;
 import org.apache.camel.karavan.model.Project;
 import org.apache.camel.karavan.watcher.DeploymentWatcher;
diff --git a/karavan-app/src/main/resources/application.properties b/karavan-app/src/main/resources/application.properties
index 6c1a38c..d13b127 100644
--- a/karavan-app/src/main/resources/application.properties
+++ b/karavan-app/src/main/resources/application.properties
@@ -16,10 +16,10 @@ karavan.kamelets-git-password=${GIT_TOKEN}
 karavan.kamelets-git-branch=main
 
 # Projects default configuration
-karavan.config.group-id=org.camel.karavan.demo
-karavan.config.image-group=karavan
-karavan.config.runtime=QUARKUS
-karavan.config.runtime-version=2.13.3.Final
+karavan.default.group-id=org.camel.karavan.demo
+karavan.default.image-group=karavan
+karavan.default.runtime=QUARKUS
+karavan.default.runtime-version=2.13.3.Final
 
 # Infinispan Server address
 #quarkus.infinispan-client.server-list=localhost:12345