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>
+ );
+}