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 d18dab88 Exchange tracing by nodes #757
d18dab88 is described below

commit d18dab88ed6556917e0b3802aa90a8f9fa8c147d
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Sun May 14 19:04:34 2023 -0400

    Exchange tracing by nodes #757
---
 .../camel/karavan/service/RunnerService.java       |  3 -
 .../main/webui/src/projects/ProjectDevelopment.tsx |  2 +-
 .../webui/src/projects/RunnerInfoDataModal.tsx     | 82 -------------------
 .../main/webui/src/projects/RunnerInfoTrace.tsx    | 91 ++++++++++++----------
 .../webui/src/projects/RunnerInfoTraceModal.tsx    | 66 ++++++++++++++++
 .../webui/src/projects/RunnerInfoTraceNode.tsx     | 60 ++++++++++++++
 6 files changed, 176 insertions(+), 128 deletions(-)

diff --git 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
index 2bb70cf7..380bc94e 100644
--- 
a/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
+++ 
b/karavan-app/src/main/java/org/apache/camel/karavan/service/RunnerService.java
@@ -25,7 +25,6 @@ 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.ProjectFile;
 import org.apache.camel.karavan.model.RunnerStatus;
 import org.eclipse.microprofile.config.inject.ConfigProperty;
 import org.eclipse.microprofile.faulttolerance.CircuitBreaker;
@@ -33,9 +32,7 @@ import org.jboss.logging.Logger;
 
 import javax.enterprise.context.ApplicationScoped;
 import javax.inject.Inject;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.ExecutionException;
 
