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


The following commit(s) were added to refs/heads/main by this push:
     new e5b51352 Dev console JVM and Camel Contex  #757
e5b51352 is described below

commit e5b513524d362947df2351164b56ba2db2492226
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Fri May 12 12:54:25 2023 -0400

    Dev console JVM and Camel Contex  #757
---
 .../apache/camel/karavan/api/RunnerResource.java   |  37 ++--
 .../camel/karavan/handler/PodEventHandler.java     |   9 +-
 .../apache/camel/karavan/model/RunnerStatus.java   |  14 ++
 .../camel/karavan/service/InfinispanService.java   |  27 ++-
 .../camel/karavan/service/KubernetesService.java   |  17 +-
 ...RunnerStatusService.java => RunnerService.java} |  63 ++++++-
 karavan-app/src/main/webui/src/api/KaravanApi.tsx  |  11 +-
 .../main/webui/src/projects/ProjectDevelopment.tsx |   8 +-
 .../main/webui/src/projects/RunnerInfoContext.tsx  | 192 +++++++++++++++++++++
 .../main/webui/src/projects/RunnerInfoMemory.tsx   | 183 ++++++++++++++++++++
 10 files changed, 517 insertions(+), 44 deletions(-)

diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/api/RunnerResource.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/api/RunnerResource.java
index 6aaeda5d..f07df5e2 100644
--- a/karavan-app/src/main/java/org/apache/camel/karavan/api/RunnerResource.java
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/api/RunnerResource.java
@@ -17,22 +17,27 @@
 package org.apache.camel.karavan.api;
 
 import io.vertx.core.json.JsonObject;
-import org.apache.camel.karavan.model.CamelStatus;
 import org.apache.camel.karavan.model.PodStatus;
 import org.apache.camel.karavan.model.Project;
+import org.apache.camel.karavan.model.RunnerStatus;
 import org.apache.camel.karavan.service.InfinispanService;
 import org.apache.camel.karavan.service.KubernetesService;
-import org.apache.camel.karavan.service.StatusService;
+import org.apache.camel.karavan.service.RunnerService;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 
 import javax.inject.Inject;
-import javax.ws.rs.*;
+import javax.ws.rs.Consumes;
+import javax.ws.rs.DELETE;
+import javax.ws.rs.GET;
+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.Map;
 import java.util.Optional;
 
