You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/08/18 18:34:03 UTC

[camel-karavan] branch main updated (575dff39 -> f91a1125)

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 575dff39 Update Dockerfile.devmode #861
     new cc275e77 Simplify page navigation #864
     new f91a1125 Fix #865

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


Summary of changes:
 .../camel/karavan/api/InfrastructureResource.java  |  10 +-
 .../apache/camel/karavan/api/StatusResource.java   |  17 +-
 .../src/main/resources/services/devservices.yaml   |  15 +-
 .../src/main/webui/src/api/KaravanApi.tsx          |   6 +-
 .../src/main/webui/src/api/ProjectStore.ts         |  73 +++++-
 .../src/main/webui/src/dashboard/DashboardPage.tsx |  66 +----
 .../karavan-app/src/main/webui/src/index.css       |   2 +-
 .../karavan-app/src/main/webui/src/main/Main.tsx   | 106 ++------
 .../src/main/webui/src/main/MainDataPoller.tsx     |  62 +++++
 .../src/main/webui/src/main/MainLogin.tsx          | 102 ++++----
 .../src/main/webui/src/main/PageNavigation.tsx     |  17 +-
 .../src/main/{DataPoller.tsx => useMainHook.tsx}   |  29 +--
 .../main/webui/src/project/ProjectDataPoller.tsx   |  61 +++++
 .../src/main/webui/src/project/ProjectPage.tsx     |   2 +
 .../webui/src/project/dashboard/DashboardTab.tsx   |  44 +---
 .../main/webui/src/project/files/FilesToolbar.tsx  |   1 -
 .../main/webui/src/project/log/ProjectLogPanel.tsx |   2 -
 .../src/project/pipeline/ProjectPipelineTab.tsx    |   4 +-
 .../webui/src/project/pipeline/ProjectStatus.tsx   | 285 +++++++++------------
 .../src/project/trace/RunnerInfoTraceModal.tsx     |   4 +-
 .../src/project/trace/RunnerInfoTraceNode.tsx      |   4 +-
 .../src/main/webui/src/project/trace/TraceTab.tsx  |  36 +--
 .../src/main/webui/src/projects/ProjectsPage.tsx   |  38 +--
 .../karavan/infinispan/InfinispanService.java      |   7 +
 24 files changed, 461 insertions(+), 532 deletions(-)
 create mode 100644 karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
 rename karavan-web/karavan-app/src/main/webui/src/main/{DataPoller.tsx => useMainHook.tsx} (74%)
 create mode 100644 karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx


[camel-karavan] 01/02: Simplify page navigation #864

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 cc275e776b238d718d5af93ef23d53befac08530
Author: Marat Gubaidullin <ma...@Marats-MacBook-Pro.local>
AuthorDate: Fri Aug 18 09:05:27 2023 -0400

    Simplify page navigation #864
---
 .../src/main/webui/src/api/ProjectStore.ts         |  6 --
 .../src/main/webui/src/main/DataPoller.tsx         |  8 +-
 .../karavan-app/src/main/webui/src/main/Main.tsx   | 86 ++++------------------
 .../src/main/webui/src/main/PageNavigation.tsx     |  3 +-
 .../src/main/{DataPoller.tsx => useMainHook.tsx}   | 29 ++------
 5 files changed, 25 insertions(+), 107 deletions(-)

diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
index eba4c0c4..651c1071 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -23,19 +23,13 @@ import {unstable_batchedUpdates} from "react-dom";
 interface AppConfigState {
     config: AppConfig;
     setConfig: (config: AppConfig) => void;
-    pageId: string;
-    setPageId: (pageId: string) => void;
 }
 
 export const useAppConfigStore = create<AppConfigState>((set) => ({
     config: new AppConfig(),
-    pageId: 'projects',
     setConfig: (config: AppConfig)  => {
         set({config: config})
     },
-    setPageId: (pageId: string)  => {
-        set({pageId: pageId})
-    },
 }))
 
 
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
index e3c0998a..3b917172 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
@@ -1,10 +1,8 @@
-import React, {useEffect, useState} from 'react';
+import React, {useEffect} from 'react';
 
 import {KaravanApi} from "../api/KaravanApi";
-import {SsoApi} from "../api/SsoApi";
 import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import '../designer/karavan.css';
-import {v4 as uuidv4} from "uuid";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {AppConfig, ContainerStatus} from "../api/ProjectModels";
 import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore";
@@ -13,9 +11,8 @@ import {shallow} from "zustand/shallow";
 
 export const DataPoller = () => {
 
-    const [config, pageId, setPageId, setConfig] = useAppConfigStore((state) => [state.config, state.pageId, state.setPageId, state.setConfig], shallow)
+    const [setConfig] = useAppConfigStore((state) => [state.setConfig], shallow)
     const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow);
-    const [request, setRequest] = useState<string>(uuidv4());
 
     useEffect(() => {
         console.log("DataPoller Start");
@@ -39,7 +36,6 @@ export const DataPoller = () => {
     function getData() {
         if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
             KaravanApi.getConfiguration((config: AppConfig) => {
-                setRequest(uuidv4());
                 setConfig(config);
                 InfrastructureAPI.infrastructure = config.infrastructure;
             });
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index c98fcf68..3cf72154 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -1,6 +1,6 @@
 import {Routes, Route, useNavigate, Navigate} from 'react-router-dom';
 import {useLocation} from 'react-router-dom';
-import React, {useEffect, useState} from "react";
+import React, {useEffect, useRef, useState} from "react";
 import {KaravanApi} from "../api/KaravanApi";
 import {Bullseye, Flex, FlexItem, Page, Spinner} from "@patternfly/react-core";
 import Icon from "../Logo";
@@ -13,32 +13,32 @@ import {ServicesPage} from "../services/ServicesPage";
 import {ContainersPage} from "../containers/ContainersPage";
 import {KnowledgebasePage} from "../knowledgebase/KnowledgebasePage";
 import {ProjectEventBus} from "../api/ProjectEventBus";
-import {AppConfig, ContainerStatus, Project, ToastMessage} from "../api/ProjectModels";
+import {Project, ToastMessage} from "../api/ProjectModels";
 import {SsoApi} from "../api/SsoApi";
-import {v4 as uuidv4} from "uuid";
-import {InfrastructureAPI} from "../designer/utils/InfrastructureAPI";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore";
 import {shallow} from "zustand/shallow";
 import {PageNavigation} from "./PageNavigation";
+import {useMainHook} from "./useMainHook";
 
 export const Main = () => {
 
-    const [config, pageId, setPageId, setConfig] = useAppConfigStore((state) => [state.config, state.pageId, state.setPageId, state.setConfig], shallow)
-    const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow);
-    const [request, setRequest] = useState<string>(uuidv4());
-    let location = useLocation();
-    const navigate = useNavigate();
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const { getData, getStatuses } = useMainHook();
+
+    const initialized = useRef(false)
 
     useEffect(() => {
+        if (!initialized.current) {
+            initialized.current = true
+            effect()
+        }
+    }, [])
+
+    function effect() {
         console.log("Main Start");
         const interval = setInterval(() => {
             getStatuses();
         }, 1000);
-        const sub = ProjectEventBus.onSelectProject()?.subscribe((project: Project | undefined) => {
-            if (project) setPageId("project");
-        });
         KaravanApi.getAuthType((authType: string) => {
             console.log("authType", authType);
             if (authType === 'oidc') {
@@ -53,9 +53,8 @@ export const Main = () => {
         return () => {
             console.log("Main End");
             clearInterval(interval);
-            sub?.unsubscribe();
         };
-    }, []);
+    }
 
     function onLogin(username: string, password: string) {
         KaravanApi.auth(username, password, (res: any) => {
@@ -67,59 +66,6 @@ export const Main = () => {
         });
     }
 
-    function getStatuses() {
-        if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
-            KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
-                setContainers(statuses);
-            });
-        }
-    }
-
-    function getData() {
-        if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
-            KaravanApi.getConfiguration((config: AppConfig) => {
-                setRequest(uuidv4());
-                setConfig(config);
-                InfrastructureAPI.infrastructure = config.infrastructure;
-            });
-            updateKamelets();
-            updateComponents();
-            // updateSupportedComponents(); // not implemented yet
-        }
-    }
-
-    async function updateKamelets(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getKamelets(yamls => {
-                const kamelets: string[] = [];
-                yamls.split("\n---\n").map(c => c.trim()).forEach(z => kamelets.push(z));
-                KameletApi.saveKamelets(kamelets, true);
-            })
-            KaravanApi.getCustomKameletNames(names => {
-                KameletApi.saveCustomKameletNames(names);
-            })
-        });
-    }
-
-    async function updateComponents(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getComponents(code => {
-                const components: [] = JSON.parse(code);
-                const jsons: string[] = [];
-                components.forEach(c => jsons.push(JSON.stringify(c)));
-                ComponentApi.saveComponents(jsons, true);
-            })
-        });
-    }
-
-    async function updateSupportedComponents(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getSupportedComponents(jsons => {
-                ComponentApi.saveSupportedComponents(jsons);
-            })
-        });
-    }
-
     function toast(title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'custom') {
         ProjectEventBus.sendAlert(new ToastMessage(title, text, variant))
     }