diff --git a/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx 
b/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
index 1e19cc6d..f0d4c340 100644
--- a/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
+++ b/karavan-app/src/main/webui/src/projects/ProjectDevelopment.tsx
@@ -101,7 +101,7 @@ export const ProjectDevelopment = (props: Props) => {
     }
 
     function showConsole(): boolean {
-        return podStatus.phase !== '';
+        return true;//podStatus.phase !== '';
     }
 
     const {project, config} = props;
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoDataModal.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoDataModal.tsx
deleted file mode 100644
index f8700833..00000000
--- a/karavan-app/src/main/webui/src/projects/RunnerInfoDataModal.tsx
+++ /dev/null
@@ -1,82 +0,0 @@
-import React, {useEffect, useRef, useState} from 'react';
-import {
-    Badge, Bullseye,
-    Button, CodeBlock, CodeBlockCode, DataList, DataListCell, DataListItem, 
DataListItemCells, DataListItemRow,
-    DescriptionList,
-    DescriptionListDescription,
-    DescriptionListGroup,
-    DescriptionListTerm, Divider, EmptyState, EmptyStateIcon, 
EmptyStateVariant, Form, FormGroup, FormHelperText, HelperText, HelperTextItem,
-    Label, LabelGroup, Modal, ModalVariant, Panel, PanelHeader, PanelMain, 
PanelMainBody, Switch, Text, TextInput, Title, ToggleGroup, ToggleGroupItem,
-    Tooltip, TooltipPosition
-} from '@patternfly/react-core';
-import '../designer/karavan.css';
-import {getProjectFileType, PodStatus, Project, ProjectFileTypes} 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";
-import {TableComposable, Tbody, Td, Th, Thead, Tr} from 
"@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
-import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
-
-interface Props {
-    trace: any
-    isOpen: boolean
-    onClose: () => void
-}
-
-export const RunnerInfoDataModal = (props: Props) => {
-
-    const type = props.trace?.message?.body?.type;
-    const body = props.trace?.message?.body?.value;
-    const headers: any[] = [{key: "header1", value: "value1"}, {key: 
"header2", value: "value2"}];
-    return (
-        <Modal
-            title={"Exchange: " + props.trace?.message?.exchangeId}
-            variant={ModalVariant.large}
-            isOpen={props.isOpen}
-            onClose={() => props.onClose?.call(this)}
-            actions={[
-                <Button key="cancel" variant="primary" onClick={event => 
props.onClose?.call(this)}>Close</Button>
-            ]}
-        >
-            <Panel isScrollable>
-                <PanelMain tabIndex={0}>
-                    <PanelHeader>
-                        <DescriptionList isHorizontal>
-                            <DescriptionListGroup>
-                                
<DescriptionListTerm>Headers</DescriptionListTerm>
-                                <DescriptionListDescription>
-                                    <DataList aria-label="Compact data list 
example" isCompact>
-                                        {headers.map((header: any) => (
-                                                <DataListItem key={header[0]} 
aria-labelledby="compact-item1">
-                                                    <DataListItemRow>
-                                                        <DataListItemCells
-                                                            dataListCells={[
-                                                                <DataListCell 
key="uid">{header.key}</DataListCell>,
-                                                                <DataListCell 
key="routeId">{header.value}</DataListCell>,
-                                                            ]}
-                                                        />
-                                                    </DataListItemRow>
-                                                </DataListItem>))}
-                                    </DataList>
-                                </DescriptionListDescription>
-                            </DescriptionListGroup>
-                            <DescriptionListGroup>
-                                <DescriptionListTerm>Body</DescriptionListTerm>
-                                <DescriptionListDescription>
-                                    {type && <Label>{type}</Label>}
-                                </DescriptionListDescription>
-                            </DescriptionListGroup>
-                        </DescriptionList>
-                    </PanelHeader>
-                    <PanelMainBody style={{padding: "0"}}>
-                        <CodeBlock title="Body">
-                            <CodeBlockCode 
id="code-content">{body}</CodeBlockCode>
-                        </CodeBlock>
-                    </PanelMainBody>
-                </PanelMain>
-            </Panel>
-        </Modal>
-    );
-}
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoTrace.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoTrace.tsx
index 044c0345..2f9bc76b 100644
--- a/karavan-app/src/main/webui/src/projects/RunnerInfoTrace.tsx
+++ b/karavan-app/src/main/webui/src/projects/RunnerInfoTrace.tsx
@@ -1,24 +1,14 @@
-import React, {useEffect, useRef, useState} from 'react';
+import React, {useState} from 'react';
 import {
-    Badge, Bullseye,
     Button, DataList, DataListCell, DataListItem, DataListItemCells, 
DataListItemRow,
     DescriptionList,
-    DescriptionListDescription,
     DescriptionListGroup,
-    DescriptionListTerm, Divider, EmptyState, EmptyStateIcon, 
EmptyStateVariant,
-    Label, LabelGroup, Panel, PanelHeader, PanelMain, PanelMainBody, Switch, 
Title,
+    DescriptionListTerm, Panel, PanelHeader, PanelMain, PanelMainBody, Switch,
     Tooltip, TooltipPosition
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
-import {getProjectFileType, 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";
-import {TableComposable, Tbody, Td, Th, Thead, Tr} from 
"@patternfly/react-table";
-import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
-import SearchIcon from "@patternfly/react-icons/dist/esm/icons/search-icon";
-import {RunnerInfoDataModal} from "./RunnerInfoDataModal";
+import {RunnerInfoTraceModal} from "./RunnerInfoTraceModal";
 
 
 interface Props {
@@ -29,18 +19,35 @@ interface Props {
 export const RunnerInfoTrace = (props: Props) => {
 
     const [trace, setTrace] = useState({});
+    const [nodes, setNodes] = useState([{}]);
     const [isOpen, setIsOpen] = useState(false);
 
     function closeModal() {
         setIsOpen(false);
     }
 
-    const traces: any[] = props.trace?.trace?.traces || [];
+    function getNodes(exchangeId: string): any[] {
+        const traces: any[] = props.trace?.trace?.traces || [];
+        return traces
+            .filter(t => t.message?.exchangeId === exchangeId)
+            .sort((a, b) => a.uid > b.uid ? 1 : -1);
+    }
+
+    function getNode(exchangeId: string): any {
+        const traces: any[] = props.trace?.trace?.traces || [];
+        return traces
+            .filter(t => t.message?.exchangeId === exchangeId)
+            .sort((a, b) => a.uid > b.uid ? 1 : -1)
+            .at(0);
+    }
+
+    const traces: any[] = (props.trace?.trace?.traces || []).sort((a: any, b: 
any) => b.uid > a.uid ? 1 : -1);
+    const exchanges: any[] = Array.from(new Set((traces).map((item: any) => 
item?.message?.exchangeId)));
     return (
         <Panel isScrollable>
-            <RunnerInfoDataModal isOpen={isOpen} trace={trace} 
onClose={closeModal}/>
+            {isOpen && <RunnerInfoTraceModal isOpen={isOpen} trace={trace} 
nodes={nodes} onClose={closeModal}/>}
             <PanelHeader>
-                <div style={{display:"flex", flexDirection:"row", 
justifyContent:"space-between"}}>
+                <div style={{display: "flex", flexDirection: "row", 
justifyContent: "space-between"}}>
                     <DescriptionList>
                         <DescriptionListGroup>
                             <DescriptionListTerm>Trace routed 
messages</DescriptionListTerm>
@@ -49,9 +56,9 @@ export const RunnerInfoTrace = (props: Props) => {
                     <div style={{marginRight: "16px"}}>
                         <Tooltip content="Auto refresh" 
position={TooltipPosition.left}>
                             <Switch aria-label="refresh"
-                                id="refresh"
-                                isChecked={props.refreshTrace}
-                                onChange={checked => 
ProjectEventBus.refreshTrace(checked)}
+                                    id="refresh"
+                                    isChecked={props.refreshTrace}
+                                    onChange={checked => 
ProjectEventBus.refreshTrace(checked)}
                             />
                         </Tooltip>
                     </div>
@@ -60,30 +67,30 @@ export const RunnerInfoTrace = (props: Props) => {
             <PanelMain tabIndex={0}>
                 <PanelMainBody style={{padding: "0"}}>
                     <DataList aria-label="Compact data list example" isCompact>
-                        {traces.filter(t => t.nodeId === undefined)
-                            .sort((a, b) => b.uid > a.uid ? 1 : -1)
-                            .map(trace => (
-                                <DataListItem key={trace.uid} 
aria-labelledby="compact-item1">
-                                    <DataListItemRow>
-                                        <DataListItemCells
-                                            dataListCells={[
-                                                <DataListCell 
key="uid">{trace.uid}</DataListCell>,
-                                                <DataListCell 
key="routeId">{trace.routeId}</DataListCell>,
-                                                <DataListCell key="exchangeId">
-                                                    <Button style={{padding: 
'0'}} variant={"link"}
-                                                            onClick={e => {
-                                                                
setTrace(trace);
-                                                                
setIsOpen(true);
-                                                            }}>
-                                                        
{trace.message.exchangeId}
-                                                    </Button>
+                        {exchanges.map(exchangeId => {
+                            const node = getNode(exchangeId);
+                            return <DataListItem key={exchangeId} 
aria-labelledby="compact-item1">
+                                <DataListItemRow>
+                                    <DataListItemCells
+                                        dataListCells={[
+                                            <DataListCell 
key="uid">{node?.uid}</DataListCell>,
+                                            <DataListCell key="exchangeId">
+                                                <Button style={{padding: '0'}} 
variant={"link"}
+                                                        onClick={e => {
+                                                            setTrace(trace);
+                                                            
setNodes(getNodes(exchangeId));
+                                                            setIsOpen(true);
+                                                        }}>
+                                                    {exchangeId}
+                                                </Button>
 
-                                                </DataListCell>,
-                                                <DataListCell 
key="timestamp">{new Date(trace.timestamp).toISOString()}</DataListCell>
-                                            ]}
-                                        />
-                                    </DataListItemRow>
-                                </DataListItem>))}
+                                            </DataListCell>,
+                                            <DataListCell 
key="timestamp">{node ? new Date(node?.timestamp).toISOString() : 
""}</DataListCell>
+                                        ]}
+                                    />
+                                </DataListItemRow>
+                            </DataListItem>
+                        })}
                     </DataList>
                 </PanelMainBody>
             </PanelMain>
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoTraceModal.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoTraceModal.tsx
new file mode 100644
index 00000000..a9e4e1d9
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/RunnerInfoTraceModal.tsx
@@ -0,0 +1,66 @@
+import React, {useState} from 'react';
+import {
+    Flex, FlexItem,
+    Modal, ModalVariant, DescriptionListGroup, DescriptionListTerm, 
DescriptionList, Nav, NavList, NavItem, Menu, MenuContent, MenuList, MenuItem, 
MenuGroup, Button
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+import {RunnerInfoTraceNode} from "./RunnerInfoTraceNode";
+import ArrowRightIcon from 
"@patternfly/react-icons/dist/esm/icons/arrow-right-icon";
+
+interface Props {
+    trace: any
+    nodes: any[]
+    isOpen: boolean
+    onClose: () => void
+}
+
+export const RunnerInfoTraceModal = (props: Props) => {
+
+    const [activeNode, setActiveNode] = useState(props.nodes.at(0));
+
+    function getComponent(node: any): any {
+        return {name: node.nodeId, component: (<p>Step 1 content</p>) }
+    }
+
+    function getRoutes(): any[] {
+        return Array.from(new Set((props.nodes).map((item: any) => 
item?.routeId)));
+    }
+
+    return (
+        <Modal
+            title={"Exchange: " + props.trace?.message?.exchangeId}
+            variant={ModalVariant.large}
+            isOpen={props.isOpen}
+            onClose={() => props.onClose?.call(this)}
+            actions={[
+            ]}
+        >
+            <Flex direction={{default: "row"}} 
justifyContent={{default:"justifyContentSpaceBetween"}}>
+                <FlexItem flex={{default: "flex_1"}}>
+                    <DescriptionList>
+                        <DescriptionListGroup>
+                            <DescriptionListTerm>Nodes</DescriptionListTerm>
+                        </DescriptionListGroup>
+                    </DescriptionList>
+                    {props.nodes.map((node: any) => (
+                        <FlexItem>
+                            <Button variant={node.uid === activeNode.uid ? 
"secondary" : "link"}
+                                    icon={node.nodeId === undefined ? 
<ArrowRightIcon/> : undefined}
+                                    onClick={event => {setActiveNode(node)}}>
+                                {node.nodeId ? node.nodeId : node.routeId}
+                            </Button>
+                        </FlexItem>
+                    ))}
+                </FlexItem>
+                <FlexItem flex={{default: "flex_3"}}>
+                    <DescriptionList>
+                        <DescriptionListGroup>
+                            <DescriptionListTerm>Exchange</DescriptionListTerm>
+                        </DescriptionListGroup>
+                    </DescriptionList>
+                    <RunnerInfoTraceNode trace={activeNode} />
+                </FlexItem>
+            </Flex>
+        </Modal>
+    );
+}
diff --git a/karavan-app/src/main/webui/src/projects/RunnerInfoTraceNode.tsx 
b/karavan-app/src/main/webui/src/projects/RunnerInfoTraceNode.tsx
new file mode 100644
index 00000000..dbf0187c
--- /dev/null
+++ b/karavan-app/src/main/webui/src/projects/RunnerInfoTraceNode.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import {
+    CodeBlock, CodeBlockCode, DataList, DataListCell, DataListItem, 
DataListItemCells, DataListItemRow, DataListWrapModifier,
+    DescriptionList,
+    DescriptionListDescription,
+    DescriptionListGroup,
+    DescriptionListTerm, Panel, PanelHeader, PanelMain, PanelMainBody
+} from '@patternfly/react-core';
+import '../designer/karavan.css';
+
+interface Props {
+    trace: any
+}
+
+export const RunnerInfoTraceNode = (props: Props) => {
+
+    const type = props.trace?.message?.body?.type;
+    const body = props.trace?.message?.body?.value;
+    const headers: any[] = [{key: "header1", type: "java.lang.String", value: 
"value1"}, {key: "header2", type: "java.lang.String", value: "value2"}];
+    return (
+        <Panel isScrollable>
+                <PanelMain tabIndex={0}>
+                    <PanelHeader>
+                        <DescriptionList isHorizontal>
+                            <DescriptionListGroup>
+                                
<DescriptionListTerm>Headers</DescriptionListTerm>
+                            </DescriptionListGroup>
+                            <DataList aria-label="Compact data list example" 
isCompact>
+                                {headers.map((header: any) => (
+                                    <DataListItem key={header[0]} 
aria-labelledby="compact-item1">
+                                        <DataListItemRow>
+                                            <DataListItemCells
+                                                dataListCells={[
+                                                    <DataListCell key="uid" 
>{header.key}</DataListCell>,
+                                                    <DataListCell 
key="type">{header.type}</DataListCell>,
+                                                    <DataListCell 
key="routeId" wrapModifier={DataListWrapModifier.truncate}>
+                                                        {header.value}
+                                                    </DataListCell>,
+                                                ]}
+                                            />
+                                        </DataListItemRow>
+                                    </DataListItem>))}
+                            </DataList>
+                            <DescriptionListGroup>
+                                <DescriptionListTerm>Body</DescriptionListTerm>
+                                <DescriptionListDescription>
+                                    {type}
+                                </DescriptionListDescription>
+                            </DescriptionListGroup>
+                        </DescriptionList>
+                    </PanelHeader>
+                    <PanelMainBody style={{padding: "0"}}>
+                        <CodeBlock title="Body">
+                            <CodeBlockCode 
id="code-content">{body}</CodeBlockCode>
+                        </CodeBlock>
+                    </PanelMainBody>
+                </PanelMain>
+            </Panel>
+    );
+}

Reply via email to