-import static org.apache.camel.karavan.service.KubernetesService.RUNNER_SUFFIX;
+import static org.apache.camel.karavan.service.RunnerService.RUNNER_SUFFIX;
 
 @Path("/api/runner")
 public class RunnerResource {
@@ -40,6 +45,9 @@ public class RunnerResource {
     @ConfigProperty(name = "karavan.environment")
     String environment;
 
+    @Inject
+    RunnerService runnerServices;
+
     @Inject
     KubernetesService kubernetesService;
 
@@ -50,22 +58,29 @@ public class RunnerResource {
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     public String runProject(Project project) {
+        String runnerName = project.getProjectId() + "-" + RUNNER_SUFFIX;
+        String status = infinispanService.getRunnerStatus(runnerName, 
RunnerStatus.NAME.context);
+        if (status != null) {
+            JsonObject js = new JsonObject(status);
+            System.out.println(status);
+        }
         Project p = infinispanService.getProject(project.getProjectId());
-        return kubernetesService.tryCreateRunner(p);
+        return kubernetesService.tryCreateRunner(p, runnerName);
     }
 
     @DELETE
     @Produces(MediaType.APPLICATION_JSON)
     @Consumes(MediaType.APPLICATION_JSON)
     @Path("/{name}")
-    public Response deletePod(@PathParam("name") String name) throws Exception 
{
+    public Response deletePod(@PathParam("name") String name) {
         kubernetesService.deleteRunner(name);
+        infinispanService.deleteRunnerStatuses(name);
         return Response.accepted().build();
     }
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/status/{projectId}/{name}")
+    @Path("/pod/{projectId}/{name}")
     public Response getPodStatus(@PathParam("projectId") String projectId, 
@PathParam("name") String name) {
         Optional<PodStatus> ps =  infinispanService.getPodStatuses(projectId, 
environment).stream()
                 .filter(podStatus -> podStatus.getName().equals(name))
@@ -79,10 +94,10 @@ public class RunnerResource {
 
     @GET
     @Produces(MediaType.APPLICATION_JSON)
-    @Path("/{projectId}")
-    public Response getCamelStatusByProjectAndEnv(@PathParam("projectId") 
String projectId) {
+    @Path("/console/{statusName}/{projectId}")
+    public Response getCamelStatusByProjectAndEnv(@PathParam("projectId") 
String projectId, @PathParam("statusName") String statusName) {
         String name = projectId + "-" + RUNNER_SUFFIX;
-        String status = infinispanService.geRunnerStatus(name);
+        String status = infinispanService.getRunnerStatus(name, 
RunnerStatus.NAME.valueOf(statusName));
         if (status != null) {
             return Response.ok(status).build();
         } else {
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/handler/PodEventHandler.java
 
b/karavan-app/src/main/java/org/apache/camel/karavan/handler/PodEventHandler.java
index a6ffb0e0..508c753d 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/handler/PodEventHandler.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/handler/PodEventHandler.java
@@ -1,15 +1,16 @@
 package org.apache.camel.karavan.handler;
 
-import io.fabric8.kubernetes.api.model.*;
+import io.fabric8.kubernetes.api.model.ContainerBuilder;
+import io.fabric8.kubernetes.api.model.Pod;
+import io.fabric8.kubernetes.api.model.Quantity;
+import io.fabric8.kubernetes.api.model.ResourceRequirements;
 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;
-
-import static org.apache.camel.karavan.service.KubernetesService.RUNNER_SUFFIX;
+import static org.apache.camel.karavan.service.RunnerService.RUNNER_SUFFIX;
 import static 
org.apache.camel.karavan.service.ServiceUtil.DEFAULT_CONTAINER_RESOURCES;
 
 public class PodEventHandler implements ResourceEventHandler<Pod> {
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/model/RunnerStatus.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/model/RunnerStatus.java
new file mode 100644
index 00000000..de474bd9
--- /dev/null
+++ b/karavan-app/src/main/java/org/apache/camel/karavan/model/RunnerStatus.java
@@ -0,0 +1,14 @@
+package org.apache.camel.karavan.model;
+
+public class RunnerStatus {
+
+    public enum NAME {
+        context,
+        inflight,
+        memory,
+        properties,
+        route,
+        trace,
+        jvm
+    }
+}
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 48eb0a1f..b1fffc1f 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.RunnerStatus;
 import org.apache.camel.karavan.model.ServiceStatus;
 import org.eclipse.microprofile.health.HealthCheck;
 import org.eclipse.microprofile.health.HealthCheckResponse;
@@ -48,6 +49,7 @@ import javax.enterprise.inject.Default;
 import javax.inject.Inject;
 import java.time.Instant;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -71,7 +73,7 @@ public class InfinispanService implements HealthCheck  {
     private BasicCache<GroupedKey, ServiceStatus> serviceStatuses;
     private BasicCache<String, Environment> environments;
     private BasicCache<String, String> commits;
-    private BasicCache<String, String> runnerStatuses;
+    private BasicCache<GroupedKey, String> runnerStatuses;
     private final AtomicBoolean ready = new AtomicBoolean(false);
 
     @Inject
@@ -91,7 +93,7 @@ public class InfinispanService implements HealthCheck  {
         if (cacheManager == null) {
             LOGGER.info("InfinispanService is starting in local mode");
             GlobalConfigurationBuilder global = 
GlobalConfigurationBuilder.defaultClusteredBuilder();
-            
global.globalState().enable().persistentLocation("/deployments/karavan-data");
+            global.globalState().enable().persistentLocation("karavan-data");
             DefaultCacheManager cacheManager = new 
DefaultCacheManager(global.build());
             ConfigurationBuilder builder = new ConfigurationBuilder();
             builder.clustering()
@@ -99,7 +101,8 @@ public class InfinispanService implements HealthCheck  {
                     .persistence().passivation(false)
                     .addStore(SingleFileStoreConfigurationBuilder.class)
                     .shared(false)
-                    .preload(true);
+                    .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());
@@ -321,16 +324,22 @@ public class InfinispanService implements HealthCheck  {
         camelStatuses.remove(GroupedKey.create(name, env));
     }
 
-    public String geRunnerStatus(String podName) {
-        return runnerStatuses.get(podName);
+    public String getRunnerStatus(String podName, RunnerStatus.NAME 
statusName) {
+        return runnerStatuses.get(GroupedKey.create(podName, 
statusName.name()));
     }
 
-    public void saveRunnerStatus(String podName, String status) {
-        runnerStatuses.put(podName, status);
+    public void saveRunnerStatus(String podName, RunnerStatus.NAME statusName, 
String status) {
+        runnerStatuses.put(GroupedKey.create(podName, statusName.name()), 
status);
     }
 
-    public void deleteRunnerStatus(String podName) {
-        runnerStatuses.remove(podName);
+    public void deleteRunnerStatus(String podName, RunnerStatus.NAME 
statusName) {
+        runnerStatuses.remove(GroupedKey.create(podName, statusName.name()));
+    }
+
+    public void deleteRunnerStatuses(String podName) {
+        Arrays.stream(RunnerStatus.NAME.values()).forEach(statusName -> {
+            runnerStatuses.remove(GroupedKey.create(podName, 
statusName.name()));
+        });
     }
 
     public List<Environment> getEnvironments() {
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 034f3e1d..d24b776e 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
@@ -59,7 +59,6 @@ public class KubernetesService implements HealthCheck{
     public static final int INFORMERS = 4;
     private static final String CAMEL_PREFIX = "camel";
     private static final String KARAVAN_PREFIX = "karavan";
-    public static final String RUNNER_SUFFIX = "runner";
     private static final String JBANG_CACHE_SUFFIX = "jbang-cache";
     private static final String M2_CACHE_SUFFIX = "m2-cache";
 
@@ -382,21 +381,21 @@ public class KubernetesService implements HealthCheck{
         return result;
     }
 
-    public String tryCreateRunner(Project project) {
-        String name = project.getProjectId() + "-" + RUNNER_SUFFIX;
-        createPVC(name + "-" + JBANG_CACHE_SUFFIX, name);
-        createPVC(name + "-" + M2_CACHE_SUFFIX, name);
-        Pod old = 
kubernetesClient().pods().inNamespace(getNamespace()).withName(name).get();
+    public String tryCreateRunner(Project project, String runnerName) {
+
+        createPVC(runnerName + "-" + JBANG_CACHE_SUFFIX, runnerName);
+        createPVC(runnerName + "-" + M2_CACHE_SUFFIX, runnerName);
+        Pod old = 
kubernetesClient().pods().inNamespace(getNamespace()).withName(runnerName).get();
         if (old == null) {
             ProjectFile properties = 
infinispanService.getProjectFile(project.getProjectId(), 
APPLICATION_PROPERTIES_FILENAME);
             Map<String,String> containerResources = ServiceUtil
                     .getRunnerContainerResourcesMap(properties, isOpenshift(), 
project.getRuntime().equals("quarkus"));
-            Pod pod = getPod(project.getProjectId(), name, containerResources);
+            Pod pod = getPod(project.getProjectId(), runnerName, 
containerResources);
             Pod result = kubernetesClient().resource(pod).create();
             LOGGER.info("Created pod " + result.getMetadata().getName());
         }
-        createService(name);
-        return name;
+        createService(runnerName);
+        return runnerName;
     }
 
     public void deleteRunner(String name) {
diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerStatusService.java
 b/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
similarity index 59%
rename from 
karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerStatusService.java
rename to 
karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
index 8ae0ecee..709da51c 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerStatusService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
@@ -25,20 +25,23 @@ import io.vertx.mutiny.core.eventbus.EventBus;
 import io.vertx.mutiny.ext.web.client.HttpResponse;
 import io.vertx.mutiny.ext.web.client.WebClient;
 import org.apache.camel.karavan.model.PodStatus;
+import org.apache.camel.karavan.model.RunnerStatus;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
-import org.eclipse.microprofile.faulttolerance.Retry;
 import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
+import java.util.Arrays;
+import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 
 @ApplicationScoped
-public class RunnerStatusService {
+public class RunnerService {
 
-    private static final Logger LOGGER = 
Logger.getLogger(RunnerStatusService.class.getName());
+    private static final Logger LOGGER = 
Logger.getLogger(RunnerService.class.getName());
     public static final String CMD_COLLECT_RUNNER_STATUS = 
"collect-runner-status";
+    public static final String RUNNER_SUFFIX = "runner";
 
     @Inject
     InfinispanService infinispanService;
@@ -69,19 +72,61 @@ public class RunnerStatusService {
         if (infinispanService.call().getStatus().name().equals("UP")) {
             
infinispanService.getPodStatuses(environment).stream().filter(PodStatus::getRunner).forEach(podStatus
 -> {
                 eventBus.publish(CMD_COLLECT_RUNNER_STATUS, 
podStatus.getName());
-             });
+            });
         }
     }
 
     @ConsumeEvent(value = CMD_COLLECT_RUNNER_STATUS, blocking = true, ordered 
= false)
-    public void collectRunnerStatuses(String podName) throws 
ExecutionException, InterruptedException {
-        String url = "http://"; + podName + "." + 
kubernetesService.getNamespace() + ".svc.cluster.local/q/dev";
-        String result = result(url, 100);
-        if (result != null) {
-            infinispanService.saveRunnerStatus(podName, result);
+    public void collectRunnerStatuses(String podName) {
+        String oldContext = infinispanService.getRunnerStatus(podName, 
RunnerStatus.NAME.context);
+        String newContext = getRunnerStatus(podName, 
RunnerStatus.NAME.context);
+        if (newContext != null) {
+            infinispanService.saveRunnerStatus(podName, 
RunnerStatus.NAME.context, newContext);
+            Arrays.stream(RunnerStatus.NAME.values())
+                    .filter(name -> !name.equals(RunnerStatus.NAME.context))
+                    .forEach(statusName -> {
+                        String status = getRunnerStatus(podName, statusName);
+                        infinispanService.saveRunnerStatus(podName, 
statusName, status);
+                    });
+            reloadCode(podName, oldContext, newContext);
         }
     }
 
+    private void reloadCode(String podName, String oldContext, String 
newContext) {
+        String projectName = podName.replace("-" + RUNNER_SUFFIX, "");
+        String newState = getContextState(newContext);
+        String oldState = getContextState(oldContext);
+        if (newContext != null && !Objects.equals(newState, oldState) && 
"Running".equals(newState)) {
+            sendCodeToRunner(projectName);
+        }
+    }
+
+    private void sendCodeToRunner(String projectName) {
+        infinispanService.getProjectFiles(projectName).forEach(projectFile -> {
+
+        });
+    }
+
+    private String getContextState(String context) {
+        if (context != null) {
+            JsonObject obj = new JsonObject(context);
+            return obj.getJsonObject("context").getString("state");
+        } else {
+            return null;
+        }
+    }
+
+    public String getRunnerStatus(String podName, RunnerStatus.NAME 
statusName) {
+        String url = "http://"; + podName + "." + 
kubernetesService.getNamespace() + ".svc.cluster.local/q/dev/" + 
statusName.name();
+//        String url = "http://0.0.0.0:8888/q/dev/"; + statusName.name();
+        try {
+            return result(url, 1000);
+        } catch (InterruptedException | ExecutionException e) {
+            LOGGER.error(e.getMessage());
+        }
+        return null;
+    }
+
     @CircuitBreaker(requestVolumeThreshold = 10, failureRatio = 0.5, delay = 
1000)
     public String result(String url, int timeout) throws InterruptedException, 
ExecutionException {
         try {
diff --git a/karavan-app/src/main/webui/src/api/KaravanApi.tsx 
b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
index 99ea5dfa..45b86a2a 100644
--- a/karavan-app/src/main/webui/src/api/KaravanApi.tsx
+++ b/karavan-app/src/main/webui/src/api/KaravanApi.tsx
@@ -301,7 +301,16 @@ export class KaravanApi {
     }
 
     static async getRunnerPodStatus(projectId: string, name: string, after: 
(res: AxiosResponse<PodStatus>) => void) {
-        instance.get('/api/runner/status/' + projectId + "/" + name)
+        instance.get('/api/runner/pod/' + projectId + "/" + name)
+            .then(res => {
+                after(res);
+            }).catch(err => {
+            after(err);
+        });
+    }
+
+    static async getRunnerConsoleStatus(projectId: string, statusName: string, 
after: (res: AxiosResponse<string>) => void) {
+        instance.get('/api/runner/console/' + statusName + "/" + projectId)
             .then(res => {
                 after(res);
             }).catch(err => {
diff --git a/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
index ce2fc1c7..e065b315 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
@@ -7,6 +7,8 @@ import '../designer/karavan.css';
 import {Project} from "./ProjectModels";
 import {RunnerToolbar} from "./RunnerToolbar";
 import {RunnerInfoPod} from "./RunnerInfoPod";
+import {RunnerInfoContext} from "./RunnerInfoContext";
+import {RunnerInfoMemory} from "./RunnerInfoMemory";
 
 
 interface Props {
@@ -27,7 +29,11 @@ export const ProjectDevelopment = (props: Props) => {
                         </FlexItem>
                         <Divider orientation={{default: "vertical"}}/>
                         <FlexItem flex={{default: "flex_1"}}>
-                            {/*<Runner project={project} config={config} />*/}
+                            <RunnerInfoMemory project={project} 
config={config} />
+                        </FlexItem>
+                        <Divider orientation={{default: "vertical"}}/>
+                        <FlexItem flex={{default: "flex_1"}}>
+                            <RunnerInfoContext project={project} 
config={config} />
                         </FlexItem>
                         <Divider orientation={{default: "vertical"}}/>
                         <FlexItem>
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoContext.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoContext.tsx
new file mode 100644
index 00000000..9bd7e333
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/RunnerInfoContext.tsx
@@ -0,0 +1,192 @@
+import React, {useEffect, useRef, useState} from 'react';
+import {
+    Button,
+    DescriptionList,
+    DescriptionListDescription,
+    DescriptionListGroup,
+    DescriptionListTerm,
+    Label, LabelGroup,
+    Tooltip
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {PodStatus, Project} from "./ProjectModels";
+import {KaravanApi} from "../api/KaravanApi";
+import {ProjectEventBus} from "./ProjectEventBus";
+import DownIcon from 
"@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+
+
+interface Props {
+    project: Project,
+    config: any,
+}
+
+export const RunnerInfoContext = (props: Props) => {
+
+    const [context, setContext] = useState({});
+
+    useEffect(() => {
+        const interval = setInterval(() => {
+            onRefreshStatus();
+        }, 1000);
+        return () => clearInterval(interval);
+    }, []);
+
+    function onRefreshStatus() {
+        const projectId = props.project.projectId;
+        KaravanApi.getRunnerConsoleStatus(projectId, "context", res => {
+            if (res.status === 200) {
+                setContext(res.data);
+            } else {
+                setContext({});
+            }
+        })
+    }
+
+    function getContextInfo() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="Name" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.name}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getVersionInfo() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="Version" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.version}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getContextState() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="State" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.state}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Uptime" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.uptime}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Phase" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.phase}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getExchanges() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="Total" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as any)?.context?.statistics?.exchangesTotal}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Failed" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.exchangesFailed}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Inflight" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.exchangesInflight}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getProcessingTime() {
+        return (
+            <LabelGroup numLabels={4}>
+                <Tooltip content="Min" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.minProcessingTime}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Mean" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.meanProcessingTime}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Max" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.maxProcessingTime}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Last" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(context as 
any)?.context?.statistics?.lastProcessingTime}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getIcon() {
+        return (getRunning() ? <UpIcon/> : <DownIcon/>)
+    }
+
+    function getColor() {
+        return getRunning() ? "green" : "grey";
+    }
+
+    function getRunning(): boolean {
+        return isRunning(context);
+    }
+
+
+    function isRunning(c: any): boolean {
+        return c?.context?.state === 'Started';
+    }
+
+    return (
+        <DescriptionList isHorizontal>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Camel Context</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getContextInfo()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Version</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getVersionInfo()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>State</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getContextState()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Exchanges:</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getExchanges()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Processing Time</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getProcessingTime()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+        </DescriptionList>
+    );
+}
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoMemory.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoMemory.tsx
new file mode 100644
index 00000000..9558dc35
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/RunnerInfoMemory.tsx
@@ -0,0 +1,183 @@
+import React, {useEffect, useRef, useState} from 'react';
+import {
+    Button,
+    DescriptionList,
+    DescriptionListDescription,
+    DescriptionListGroup,
+    DescriptionListTerm,
+    Label, LabelGroup,
+    Tooltip
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {PodStatus, Project} from "./ProjectModels";
+import {KaravanApi} from "../api/KaravanApi";
+import {ProjectEventBus} from "./ProjectEventBus";
+import DownIcon from 
"@patternfly/react-icons/dist/esm/icons/error-circle-o-icon";
+import UpIcon from "@patternfly/react-icons/dist/esm/icons/check-circle-icon";
+
+
+interface Props {
+    project: Project,
+    config: any,
+}
+
+export const RunnerInfoMemory = (props: Props) => {
+
+    const [memory, setMemory] = useState({});
+    const [jvm, setJvm] = useState({});
+
+    useEffect(() => {
+        const interval = setInterval(() => {
+            onRefreshStatus();
+        }, 1000);
+        return () => clearInterval(interval);
+    }, []);
+
+    function onRefreshStatus() {
+        const projectId = props.project.projectId;
+        KaravanApi.getRunnerConsoleStatus(projectId, "memory", res => {
+            if (res.status === 200) {
+                setMemory(res.data);
+            } else {
+                setMemory({});
+            }
+        })
+        KaravanApi.getRunnerConsoleStatus(projectId, "jvm", res => {
+            if (res.status === 200) {
+                setJvm(res.data);
+            } else {
+                setJvm({});
+            }
+        })
+    }
+
+    function getJvmInfo() {
+        return (
+            <LabelGroup numLabels={2}>
+                <Label icon={getIcon()} color={getColor()}>
+                    {(jvm as any)?.jvm?.vmVendor} {(jvm as 
any)?.jvm?.vmVersion}
+                </Label>
+            </LabelGroup>
+        )
+    }
+
+    function getHeapInfo() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="Init" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.heapMemoryInit}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Max" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.heapMemoryMax}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Used" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.heapMemoryUsed}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getJvmUptime() {
+        return (
+            <LabelGroup numLabels={2}>
+                <Tooltip content="Uptime" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(jvm as any)?.jvm?.vmUptime}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getPid() {
+        return (
+            <LabelGroup numLabels={2}>
+                <Tooltip content="PID" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(jvm as any)?.jvm?.pid}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getNonHeapInfo() {
+        return (
+            <LabelGroup numLabels={3}>
+                <Tooltip content="Init" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.nonHeapMemoryInit}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Max" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.nonHeapMemoryMax}
+                    </Label>
+                </Tooltip>
+                <Tooltip content="Used" position={"bottom"}>
+                    <Label icon={getIcon()} color={getColor()}>
+                        {(memory as any)?.memory?.nonHeapMemoryUsed}
+                    </Label>
+                </Tooltip>
+            </LabelGroup>
+        )
+    }
+
+    function getIcon() {
+        return (getRunning() ? <UpIcon/> : <DownIcon/>)
+    }
+
+    function getColor() {
+        return getRunning() ? "green" : "grey";
+    }
+
+    function getRunning(): boolean {
+        return isRunning(jvm);
+    }
+
+
+    function isRunning(c: any): boolean {
+        return c?.jvm?.pid != undefined;
+    }
+
+    return (
+        <DescriptionList isHorizontal>
+            <DescriptionListGroup>
+                <DescriptionListTerm>JVM Memory</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getJvmInfo()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>PID</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getPid()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Uptime</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getJvmUptime()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Heap</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getHeapInfo()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+            <DescriptionListGroup>
+                <DescriptionListTerm>Non-Heap</DescriptionListTerm>
+                <DescriptionListDescription>
+                    {getNonHeapInfo()}
+                </DescriptionListDescription>
+            </DescriptionListGroup>
+        </DescriptionList>
+    );
+}

Reply via email to