@@ -152,7 +98,7 @@ export const Main = () => {
             }
             {!KaravanApi.isAuthorized && KaravanApi.authType === 'basic' &&
                 <MainLogin config={config} onLogin={onLogin}/>}
-            <Notification/>
+            {/*<Notification/>*/}
         </Page>
     );
 };
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
index 155affcc..648add20 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
@@ -33,10 +33,11 @@ class MenuItem {
 
 export const PageNavigation = () => {
 
-    const [config, pageId, setPageId] = useAppConfigStore((state) => [state.config, state.pageId, state.setPageId], shallow)
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
     const [setFile] = useFileStore((state) => [state.setFile], shallow)
     const [setStatus, setPodName] = useDevModeStore((state) => [state.setStatus, state.setPodName], shallow)
     const [showUser, setShowUser] = useState<boolean>(false);
+    const [pageId, setPageId] = useState<string>();
     const navigate = useNavigate();
 
     function getMenu() : MenuItem[]  {
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
similarity index 74%
copy from karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
copy to karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
index e3c0998a..6df01d20 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/useMainHook.tsx
@@ -1,34 +1,18 @@
-import React, {useEffect, useState} from 'react';
-
 import {KaravanApi} from "../api/KaravanApi";
-import {SsoApi} from "../api/SsoApi";
 import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import '../designer/karavan.css';
-import {v4 as uuidv4} from "uuid";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {AppConfig, ContainerStatus} from "../api/ProjectModels";
 import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore";
 import {InfrastructureAPI} from "../designer/utils/InfrastructureAPI";
 import {shallow} from "zustand/shallow";
 
-export const DataPoller = () => {
+export const useMainHook = () => {
 
-    const [config, pageId, setPageId, setConfig] = useAppConfigStore((state) => [state.config, state.pageId, state.setPageId, state.setConfig], shallow)
+    const [setConfig] = useAppConfigStore((state) => [state.setConfig], shallow)
     const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow);
-    const [request, setRequest] = useState<string>(uuidv4());
-
-    useEffect(() => {
-        console.log("DataPoller Start");
-        const interval = setInterval(() => {
-            getStatuses();
-        }, 1000);
-        return () => {
-            console.log("DataPoller End");
-            clearInterval(interval);
-        };
-    }, []);
 
-    function getStatuses() {
+    const getStatuses = () =>  {
         if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
             KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
                 setContainers(statuses);
@@ -36,10 +20,9 @@ export const DataPoller = () => {
         }
     }
 
-    function getData() {
+    const getData = () =>  {
         if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
             KaravanApi.getConfiguration((config: AppConfig) => {
-                setRequest(uuidv4());
                 setConfig(config);
                 InfrastructureAPI.infrastructure = config.infrastructure;
             });
@@ -81,7 +64,5 @@ export const DataPoller = () => {
         });
     }
 
-    return (
-        <React.Fragment></React.Fragment>
-    )
+    return { getData, getStatuses }
 }
\ No newline at end of file


[camel-karavan] 02/02: Fix #865

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 f91a11255e8a7f95dc63c087c1ad634a9cc19e56
Author: Marat Gubaidullin <ma...@Marats-MacBook-Pro.local>
AuthorDate: Fri Aug 18 14:33:01 2023 -0400

    Fix #865
---
 .../camel/karavan/api/InfrastructureResource.java  |  10 +-
 .../apache/camel/karavan/api/StatusResource.java   |  17 +-
 .../src/main/resources/services/devservices.yaml   |  15 +-
 .../src/main/webui/src/api/KaravanApi.tsx          |   6 +-
 .../src/main/webui/src/api/ProjectStore.ts         |  67 ++++-
 .../src/main/webui/src/dashboard/DashboardPage.tsx |  66 +----
 .../karavan-app/src/main/webui/src/index.css       |   2 +-
 .../src/main/webui/src/main/DataPoller.tsx         |  83 ------
 .../karavan-app/src/main/webui/src/main/Main.tsx   |  30 +--
 .../src/main/webui/src/main/MainDataPoller.tsx     |  62 +++++
 .../src/main/webui/src/main/MainLogin.tsx          | 102 ++++----
 .../src/main/webui/src/main/PageNavigation.tsx     |  16 +-
 .../main/webui/src/project/ProjectDataPoller.tsx   |  61 +++++
 .../src/main/webui/src/project/ProjectPage.tsx     |   2 +
 .../webui/src/project/dashboard/DashboardTab.tsx   |  44 +---
 .../main/webui/src/project/files/FilesToolbar.tsx  |   1 -
 .../main/webui/src/project/log/ProjectLogPanel.tsx |   2 -
 .../src/project/pipeline/ProjectPipelineTab.tsx    |   4 +-
 .../webui/src/project/pipeline/ProjectStatus.tsx   | 285 +++++++++------------
 .../src/project/trace/RunnerInfoTraceModal.tsx     |   4 +-
 .../src/project/trace/RunnerInfoTraceNode.tsx      |   4 +-
 .../src/main/webui/src/project/trace/TraceTab.tsx  |  36 +--
 .../src/main/webui/src/projects/ProjectsPage.tsx   |  38 +--
 .../karavan/infinispan/InfinispanService.java      |   7 +
 24 files changed, 444 insertions(+), 520 deletions(-)

diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
index 478205b5..931aa2c5 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/InfrastructureResource.java
@@ -156,9 +156,13 @@ public class InfrastructureResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/service")
     public List<ServiceStatus> getAllServiceStatuses() throws Exception {
-        return infinispanService.getServiceStatuses().stream()
-                .sorted(Comparator.comparing(ServiceStatus::getProjectId))
-                .collect(Collectors.toList());
+        if (infinispanService.isReady()) {
+            return infinispanService.getServiceStatuses().stream()
+                    .sorted(Comparator.comparing(ServiceStatus::getProjectId))
+                    .collect(Collectors.toList());
+        } else {
+            return List.of();
+        }
     }
 
     @GET
diff --git a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
index 3a584f36..b4dcd21d 100644
--- a/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
+++ b/karavan-web/karavan-app/src/main/java/org/apache/camel/karavan/api/StatusResource.java
@@ -44,13 +44,12 @@ public class StatusResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/pipeline/{projectId}/{env}")
-    public Response getPipelineStatus(@PathParam("projectId") String projectId, @PathParam("env") String env) {
-        PipelineStatus status = infinispanService.getPipelineStatus(projectId, env);
-        if (status != null) {
-            return Response.ok(status).build();
+    @Path("/pipeline/{env}")
+    public List<PipelineStatus> getPipelineStatuses(@PathParam("env") String env) {
+        if (infinispanService.isReady()) {
+            return infinispanService.getPipelineStatuses(env);
         } else {
-            return Response.noContent().build();
+            return List.of();
         }
     }
 
@@ -81,6 +80,10 @@ public class StatusResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Path("/camel/{env}")
     public List<CamelStatus> getCamelStatusByEnv(@PathParam("env") String env) {
-        return infinispanService.getCamelStatusesByEnv(env, CamelStatus.Name.context);
+        if (infinispanService.isReady()) {
+            return infinispanService.getCamelStatusesByEnv(env, CamelStatus.Name.context);
+        } else {
+            return List.of();
+        }
     }
 }
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/resources/services/devservices.yaml b/karavan-web/karavan-app/src/main/resources/services/devservices.yaml
index 1365fd9a..e921cd22 100644
--- a/karavan-web/karavan-app/src/main/resources/services/devservices.yaml
+++ b/karavan-web/karavan-app/src/main/resources/services/devservices.yaml
@@ -41,17 +41,20 @@ services:
       KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
       KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
 
-  mariadb:
-    image: mariadb
+  postgres:
+    image: postgres:15.4
     restart: always
     environment:
-      MARIADB_ROOT_PASSWORD: mariadb
+      - POSTGRES_USER=postgres
+      - POSTGRES_PASSWORD=postgres
+    ports:
+      - '5432:5432'
 
-  mariadb-adminer:
-    image: adminer
+  adminer:
+    image: adminer:4.8.1-standalone
     restart: always
     ports:
-      - 9080:8080
+      - 8080:8080
 
   greenmail:
     container_name: greenmail
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 43919f12..cd2213f2 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -155,13 +155,13 @@ export class KaravanApi {
         });
     }
 
-    static async getProjectPipelineStatus(projectId: string, env: string, after: (status?: PipelineStatus) => void) {
-        instance.get('/api/status/pipeline/' + projectId + "/" + env)
+    static async getPipelineStatuses(env: string, after: (status: PipelineStatus[]) => void) {
+        instance.get('/api/status/pipeline/' + env)
             .then(res => {
                 if (res.status === 200) {
                     after(res.data);
                 } else if (res.status === 204) {
-                    after(undefined);
+                    after([]);
                 }
 
             }).catch(err => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
index 651c1071..ed7f1acc 100644
--- a/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/api/ProjectStore.ts
@@ -16,16 +16,32 @@
  */
 
 import {create} from 'zustand'
-import {AppConfig, DeploymentStatus, ContainerStatus, Project, ProjectFile, ServiceStatus, CamelStatus} from "./ProjectModels";
+import {
+    AppConfig,
+    DeploymentStatus,
+    ContainerStatus,
+    Project,
+    ProjectFile,
+    ServiceStatus,
+    CamelStatus,
+    PipelineStatus
+} from "./ProjectModels";
 import {ProjectEventBus} from "./ProjectEventBus";
 import {unstable_batchedUpdates} from "react-dom";
+import {useState} from "react";
 
 interface AppConfigState {
+    loading: boolean;
+    setLoading: (loading: boolean) => void;
     config: AppConfig;
     setConfig: (config: AppConfig) => void;
 }
 
 export const useAppConfigStore = create<AppConfigState>((set) => ({
+    loading: false,
+    setLoading: (loading: boolean)  => {
+        set({loading: loading})
+    },
     config: new AppConfig(),
     setConfig: (config: AppConfig)  => {
         set({config: config})
@@ -56,12 +72,22 @@ export const useProjectsStore = create<ProjectsState>((set) => ({
 }))
 
 interface ProjectState {
-    project: Project;
     isPushing: boolean,
     isRunning: boolean,
-    operation: "create" | "select" | "delete" | "none" | "copy";
+    project: Project;
     setProject: (project: Project, operation:  "create" | "select" | "delete"| "none" | "copy") => void;
+    operation: "create" | "select" | "delete" | "none" | "copy";
     setOperation: (o: "create" | "select" | "delete"| "none" | "copy") => void;
+    memory: any,
+    setMemory: (memory: any) => void;
+    jvm: any,
+    setJvm: (jvm: any) => void;
+    context: any,
+    setContext: (context: any) => void;
+    trace: any,
+    setTrace: (trace: any) => void;
+    refreshTrace: boolean
+    setRefreshTrace: (refreshTrace: boolean) => void;
 }
 
 export const useProjectStore = create<ProjectState>((set) => ({
@@ -72,7 +98,12 @@ export const useProjectStore = create<ProjectState>((set) => ({
     setProject: (project: Project, operation:  "create" | "select" | "delete"| "none" | "copy") => {
         set((state: ProjectState) => ({
             project: project,
-            operation: operation
+            operation: operation,
+            refreshTrace: false,
+            jvm: {},
+            context: {},
+            trace: {},
+            memory: {},
         }));
     },
     setOperation: (o: "create" | "select" | "delete"| "none" | "copy") => {
@@ -80,6 +111,26 @@ export const useProjectStore = create<ProjectState>((set) => ({
             operation: o
         }));
     },
+    memory: {},
+    setMemory: (memory: boolean)  => {
+        set({memory: memory})
+    },
+    jvm: {},
+    setJvm: (jvm: boolean)  => {
+        set({jvm: jvm})
+    },
+    context: {},
+    setContext: (context: boolean)  => {
+        set({context: context})
+    },
+    trace: {},
+    setTrace: (trace: boolean)  => {
+        set({trace: trace})
+    },
+    refreshTrace: false,
+    setRefreshTrace: (refreshTrace: boolean)  => {
+        set({refreshTrace: refreshTrace})
+    },
 }))
 
 interface FilesState {
@@ -170,6 +221,8 @@ interface StatusesState {
     setServices: (s: ServiceStatus[]) => void;
     setContainers: (c: ContainerStatus[]) => void;
     setCamels: (c: CamelStatus[]) => void;
+    pipelineStatuses: PipelineStatus[],
+    setPipelineStatuses: (pipelineStatus: PipelineStatus[]) => void;
 }
 
 export const useStatusesStore = create<StatusesState>((set) => ({
@@ -196,7 +249,11 @@ export const useStatusesStore = create<StatusesState>((set) => ({
         set((state: StatusesState) => ({
             camels: c,
         }));
-    }
+    },
+    pipelineStatuses: [],
+    setPipelineStatuses: (pipelineStatuses: PipelineStatus[])  => {
+        set({pipelineStatuses: pipelineStatuses})
+    },
 }))
 
 interface LogState {
diff --git a/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx b/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
index 9b54deba..c032a31b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/dashboard/DashboardPage.tsx
@@ -1,4 +1,4 @@
-import React, {useEffect, useState} from 'react';
+import React, {useState} from 'react';
 import {
     Badge, Bullseye,
     Button, EmptyState, EmptyStateIcon, EmptyStateVariant,
@@ -26,11 +26,9 @@ import {
 	Table
 } from '@patternfly/react-table/deprecated';
 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";
-import RefreshIcon from "@patternfly/react-icons/dist/esm/icons/sync-alt-icon";
 import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
 import {MainToolbar} from "../designer/MainToolbar";
 import {useAppConfigStore, useProjectsStore, useStatusesStore} from "../api/ProjectStore";
@@ -44,51 +42,8 @@ export const DashboardPage = () => {
         = useStatusesStore((state) => [state.deployments, state.services, state.containers, state.camels,
         state.setDeployments, state.setServices, state.setContainers, state.setCamels], shallow);
     const [filter, setFilter] = useState<string>('');
-    const [loading, setLoading] = useState<boolean>(true);
     const [selectedEnv, setSelectedEnv] = useState<string[]>([config.environment]);
 
-    useEffect(() => {
-        const interval = setInterval(() => {
-            onGetProjects()
-        }, 1300);
-        return () => {
-            clearInterval(interval)
-        };
-    }, []);
-
-    function onGetProjects() {
-        KaravanApi.getConfiguration((config: any) => {
-            KaravanApi.getProjects((projects: Project[]) => {
-                setProjects(projects);
-            });
-            KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => {
-                setDeployments(statuses);
-            });
-            KaravanApi.getAllServiceStatuses((statuses: ServiceStatus[]) => {
-                setServices(statuses);
-            });
-            KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
-                setContainers(statuses);
-            });
-            selectedEnv.forEach(env => {
-                KaravanApi.getAllCamelStatuses(env, (statuses: CamelStatus[]) => {
-                    setCamels(statuses);
-                    setLoading(false);
-                    // setState((state) => {
-                    //     statuses.forEach(newStatus => {
-                    //         const index = state.camelStatuses.findIndex(s => s.projectId === newStatus.projectId && s.env === newStatus.env);
-                    //         if (index !== -1) {
-                    //             state.camelStatuses.splice(index, 1);
-                    //         }
-                    //         state.camelStatuses.push(newStatus);
-                    //     })
-                    //     return state;
-                    // })
-                });
-            });
-        });
-    }
-
     function selectEnvironment(name: string, selected: boolean) {
         if (selected && !selectedEnv.includes(name)) {
             setSelectedEnv((state: string[]) => {
@@ -105,9 +60,9 @@ export const DashboardPage = () => {
     function tools() {
         return (<Toolbar id="toolbar-group-types">
             <ToolbarContent>
-                <ToolbarItem>
-                    <Button variant="link" icon={<RefreshIcon/>} onClick={e => onGetProjects()}/>
-                </ToolbarItem>
+                {/*<ToolbarItem>*/}
+                {/*    <Button variant="link" icon={<RefreshIcon/>} onClick={e => onGetProjects()}/>*/}
+                {/*</ToolbarItem>*/}
                 <ToolbarItem>
                     <ToggleGroup aria-label="Default with single selectable">
                         {config.environments.map(env => (
@@ -170,9 +125,9 @@ export const DashboardPage = () => {
     }
 
     function getCamelStatusByEnvironments(name: string): [string, CamelStatus | undefined] [] {
-        return getSelectedEnvironments().map(e => {
+        return selectedEnv.map(e => {
             const env: string = e as string;
-            const status = camels.find(d => d.projectId === name && d.env === env);
+            const status = camels?.find(d => d.projectId === name && d.env === env);
             return [env, status];
         });
     }
@@ -222,12 +177,9 @@ export const DashboardPage = () => {
             <Tr>
                 <Td colSpan={8}>
                     <Bullseye>
-                        {loading && <Spinner className="progress-stepper" diameter="80px" aria-label="Loading..."/>}
-                        {!loading &&
-                            <EmptyState variant={EmptyStateVariant.sm}>
-                                <EmptyStateHeader titleText="No results found" icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2" />
-                            </EmptyState>
-                        }
+                        <EmptyState variant={EmptyStateVariant.sm}>
+                            <EmptyStateHeader titleText="No results found" icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2" />
+                        </EmptyState>
                     </Bullseye>
                 </Td>
             </Tr>
diff --git a/karavan-web/karavan-app/src/main/webui/src/index.css b/karavan-web/karavan-app/src/main/webui/src/index.css
index c013e3fd..d7ee69a5 100644
--- a/karavan-web/karavan-app/src/main/webui/src/index.css
+++ b/karavan-web/karavan-app/src/main/webui/src/index.css
@@ -28,7 +28,7 @@
 
 .karavan .nav-buttons .logo {
   margin-top: 16px;
-  margin-bottom: 10px;
+  margin-bottom: 16px;
   width: 32px;
   height: 32px;
 }
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
deleted file mode 100644
index 3b917172..00000000
--- a/karavan-web/karavan-app/src/main/webui/src/main/DataPoller.tsx
+++ /dev/null
@@ -1,83 +0,0 @@
-import React, {useEffect} from 'react';
-
-import {KaravanApi} from "../api/KaravanApi";
-import {KameletApi} from "karavan-core/lib/api/KameletApi";
-import '../designer/karavan.css';
-import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
-import {AppConfig, ContainerStatus} from "../api/ProjectModels";
-import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore";
-import {InfrastructureAPI} from "../designer/utils/InfrastructureAPI";
-import {shallow} from "zustand/shallow";
-
-export const DataPoller = () => {
-
-    const [setConfig] = useAppConfigStore((state) => [state.setConfig], shallow)
-    const [setContainers] = useStatusesStore((state) => [state.setContainers], shallow);
-
-    useEffect(() => {
-        console.log("DataPoller Start");
-        const interval = setInterval(() => {
-            getStatuses();
-        }, 1000);
-        return () => {
-            console.log("DataPoller End");
-            clearInterval(interval);
-        };
-    }, []);
-
-    function getStatuses() {
-        if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
-            KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
-                setContainers(statuses);
-            });
-        }
-    }
-
-    function getData() {
-        if (KaravanApi.isAuthorized || KaravanApi.authType === 'public') {
-            KaravanApi.getConfiguration((config: AppConfig) => {
-                setConfig(config);
-                InfrastructureAPI.infrastructure = config.infrastructure;
-            });
-            updateKamelets();
-            updateComponents();
-            // updateSupportedComponents(); // not implemented yet
-        }
-    }
-
-    async function updateKamelets(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getKamelets(yamls => {
-                const kamelets: string[] = [];
-                yamls.split("\n---\n").map(c => c.trim()).forEach(z => kamelets.push(z));
-                KameletApi.saveKamelets(kamelets, true);
-            })
-            KaravanApi.getCustomKameletNames(names => {
-                KameletApi.saveCustomKameletNames(names);
-            })
-        });
-    }
-
-    async function updateComponents(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getComponents(code => {
-                const components: [] = JSON.parse(code);
-                const jsons: string[] = [];
-                components.forEach(c => jsons.push(JSON.stringify(c)));
-                ComponentApi.saveComponents(jsons, true);
-            })
-        });
-    }
-
-    async function updateSupportedComponents(): Promise<void> {
-        await new Promise(resolve => {
-            KaravanApi.getSupportedComponents(jsons => {
-                ComponentApi.saveSupportedComponents(jsons);
-            })
-        });
-    }
-
-    return (
-        <React.Fragment></React.Fragment>
-    )
-}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
index 3cf72154..7a3fa986 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/Main.tsx
@@ -1,11 +1,9 @@
-import {Routes, Route, useNavigate, Navigate} from 'react-router-dom';
-import {useLocation} from 'react-router-dom';
-import React, {useEffect, useRef, useState} from "react";
+import {Routes, Route, Navigate} from 'react-router-dom';
+import React, {useEffect, useRef} from "react";
 import {KaravanApi} from "../api/KaravanApi";
 import {Bullseye, Flex, FlexItem, Page, Spinner} from "@patternfly/react-core";
 import Icon from "../Logo";
 import {MainLogin} from "./MainLogin";
-import {Notification} from "./Notification";
 import {DashboardPage} from "../dashboard/DashboardPage";
 import {ProjectsPage} from "../projects/ProjectsPage";
 import {ProjectPage} from "../project/ProjectPage";
@@ -13,12 +11,14 @@ import {ServicesPage} from "../services/ServicesPage";
 import {ContainersPage} from "../containers/ContainersPage";
 import {KnowledgebasePage} from "../knowledgebase/KnowledgebasePage";
 import {ProjectEventBus} from "../api/ProjectEventBus";
-import {Project, ToastMessage} from "../api/ProjectModels";
+import {ToastMessage} from "../api/ProjectModels";
 import {SsoApi} from "../api/SsoApi";
-import {useAppConfigStore, useStatusesStore} from "../api/ProjectStore";
+import {useAppConfigStore} from "../api/ProjectStore";
 import {shallow} from "zustand/shallow";
 import {PageNavigation} from "./PageNavigation";
+import {Notification} from "./Notification";
 import {useMainHook} from "./useMainHook";
+import {MainDataPoller} from "./MainDataPoller";
 
 export const Main = () => {
 
@@ -36,9 +36,6 @@ export const Main = () => {
 
     function effect() {
         console.log("Main Start");
-        const interval = setInterval(() => {
-            getStatuses();
-        }, 1000);
         KaravanApi.getAuthType((authType: string) => {
             console.log("authType", authType);
             if (authType === 'oidc') {
@@ -52,19 +49,9 @@ export const Main = () => {
         });
         return () => {
             console.log("Main End");
-            clearInterval(interval);
         };
     }
 
-    function onLogin(username: string, password: string) {
-        KaravanApi.auth(username, password, (res: any) => {
-            if (res?.status === 200) {
-                getData();
-            } else {
-                toast("Error", "Incorrect username and/or password!", "danger");
-            }
-        });
-    }
 
     function toast(title: string, text: string, variant: 'success' | 'danger' | 'warning' | 'info' | 'custom') {
         ProjectEventBus.sendAlert(new ToastMessage(title, text, variant))
@@ -97,8 +84,9 @@ export const Main = () => {
                 </Flex>
             }
             {!KaravanApi.isAuthorized && KaravanApi.authType === 'basic' &&
-                <MainLogin config={config} onLogin={onLogin}/>}
-            {/*<Notification/>*/}
+                <MainLogin/>}
+            <Notification/>
+            <MainDataPoller/>
         </Page>
     );
 };
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
new file mode 100644
index 00000000..02f9301c
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/src/main/MainDataPoller.tsx
@@ -0,0 +1,62 @@
+import React, {useEffect, useState} from 'react';
+
+import {KaravanApi} from "../api/KaravanApi";
+import '../designer/karavan.css';
+import {
+    AppConfig,
+    CamelStatus,
+    ContainerStatus,
+    DeploymentStatus,
+    PipelineStatus,
+    Project,
+    ServiceStatus
+} from "../api/ProjectModels";
+import {useAppConfigStore, useProjectsStore, useStatusesStore} from "../api/ProjectStore";
+import {shallow} from "zustand/shallow";
+
+export const MainDataPoller = () => {
+
+    const [config, setLoading] = useAppConfigStore((state) => [state.config, state.setLoading], shallow)
+    const [projects, setProjects] = useProjectsStore((state) => [state.projects, state.setProjects], shallow)
+    const [deployments, services, containers, camels, setDeployments, setServices, setContainers, setCamels, setPipelineStatuses]
+        = useStatusesStore((s) => [s.deployments, s.services, s.containers, s.camels,
+        s.setDeployments, s.setServices, s.setContainers, s.setCamels, s.setPipelineStatuses], shallow);
+
+    useEffect(() => {
+        console.log("MainDataPoller Start");
+        const interval = setInterval(() => {
+            getData();
+        }, 1300);
+        return () => {
+            console.log("MainDataPoller Stop");
+            clearInterval(interval);
+        };
+    }, []);
+
+    function getData() {
+        setLoading(true);
+        KaravanApi.getConfiguration((config: AppConfig) => {
+            KaravanApi.getProjects((projects: Project[]) => {
+                setProjects(projects);
+            });
+            KaravanApi.getAllDeploymentStatuses((statuses: DeploymentStatus[]) => {
+                setDeployments(statuses);
+            });
+            KaravanApi.getAllServiceStatuses((statuses: ServiceStatus[]) => {
+                setServices(statuses);
+            });
+            KaravanApi.getAllContainerStatuses((statuses: ContainerStatus[]) => {
+                setContainers(statuses);
+            });
+            KaravanApi.getAllCamelStatuses(config.environment, (statuses: CamelStatus[]) => {
+                setCamels(statuses);
+            });
+            KaravanApi.getPipelineStatuses(config.environment, (status: PipelineStatus[]) => {
+                setPipelineStatuses(status);
+            });
+            setLoading(false);
+        });
+    }
+
+    return (<></>)
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/MainLogin.tsx b/karavan-web/karavan-app/src/main/webui/src/main/MainLogin.tsx
index 40426253..a493a963 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/MainLogin.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/MainLogin.tsx
@@ -1,61 +1,63 @@
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Bullseye, Card, CardBody, CardTitle, LoginForm, Text
 } from '@patternfly/react-core';
+import {KaravanApi} from "../api/KaravanApi";
+import {useAppConfigStore} from "../api/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {ProjectEventBus} from "../api/ProjectEventBus";
+import {ToastMessage} from "../api/ProjectModels";
 
-interface Props {
-    config: any,
-    onLogin: (username: string, password: string) => void
-}
+export const MainLogin = () => {
 
-interface State {
-    username: string,
-    password: string,
-    isValidUsername: boolean,
-    isValidPassword: boolean,
-    isRememberMeChecked: boolean,
-}
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const [username, setUsername] = useState<string>();
+    const [password, setPassword] = useState<string>();
+    const [isValidUsername, setIsValidUsername] = useState<boolean>(true);
+    const [isValidPassword, setIsValidPassword] = useState<boolean>(true);
+    const [isRememberMeChecked, setIsRememberMeChecked] = useState<boolean>(false);
 
-export class MainLogin extends React.Component<Props, State> {
-    public state: State = {
-        username: "",
-        password: "",
-        isValidUsername: true,
-        isValidPassword: true,
-        isRememberMeChecked: false,
-    }
-
-    onLoginButtonClick = (event: any) => {
+    function onLoginButtonClick(event: any) {
         event.preventDefault();
-        this.props.onLogin?.call(this, this.state.username, this.state.password);
+        if (username && password) {
+            onLogin(username, password);
+        }
     }
 
-    render() {
-        return (
-            <Bullseye>
-                <Card isFlat isCompact>
-                    <CardTitle>
-                        <img alt="karavan-logo" src="karavan-logo-light.png" className="login-logo"/>
-                        <Text component="h3" style={{width:"fit-content", marginLeft:"auto"}}>{this.props.config.version}</Text>
-                    </CardTitle>
-                    <CardBody>
-                        <LoginForm
-                            showHelperText={true}
-                            usernameLabel="Username"
-                            usernameValue={this.state.username}
-                            onChangeUsername={(_event, value) => this.setState({username: value})}
-                            isValidUsername={this.state.isValidUsername}
-                            passwordLabel="Password"
-                            passwordValue={this.state.password}
-                            isShowPasswordEnabled
-                            onChangePassword={(_event, value) => this.setState({password: value})}
-                            isValidPassword={this.state.isValidPassword}
-                            onLoginButtonClick={this.onLoginButtonClick}
-                            loginButtonLabel="Log in"
-                        />
-                    </CardBody>
-                </Card>
-            </Bullseye>
-        );
+    function onLogin(username: string, password: string) {
+        KaravanApi.auth(username, password, (res: any) => {
+            if (res?.status === 200) {
+            } else {
+                ProjectEventBus.sendAlert(new ToastMessage("Error", "Incorrect username and/or password!", "danger"))
+            }
+        });
     }
+
+    return (
+        <Bullseye>
+            <Card isFlat isCompact>
+                <CardTitle>
+                    <img alt="karavan-logo" src="karavan-logo-light.png" className="login-logo"/>
+                    <Text component="h3"
+                          style={{width: "fit-content", marginLeft: "auto"}}>{config.version}</Text>
+                </CardTitle>
+                <CardBody>
+                    <LoginForm
+                        showHelperText={true}
+                        usernameLabel="Username"
+                        usernameValue={username}
+                        onChangeUsername={(_event, value) => setUsername(value)}
+                        isValidUsername={isValidUsername}
+                        passwordLabel="Password"
+                        passwordValue={password}
+                        isShowPasswordEnabled
+                        onChangePassword={(_event, value) => setPassword(value)}
+                        isValidPassword={isValidPassword}
+                        onLoginButtonClick={onLoginButtonClick}
+                        loginButtonLabel="Log in"
+                    />
+                </CardBody>
+            </Card>
+        </Bullseye>
+    );
 }
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
index 648add20..2c35c44b 100644
--- a/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/main/PageNavigation.tsx
@@ -4,7 +4,7 @@ import {
     Flex,
     FlexItem,
     Tooltip,
-    Divider, Popover, Badge
+    Divider, Popover, Badge, Spinner, Bullseye
 } from '@patternfly/react-core';
 import {KaravanApi} from "../api/KaravanApi";
 import '../designer/karavan.css';
@@ -33,7 +33,7 @@ class MenuItem {
 
 export const PageNavigation = () => {
 
-    const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const [config, loading] = useAppConfigStore((state) => [state.config, state.loading], shallow)
     const [setFile] = useFileStore((state) => [state.setFile], shallow)
     const [setStatus, setPodName] = useDevModeStore((state) => [state.setStatus, state.setPodName], shallow)
     const [showUser, setShowUser] = useState<boolean>(false);
@@ -58,10 +58,14 @@ export const PageNavigation = () => {
     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 " + config.version}
-                     position={"right"}>
-                {Icon()}
-            </Tooltip>
+            <Bullseye>
+                {loading && <Spinner style={{position: "absolute"}} diameter="40px" aria-label="Loading..."/>}
+                <Tooltip className="logo-tooltip" content={"Apache Camel Karavan " + config.version}
+                         position={"right"}>
+                    {Icon()}
+                </Tooltip>
+            </Bullseye>
+
         </FlexItem>
         {getMenu().map(page =>
             <FlexItem key={page.pageId} className={pageId === page.pageId ? "nav-button-selected" : ""}>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx
new file mode 100644
index 00000000..2b86d831
--- /dev/null
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectDataPoller.tsx
@@ -0,0 +1,61 @@
+import React, {useEffect} from 'react';
+
+import {KaravanApi} from "../api/KaravanApi";
+import '../designer/karavan.css';
+import {useAppConfigStore, useProjectStore} from "../api/ProjectStore";
+import {shallow} from "zustand/shallow";
+import {CamelStatus, DeploymentStatus, PipelineStatus} from "../api/ProjectModels";
+
+export const ProjectDataPoller = () => {
+
+    const [config] = useAppConfigStore((state) => [state.config], shallow)
+    const [project, setMemory, setJvm, setContext, refreshTrace, setTrace] = useProjectStore((s) =>
+        [s.project, s.setMemory, s.setJvm, s.setContext, s.refreshTrace, s.setTrace], shallow);
+
+    useEffect(() => {
+        console.log("ProjectDataPoller Start");
+        const interval = setInterval(() => {
+            onRefreshStatus();
+        }, 1000);
+        return () => {
+            console.log("ProjectDataPoller Stop");
+            clearInterval(interval)
+        };
+    }, [project, refreshTrace]);
+
+    function onRefreshStatus() {
+        const projectId = project.projectId;
+        KaravanApi.getDevModeStatus(projectId, "memory", res => {
+            if (res.status === 200) {
+                setMemory(JSON.parse(res.data.status));
+            } else {
+                setMemory({});
+            }
+        })
+        KaravanApi.getDevModeStatus(projectId, "jvm", res => {
+            if (res.status === 200) {
+                setJvm(JSON.parse(res.data.status));
+            } else {
+                setJvm({});
+            }
+        })
+        KaravanApi.getDevModeStatus(projectId, "context", res => {
+            if (res.status === 200) {
+                setContext(JSON.parse(res.data.status));
+            } else {
+                setContext({});
+            }
+        })
+        if (refreshTrace) {
+            KaravanApi.getDevModeStatus(projectId, "trace", res => {
+                if (res.status === 200) {
+                    setTrace(JSON.parse(res.data.status));
+                } else {
+                    setTrace({});
+                }
+            })
+        }
+    }
+
+    return (<></>)
+}
\ No newline at end of file
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
index cb6bb96a..a771570c 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/ProjectPage.tsx
@@ -14,6 +14,7 @@ import {FileEditor} from "./file/FileEditor";
 import {shallow} from "zustand/shallow";
 import {useParams} from "react-router-dom";
 import {KaravanApi} from "../api/KaravanApi";
+import {ProjectDataPoller} from "./ProjectDataPoller";
 
 export const ProjectPage = () => {
 
@@ -53,6 +54,7 @@ export const ProjectPage = () => {
             {showFilePanel && <FileEditor/>}
             {!showFilePanel && <ProjectPanel/>}
             <ProjectLogPanel/>
+            <ProjectDataPoller/>
         </PageSection>
     )
 }
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
index beceb5c8..4a21f9ad 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/dashboard/DashboardTab.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useEffect, useState} from 'react';
+import React from 'react';
 import {
     Card,
     CardBody, Flex, FlexItem, Divider, PageSection
@@ -23,55 +23,19 @@ import '../../designer/karavan.css';
 import {InfoContainer} from "./InfoContainer";
 import {InfoContext} from "./InfoContext";
 import {InfoMemory} from "./InfoMemory";
-import {KaravanApi} from "../../api/KaravanApi";
 import {useProjectStore, useStatusesStore} from "../../api/ProjectStore";
 import {shallow} from "zustand/shallow";
 import {ContainerStatus} from "../../api/ProjectModels";
 
 export const DashboardTab = () => {
 
-    const [project] = useProjectStore((state) => [state.project], shallow);
+    const [project, memory, jvm, context] = useProjectStore((state) =>
+        [state.project, state.memory, state.jvm, state.context], shallow);
     const [containers] = useStatusesStore((state) => [state.containers], shallow);
-    const [memory, setMemory] = useState({});
-    const [jvm, setJvm] = useState({});
-    const [context, setContext] = useState({});
-
-    useEffect(() => {
-        const interval = setInterval(() => {
-            onRefreshStatus();
-        }, 1000);
-        return () => {
-            clearInterval(interval)
-        };
-    }, []);
-
-    function onRefreshStatus() {
-        const projectId = project.projectId;
-        KaravanApi.getDevModeStatus(projectId, "memory", res => {
-            if (res.status === 200) {
-                setMemory(JSON.parse(res.data.status));
-            } else {
-                setMemory({});
-            }
-        })
-        KaravanApi.getDevModeStatus(projectId, "jvm", res => {
-            if (res.status === 200) {
-                setJvm(JSON.parse(res.data.status));
-            } else {
-                setJvm({});
-            }
-        })
-        KaravanApi.getDevModeStatus(projectId, "context", res => {
-            if (res.status === 200) {
-                setContext(JSON.parse(res.data.status));
-            } else {
-                setContext({});
-            }
-        })
-    }
 
     const containerStatus = containers.filter(c => c.containerName === project.projectId).at(0);
     const showConsole = containerStatus?.state === 'running'
+
     return (
         <PageSection className="project-tab-panel" padding={{default: "padding"}}>
             <Card className="project-development">
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
index da56443a..a5ee8418 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/files/FilesToolbar.tsx
@@ -39,7 +39,6 @@ export const FileToolbar = () => {
 
 
     useEffect(() => {
-        console.log("ProjectToolbar useEffect", isPushing, project.lastCommitTimestamp);
     }, [project, file]);
 
     function push () {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
index ba5e4d7e..c7eec061 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/log/ProjectLogPanel.tsx
@@ -25,8 +25,6 @@ export const ProjectLogPanel = () => {
     const [currentPodName, setCurrentPodName] = useState<string | undefined>(undefined);
 
     useEffect(() => {
-        const containerStatus = containers.filter(c => c.containerName === podName).at(0);
-        console.log("ProjectLogPanel", showLog, type, podName, containerStatus);
         const controller = new AbortController();
         if (showLog && type !== 'none' && podName !== undefined) {
             const f = KaravanApi.fetchData(type, podName, controller).then(value => {
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
index e2209f89..83b8b990 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectPipelineTab.tsx
@@ -14,8 +14,8 @@ export const ProjectPipelineTab = () => {
         <PageSection className="project-tab-panel" padding={{default: "padding"}}>
             <div className="project-operations">
                 {/*{["dev", "test", "prod"].map(env =>*/}
-                {["dev"].map(env =>
-                    <ProjectStatus key={env} project={project} config={config} env={env}/>
+                {config.environments.map(env =>
+                    <ProjectStatus env={env}/>
                 )}
             </div>
         </PageSection>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
index ae022589..698621b8 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/pipeline/ProjectStatus.tsx
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Button,
     DescriptionList,
@@ -14,116 +14,76 @@ import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
 import DownIcon from "@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
 import ClockIcon from "@patternfly/react-icons/dist/esm/icons/clock-icon";
 import DeleteIcon from "@patternfly/react-icons/dist/esm/icons/times-circle-icon";
-import {CamelStatus, DeploymentStatus, PipelineStatus, ContainerStatus, Project} from "../../api/ProjectModels";
-import {useLogStore} from "../../api/ProjectStore";
+import {CamelStatus, DeploymentStatus, ContainerStatus} from "../../api/ProjectModels";
+import {useLogStore, useProjectStore, useStatusesStore} from "../../api/ProjectStore";
+import {shallow} from "zustand/shallow";
 
 interface Props {
-    project: Project,
-    config: any,
     env: string,
 }
 
-interface State {
-    pipelineStatus?: PipelineStatus,
-    deploymentStatus?: DeploymentStatus,
-    podStatuses: ContainerStatus[],
-    camelStatus?: CamelStatus,
-    isPushing: boolean,
-    isBuilding: boolean,
-    isRolling: boolean,
-    showDeleteConfirmation: boolean,
-    deleteEntity?: 'pod' | 'deployment' | 'pipelinerun',
-    deleteEntityName?: string,
-    deleteEntityEnv?: string,
-}
-
-export class ProjectStatus extends React.Component<Props, State> {
-
-    public state: State = {
-        podStatuses: [],
-        isPushing: false,
-        isBuilding: false,
-        isRolling: false,
-        showDeleteConfirmation: false,
-    };
-    interval: any;
-
-    componentDidMount() {
-        this.interval = setInterval(() => this.onRefreshStatus(), 700);
-    }
-
-    componentWillUnmount() {
-        clearInterval(this.interval);
-    }
+export const ProjectStatus = (props: Props) => {
 
-    onRefreshStatus = () => {
-        const projectId = this.props.project.projectId;
-        const env = this.props.env;
-        if (this.props.project) {
-            KaravanApi.getProjectPipelineStatus(projectId, env, (status?: PipelineStatus) => {
-                this.setState({pipelineStatus: status});
-            });
-            KaravanApi.getProjectDeploymentStatus(projectId, env, (status?: DeploymentStatus) => {
-                this.setState({deploymentStatus: status});
-            });
-            KaravanApi.getProjectPodStatuses(projectId, env, (statuses: ContainerStatus[]) => {
-                this.setState({podStatuses: statuses});
-            });
-            KaravanApi.getProjectCamelStatus(projectId, env, (status: CamelStatus) => {
-                this.setState({camelStatus: status});
-            });
-        }
-    }
+    const [project] = useProjectStore((s) => [s.project], shallow);
+    const [containers, deployments, camels, pipelineStatuses] =
+        useStatusesStore((s) => [s.containers, s.deployments, s.camels, s.pipelineStatuses], shallow);
+    const [isPushing, setIsPushing] = useState<boolean>(false);
+    const [isBuilding, setIsBuilding] = useState<boolean>(false);
+    const [isRolling, setIsRolling] = useState<boolean>(false);
+    const [showDeleteConfirmation, setShowDeleteConfirmation] = useState<boolean>(false);
+    const [deleteEntityType, setDeleteEntityType] = useState<'pod' | 'deployment' | 'pipelinerun'>('pod');
+    const [deleteEntityName, setDeleteEntityName] = useState<string>();
+    const [deleteEntityEnv, setDeleteEntityEnv] = useState<string>();
 
-    deleteEntity = (type: 'pod' | 'deployment' | 'pipelinerun', name: string, environment: string) => {
+    function deleteEntity (type: 'pod' | 'deployment' | 'pipelinerun', name: string, environment: string)  {
         switch (type) {
             case "deployment":
                 KaravanApi.deleteDeployment(environment, name, (res: any) => {
                     // if (Array.isArray(res) && Array.from(res).length > 0)
-                    // this.onRefresh();
+                    // onRefresh();
                 });
                 break;
             case "pod":
                 KaravanApi.deleteContainer(environment, 'project', name, (res: any) => {
                     // if (Array.isArray(res) && Array.from(res).length > 0)
-                    // this.onRefresh();
+                    // onRefresh();
                 });
                 break;
             case "pipelinerun":
                 KaravanApi.stopPipelineRun(environment, name, (res: any) => {
                     // if (Array.isArray(res) && Array.from(res).length > 0)
-                    // this.onRefresh();
+                    // onRefresh();
                 });
                 break;
         }
     }
 
-    build = () => {
-        this.setState({isBuilding: true});
-        KaravanApi.pipelineRun(this.props.project, this.props.env, res => {
+    function build () {
+        setIsBuilding(true);
+        KaravanApi.pipelineRun(project, env, res => {
             if (res.status === 200 || res.status === 201) {
-                this.setState({isBuilding: false});
+                setIsBuilding(false);
             } else {
                 // Todo notification
             }
         });
     }
 
-    rollout = () => {
-        this.setState({isRolling: true});
-        KaravanApi.rolloutDeployment(this.props.project.projectId, this.props.env, res => {
+    function rollout () {
+        setIsRolling(true);
+        KaravanApi.rolloutDeployment(project.projectId, env, res => {
             console.log(res)
             if (res.status === 200 || res.status === 201) {
-                this.setState({isRolling: false});
+                setIsRolling(false);
             } else {
                 // Todo notification
             }
         });
     }
 
-    buildButton = (env: string) => {
-        const {isBuilding, isPushing, pipelineStatus} = this.state;
-        const isRunning = pipelineStatus?.result === 'Running';
+    function buildButton (env: string) {
+        const status = pipelineStatuses.filter(p => p.projectId === project.projectId).at(0);
+        const isRunning = status?.result === 'Running';
         return (<Tooltip content="Start build pipeline" position={"left"}>
             <Button isLoading={isBuilding ? true : undefined}
                     isDisabled={isBuilding || isRunning || isPushing}
@@ -131,41 +91,41 @@ export class ProjectStatus extends React.Component<Props, State> {
                     variant="secondary"
                     className="project-button"
                     icon={!isBuilding ? <BuildIcon/> : <div></div>}
-                    onClick={e => this.build()}>
+                    onClick={e => build()}>
                 {isBuilding ? "..." : "Build"}
             </Button>
         </Tooltip>)
     }
 
-    rolloutButton = () => {
-        const isRolling = this.state.isRolling;
+    function rolloutButton () {
         return (<Tooltip content="Rollout deployment" position={"left"}>
             <Button isLoading={isRolling ? true : undefined} size="sm" variant="secondary"
                     className="project-button"
                     icon={!isRolling ? <RolloutIcon/> : <div></div>}
-                    onClick={e => this.rollout()}>
+                    onClick={e => rollout()}>
                 {isRolling ? "..." : "Rollout"}
             </Button>
         </Tooltip>)
     }
 
-    deleteDeploymentButton = (env: string) => {
+    function deleteDeploymentButton (env: string) {
         return (<Tooltip content="Delete deployment" position={"left"}>
             <Button size="sm" variant="secondary"
                     className="project-button"
                     icon={<DeleteIcon/>}
-                    onClick={e => this.setState({
-                        showDeleteConfirmation: true,
-                        deleteEntity: "deployment",
-                        deleteEntityEnv: env,
-                        deleteEntityName: this.props.project?.projectId
-                    })}>
+                    onClick={e => {
+                        setShowDeleteConfirmation(true);
+                        setDeleteEntityType("deployment");
+                        setDeleteEntityEnv(env);
+                        setDeleteEntityName(project?.projectId);
+                    }}>
                 {"Delete"}
             </Button>
         </Tooltip>)
     }
 
-    getReplicasPanel(env: string, deploymentStatus?: DeploymentStatus) {
+    function getReplicasPanel(env: string) {
+        const deploymentStatus = deployments.find(d => d.name === project?.projectId);
         const ok = (deploymentStatus && deploymentStatus?.readyReplicas > 0
             && (deploymentStatus.unavailableReplicas === 0 || deploymentStatus.unavailableReplicas === undefined || deploymentStatus.unavailableReplicas === null)
             && deploymentStatus?.replicas === deploymentStatus?.readyReplicas)
@@ -185,19 +145,20 @@ export class ProjectStatus extends React.Component<Props, State> {
                     </LabelGroup>}
                     {deploymentStatus === undefined && <Label icon={<DownIcon/>} color={"grey"}>No deployments</Label>}
                 </FlexItem>
-                <FlexItem>{env === "dev" && this.deleteDeploymentButton(env)}</FlexItem>
+                <FlexItem>{env === "dev" && deleteDeploymentButton(env)}</FlexItem>
             </Flex>
         )
     }
 
-    getPodsPanel(env: string, podStatuses: ContainerStatus[]) {
+    function getPodsPanel(env: string) {
+        const podStatuses = containers.filter(d => d.projectId === project?.projectId);
         return (
             <Flex justifyContent={{default: "justifyContentSpaceBetween"}}
                   alignItems={{default: "alignItemsFlexStart"}}>
                 <FlexItem>
                     {podStatuses.length === 0 && <Label icon={<DownIcon/>} color={"grey"}>No pods</Label>}
                     <LabelGroup numLabels={2} isVertical>
-                        {podStatuses.map(pod => {
+                        {podStatuses.map((pod: ContainerStatus) => {
                                 const ready = pod.state === 'running';
                                 return (
                                     <Tooltip key={pod.containerName} content={pod.state}>
@@ -213,12 +174,12 @@ export class ProjectStatus extends React.Component<Props, State> {
                                                 {pod.containerName}
                                             </Button>
                                             <Tooltip content={"Delete Pod"}>
-                                                <Button icon={<DeleteIcon/>} variant="link" onClick={e => this.setState({
-                                                    showDeleteConfirmation: true,
-                                                    deleteEntity: "pod",
-                                                    deleteEntityEnv: env,
-                                                    deleteEntityName: pod.containerName
-                                                })}></Button>
+                                                <Button icon={<DeleteIcon/>} variant="link" onClick={e => {
+                                                    setShowDeleteConfirmation(true);
+                                                    setDeleteEntityType("pod");
+                                                    setDeleteEntityEnv(env);
+                                                    setDeleteEntityName(pod.containerName);
+                                                }}></Button>
                                             </Tooltip>
                                         </Label>
                                     </Tooltip>
@@ -227,23 +188,23 @@ export class ProjectStatus extends React.Component<Props, State> {
                         )}
                     </LabelGroup>
                 </FlexItem>
-                <FlexItem>{env === "dev" && this.rolloutButton()}</FlexItem>
+                <FlexItem>{env === "dev" && rolloutButton()}</FlexItem>
             </Flex>
         )
     }
 
-    getStatusColor(status?: string) {
+    function getStatusColor(status?: string) {
         if (status === 'UP') return 'green';
         if (status === 'DOWN') return 'red';
         if (status === 'UNDEFINED') return 'grey';
     }
 
-    getStatusIcon(status?: string) {
+    function getStatusIcon(status?: string) {
         return (status === 'UP' ? <UpIcon/> : <DownIcon/>)
     }
 
-    getHealthPanel(env: string) {
-        const status = this.state.camelStatus;
+    function getHealthPanel(env: string) {
+        const status = camels;
         // const routesStatus = status?.routesStatus;
         // const consumersStatus = status?.consumerStatus;
         // const contextStatus = status?.contextStatus;
@@ -251,19 +212,19 @@ export class ProjectStatus extends React.Component<Props, State> {
         return (
             <LabelGroup numLabels={4}>
                 {/*{contextVersion &&*/}
-                {/*    <Label icon={this.getStatusIcon(contextStatus)}*/}
-                {/*           color={this.getStatusColor(contextStatus)}>{contextVersion}</Label>}*/}
-                {/*<Label icon={this.getStatusIcon(contextStatus)}*/}
-                {/*       color={this.getStatusColor(contextStatus)}>Context</Label>*/}
-                {/*<Label icon={this.getStatusIcon(consumersStatus)}*/}
-                {/*       color={this.getStatusColor(consumersStatus)}>Consumers</Label>*/}
-                {/*<Label icon={this.getStatusIcon(routesStatus)} color={this.getStatusColor(routesStatus)}>Routes</Label>*/}
+                {/*    <Label icon={getStatusIcon(contextStatus)}*/}
+                {/*           color={getStatusColor(contextStatus)}>{contextVersion}</Label>}*/}
+                {/*<Label icon={getStatusIcon(contextStatus)}*/}
+                {/*       color={getStatusColor(contextStatus)}>Context</Label>*/}
+                {/*<Label icon={getStatusIcon(consumersStatus)}*/}
+                {/*       color={getStatusColor(consumersStatus)}>Consumers</Label>*/}
+                {/*<Label icon={getStatusIcon(routesStatus)} color={getStatusColor(routesStatus)}>Routes</Label>*/}
             </LabelGroup>
         )
     }
 
-    getPipelineState(env: string) {
-        const status = this.state.pipelineStatus;
+    function getPipelineState(env: string) {
+        const status = pipelineStatuses.filter(p => p.projectId === project.projectId).at(0);
         const pipeline = status?.pipelineName;
         const pipelineResult = status?.result;
         let lastPipelineRunTime = 0;
@@ -292,14 +253,12 @@ export class ProjectStatus extends React.Component<Props, State> {
                                     </Button>
                                     : "No pipeline"}
                                 {isRunning && <Tooltip content={"Stop PipelineRun"}>
-                                    <Button icon={<DeleteIcon/>} variant="link" onClick={e =>
-                                        this.setState({
-                                            showDeleteConfirmation: true,
-                                            deleteEntity: "pipelinerun",
-                                            deleteEntityEnv: env,
-                                            deleteEntityName: pipeline
-                                        })
-                                    }></Button>
+                                    <Button icon={<DeleteIcon/>} variant="link" onClick={e => {
+                                        setShowDeleteConfirmation(true);
+                                        setDeleteEntityType("pipelinerun");
+                                        setDeleteEntityEnv(env);
+                                        setDeleteEntityName(pipeline);
+                                        }}></Button>
                                 </Tooltip>}
                             </Label>
                             {pipeline !== undefined && showTime === true && lastPipelineRunTime !== undefined &&
@@ -307,75 +266,71 @@ export class ProjectStatus extends React.Component<Props, State> {
                         </LabelGroup>
                     </Tooltip>
                 </FlexItem>
-                <FlexItem>{env === "dev" && this.buildButton(env)}</FlexItem>
+                <FlexItem>{env === "dev" && buildButton(env)}</FlexItem>
             </Flex>
         )
     }
 
-    getDeleteConfirmation() {
-        const {deleteEntity, deleteEntityEnv, deleteEntityName} = this.state;
+    function getDeleteConfirmation() {
         return (<Modal
             className="modal-delete"
             title="Confirmation"
-            isOpen={this.state.showDeleteConfirmation}
-            onClose={() => this.setState({showDeleteConfirmation: false})}
+            isOpen={showDeleteConfirmation}
+            onClose={() => setShowDeleteConfirmation(false)}
             actions={[
                 <Button key="confirm" variant="primary" onClick={e => {
                     if (deleteEntityEnv && deleteEntityName && deleteEntity) {
-                        this.deleteEntity(deleteEntity, deleteEntityName, deleteEntityEnv);
-                        this.setState({showDeleteConfirmation: false});
+                        deleteEntity(deleteEntityType, deleteEntityName, deleteEntityEnv);
+                        setShowDeleteConfirmation(false);
                     }
                 }}>Delete
                 </Button>,
                 <Button key="cancel" variant="link"
-                        onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
+                        onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
             ]}
-            onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
+            onEscapePress={e => setShowDeleteConfirmation(false)}>
             <div>{"Delete " + deleteEntity + " " + deleteEntityName + "?"}</div>
         </Modal>)
     }
 
-    render() {
-        const {deploymentStatus, podStatuses} = this.state;
-        const {env} = this.props;
-        return (
-            <Card className="project-status">
-                <CardBody>
-                    <DescriptionList isHorizontal>
-                        <DescriptionListGroup>
-                            <DescriptionListTerm>Environment</DescriptionListTerm>
-                            <DescriptionListDescription>
-                                <Badge className="badge">{env}</Badge>
-                            </DescriptionListDescription>
-                        </DescriptionListGroup>
-                        <DescriptionListGroup>
-                            <DescriptionListTerm>Pipeline</DescriptionListTerm>
-                            <DescriptionListDescription>
-                                {this.getPipelineState(env)}
-                            </DescriptionListDescription>
-                        </DescriptionListGroup>
-                        <DescriptionListGroup>
-                            <DescriptionListTerm>Deployment</DescriptionListTerm>
-                            <DescriptionListDescription>
-                                {this.getReplicasPanel(env, deploymentStatus)}
-                            </DescriptionListDescription>
-                        </DescriptionListGroup>
-                        <DescriptionListGroup>
-                            <DescriptionListTerm>Pods</DescriptionListTerm>
-                            <DescriptionListDescription>
-                                {this.getPodsPanel(env, podStatuses)}
-                            </DescriptionListDescription>
-                        </DescriptionListGroup>
-                        <DescriptionListGroup>
-                            <DescriptionListTerm>Camel health</DescriptionListTerm>
-                            <DescriptionListDescription>
-                                {this.getHealthPanel(env)}
-                            </DescriptionListDescription>
-                        </DescriptionListGroup>
-                    </DescriptionList>
-                </CardBody>
-                {this.state.showDeleteConfirmation && this.getDeleteConfirmation()}
-            </Card>
-        )
-    }
+    const env = props.env;
+    return (
+        <Card className="project-status">
+            <CardBody>
+                <DescriptionList isHorizontal>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Environment</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            <Badge className="badge">{env}</Badge>
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Pipeline</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {getPipelineState(env)}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Deployment</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {getReplicasPanel(env)}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Pods</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {getPodsPanel(env)}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                    <DescriptionListGroup>
+                        <DescriptionListTerm>Camel health</DescriptionListTerm>
+                        <DescriptionListDescription>
+                            {getHealthPanel(env)}
+                        </DescriptionListDescription>
+                    </DescriptionListGroup>
+                </DescriptionList>
+            </CardBody>
+            {showDeleteConfirmation && getDeleteConfirmation()}
+        </Card>
+    )
 }
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
index 6940f8a8..d734018d 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx
@@ -58,8 +58,8 @@ export const RunnerInfoTraceModal = (props: Props) => {
                             <DescriptionListTerm>Nodes</DescriptionListTerm>
                         </DescriptionListGroup>
                     </DescriptionList>
-                    {props.nodes.map((node: any) => (
-                        <FlexItem>
+                    {props.nodes.map((node: any, index: number) => (
+                        <FlexItem key={node.uid + "-" + index}>
                             <Button variant={node.uid === activeNode.uid ? "secondary" : "link"}
                                     icon={node.nodeId === undefined ? <ArrowRightIcon/> : undefined}
                                     onClick={event => {setActiveNode(node)}}>
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx
index 90d71de6..5a470290 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx
@@ -42,8 +42,8 @@ export const RunnerInfoTraceNode = (props: Props) => {
                                 <DescriptionListTerm>Headers</DescriptionListTerm>
                             </DescriptionListGroup>
                             <DataList aria-label="Compact data list example" isCompact>
-                                {headers.map((header: any) => (
-                                    <DataListItem key={header[0]} aria-labelledby="compact-item1">
+                                {headers.map((header: any, index: number) => (
+                                    <DataListItem key={header[0] + "-" + index} aria-labelledby="compact-item1">
                                         <DataListItemRow>
                                             <DataListItemCells
                                                 dataListCells={[
diff --git a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
index c62aa090..d4420f2f 100644
--- a/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/project/trace/TraceTab.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {useEffect, useState} from 'react';
+import React, {useState} from 'react';
 import {
     Bullseye,
     Button,
@@ -39,40 +39,16 @@ import {
 	Table
 } from '@patternfly/react-table/deprecated';
 import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
-import {KaravanApi} from "../../api/KaravanApi";
 import {useProjectStore} from "../../api/ProjectStore";
+import {shallow} from "zustand/shallow";
 
 
 export const TraceTab = () => {
 
-    const {project} = useProjectStore();
-    const [trace, setTrace] = useState<any>({});
+    const [refreshTrace, setRefreshTrace, trace] = useProjectStore((state) =>
+        [state.refreshTrace, state.setRefreshTrace, state.trace], shallow);
     const [nodes, setNodes] = useState([{}]);
-    const [isOpen, setIsOpen] = useState(false);
-    const [refreshTrace, setRefreshTrace] = useState(false);
-
-    useEffect(() => {
-        const interval = setInterval(() => {
-            onRefreshStatus();
-        }, 1000);
-        return () => {
-            clearInterval(interval)
-        };
-    }, [refreshTrace]);
-
-
-    function onRefreshStatus() {
-        const projectId = project.projectId;
-        if (refreshTrace) {
-            KaravanApi.getDevModeStatus(projectId, "trace", res => {
-                if (res.status === 200) {
-                    setTrace(JSON.parse(res.data.status));
-                } else {
-                    setTrace({});
-                }
-            })
-        }
-    }
+    const [isOpen, setIsOpen] = useState<boolean>(false);
 
     function closeModal() {
         setIsOpen(false);
@@ -134,7 +110,7 @@ export const TraceTab = () => {
                             <Td>
                                 <Button style={{padding: '0'}} variant={"link"}
                                         onClick={e => {
-                                            setTrace(trace);
+                                            // setTrace(trace);
                                             setNodes(getNodes(exchangeId));
                                             setIsOpen(true);
                                         }}>
diff --git a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
index 64c5fd40..ef49c8aa 100644
--- a/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/projects/ProjectsPage.tsx
@@ -49,36 +49,10 @@ export const ProjectsPage = () => {
     const [projects] = useProjectsStore((state) => [state.projects], shallow)
     const [operation] = useProjectStore((state) => [state.operation], shallow)
     const [filter, setFilter] = useState<string>('');
-    const [loading, setLoading] = useState<boolean>(false);
-
-    useEffect(() => {
-        const interval = setInterval(() => {
-            if (projects.length === 0) setLoading(true);
-            if (!["create", "delete", "select", "copy"].includes(operation)) {
-                refresh();
-            }
-        }, 1300);
-        return () => {
-            clearInterval(interval)
-        };
-    }, [operation]);
-
-    function refresh() {
-        ProjectService.refreshProjects();
-        ProjectService.refreshAllDeploymentStatuses();
-        ProjectService.refreshAllContainerStatuses();
-        setLoading(false);
-    }
 
     function getTools() {
         return <Toolbar id="toolbar-group-types">
             <ToolbarContent>
-                <ToolbarItem>
-                    <Button variant="link" icon={<RefreshIcon/>} onClick={e => {
-                        setLoading(true);
-                        refresh();
-                    }}/>
-                </ToolbarItem>
                 <ToolbarItem>
                     <TextInput className="text-field" type="search" id="search" name="search"
                                autoComplete="off" placeholder="Search by name"
@@ -106,14 +80,10 @@ export const ProjectsPage = () => {
             <Tr>
                 <Td colSpan={8}>
                     <Bullseye>
-                        {loading &&
-                            <Spinner className="progress-stepper" diameter="80px" aria-label="Loading..."/>}
-                        {!loading &&
-                            <EmptyState variant={EmptyStateVariant.sm}>
-                                <EmptyStateHeader titleText="No results found"
-                                                  icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2"/>
-                            </EmptyState>
-                        }
+                        <EmptyState variant={EmptyStateVariant.sm}>
+                            <EmptyStateHeader titleText="No results found"
+                                              icon={<EmptyStateIcon icon={SearchIcon}/>} headingLevel="h2"/>
+                        </EmptyState>
                     </Bullseye>
                 </Td>
             </Tr>
diff --git a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
index 934f3042..e03e9c12 100644
--- a/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
+++ b/karavan-web/karavan-infinispan/src/main/java/org/apache/camel/karavan/infinispan/InfinispanService.java
@@ -210,6 +210,13 @@ public class InfinispanService {
         return pipelineStatuses.get(GroupedKey.create(projectId, environment, projectId));
     }
 
+    public List<PipelineStatus> getPipelineStatuses(String environment) {
+        QueryFactory queryFactory = Search.getQueryFactory((RemoteCache<?, ?>) pipelineStatuses);
+        return queryFactory.<PipelineStatus>create("FROM karavan.PipelineStatus WHERE env = :env")
+                .setParameter("env", environment)
+                .execute().list();
+    }
+
     public void savePipelineStatus(PipelineStatus status) {
         pipelineStatuses.put(GroupedKey.create(status.getProjectId(), status.getEnv(), status.getProjectId()), status);
     }