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 e2c3b49e Fix #1155 e2c3b49e is described below commit e2c3b49e51001e3da51043d914b0a36c532787e7 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Thu Feb 29 21:16:08 2024 -0500 Fix #1155 --- .../main/webui/src/designer/route/DslSelector.tsx | 18 +- .../src/project/trace/RunnerInfoTraceMessage.tsx | 190 +++++++++++++++++++++ .../src/project/trace/RunnerInfoTraceModal.tsx | 72 ++++---- .../src/project/trace/RunnerInfoTraceNode.tsx | 76 --------- .../src/main/webui/src/project/trace/trace.css | 43 +++++ 5 files changed, 273 insertions(+), 126 deletions(-) diff --git a/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx b/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx index 14a4bb2b..68e62e22 100644 --- a/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx +++ b/karavan-app/src/main/webui/src/designer/route/DslSelector.tsx @@ -68,7 +68,7 @@ export function DslSelector (props: Props) { function searchInput() { return ( <Flex className="search"> - {selectorTabIndex === 'kamelet' && <FlexItem> + {selectorTabIndex === 'kamelet' && <FlexItem> <Switch label="Custom only" id="switch" @@ -84,7 +84,7 @@ export function DslSelector (props: Props) { </Flex> ) } - + function getCard(dsl: DslMetaModel, index: number) { const labels = dsl.labels !== undefined ? dsl.labels.split(",").filter(label => label !== 'eip') : []; const isCustom = KameletApi.getCustomKameletNames().includes(dsl.name); @@ -96,7 +96,7 @@ export function DslSelector (props: Props) { {['kamelet', 'component'].includes(dsl.navigation.toLowerCase()) && <Badge isRead className="version labels">{dsl.version}</Badge> } - {isCustom && <Badge className="custom">custom</Badge>} + {isCustom && <Badge className="custom">custom</Badge>} </CardHeader> <CardHeader> {CamelUi.getIconForDsl(dsl)} @@ -149,9 +149,9 @@ export function DslSelector (props: Props) { const eipElements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, 'eip', showSteps); const componentElements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, 'component', showSteps) - .filter(dsl => (!blockedComponents.includes(dsl.uri || dsl.name))); + .filter(dsl => (!blockedComponents.includes(dsl.uri || dsl.name))); let kameletElements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, 'kamelet', showSteps) - .filter(dsl => (!blockedKamelets.includes(dsl.name))); + .filter(dsl => (!blockedKamelets.includes(dsl.name))); if (customOnly) kameletElements = kameletElements.filter(k => KameletApi.getCustomKameletNames().includes(k.name)); const filteredEipElements = filterElements(eipElements); @@ -188,14 +188,14 @@ export function DslSelector (props: Props) { } {filteredKameletElements?.length > 0 && <Tab eventKey={'kamelet'} key={"tab-kamelet"} - title={ - <TabTitleText>{`Kamelets (${filteredKameletElements?.length})`}</TabTitleText>}> + title={ + <TabTitleText>{`Kamelets (${filteredKameletElements?.length})`}</TabTitleText>}> </Tab> } {filteredComponentElements?.length > 0 && <Tab eventKey={'component'} key={'tab-component'} - title={ - <TabTitleText>{`Components (${filteredComponentElements?.length})`}</TabTitleText>}> + title={ + <TabTitleText>{`Components (${filteredComponentElements?.length})`}</TabTitleText>}> </Tab> } </Tabs> diff --git a/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceMessage.tsx b/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceMessage.tsx new file mode 100644 index 00000000..7eae1020 --- /dev/null +++ b/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceMessage.tsx @@ -0,0 +1,190 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import React, {useEffect, useState} from 'react'; +import { + CodeBlock, + CodeBlockCode, + DataList, + DataListCell, + DataListItem, + DataListItemCells, + DataListItemRow, + DataListWrapModifier, + DescriptionList, + DescriptionListDescription, + DescriptionListGroup, + DescriptionListTerm, Flex, + Panel, + PanelHeader, + PanelMain, + PanelMainBody, Tab, + Tabs, TabTitleText, Text, TextContent, TextVariants +} from '@patternfly/react-core'; +import '../../designer/karavan.css'; +import {Caption, Table, Tbody, Td, Th, Thead, Tr} from "@patternfly/react-table"; + +interface Props { + trace: any +} + +export function RunnerInfoTraceMessage (props: Props) { + + const [tab, setTab] = useState<string | number>('variables'); + const [variableName, setVariableName] = useState<string | number>(); + + const type = props.trace?.message?.body?.type; + const headers: any[] = [...props.trace?.message?.headers]; + const properties: any[] = [...props.trace?.message?.exchangeProperties]; + const variables: any[] = props.trace?.message?.exchangeVariables ? [...props.trace?.message?.exchangeVariables] : []; + const body = props.trace?.message?.body?.value; + const variable = variables.filter(v => v.key === variableName)?.at(0); + + useEffect(()=> { + console.log(variableName) + }, [variableName]) + + function getBody() { + return ( + <CodeBlock title="Body"> + <CodeBlockCode id="code-content">{body}</CodeBlockCode> + </CodeBlock> + ) + } + + function getVariableValue() { + if (variable?.value !== undefined) { + const isObject = variable?.value instanceof Object; + return ( + <CodeBlock title="Body"> + <CodeBlockCode id="code-content">{isObject ? JSON.stringify(variable.value) : variable.value}</CodeBlockCode> + </CodeBlock> + ) + } + } + + function getVariableType() { + if (variable?.value !== undefined) { + return ( + <TextContent className="title"> + <Flex gap={{default: "gap"}}> + <Text component={TextVariants.p}>Type:</Text> + <Text component={TextVariants.h6}>{variable.type}</Text> + </Flex> + </TextContent> + ) + } + } + + function getHeaders() { + return ( + <Table aria-label="Simple table" variant={'compact'} borders={true} className='table'> + <Caption>Exchange message headers</Caption> + <Thead> + <Tr> + <Th>Key</Th> + <Th>Type</Th> + <Th>Value</Th> + </Tr> + </Thead> + <Tbody> + {headers.map((header: any, index: number) => ( + <Tr key={header[0] + "-" + index}> + <Td dataLabel={'key'}>{header.key}</Td> + <Td dataLabel={'type'}>{header.type}</Td> + <Td dataLabel={'value'}>{header.value}</Td> + </Tr> + ))} + </Tbody> + </Table> + ) + } + + function getProperties() { + return ( + <Table aria-label="Simple table" variant={'compact'} borders={true} className='table'> + <Caption>Exchange message properties</Caption> + <Thead> + <Tr> + <Th>Key</Th> + <Th>Type</Th> + <Th>Value</Th> + </Tr> + </Thead> + <Tbody> + {properties.map((header: any, index: number) => ( + <Tr key={header[0] + "-" + index}> + <Td dataLabel={'key'}>{header.key}</Td> + <Td dataLabel={'type'}>{header.type}</Td> + <Td dataLabel={'value'}>{header.value}</Td> + </Tr> + ))} + </Tbody> + </Table> + ) + } + + return ( + <div className="panel2"> + <TextContent className="title"> + <Text component={TextVariants.h3}>Message</Text> + </TextContent> + <Tabs activeKey={tab} onSelect={(event, eventKey) => setTab(eventKey)}> + <Tab eventKey={'variables'} title={<TabTitleText>Variables</TabTitleText>}/> + <Tab eventKey={'body'} title={<TabTitleText>Body</TabTitleText>}/> + <Tab eventKey={'headers'} title={<TabTitleText>Headers</TabTitleText>}/> + <Tab eventKey={'properties'} title={<TabTitleText>Properties</TabTitleText>}/> + </Tabs> + {tab === 'variables' && variables.length > 0 && + <> + <Tabs activeKey={variableName} onSelect={(event, eventKey) => setVariableName(eventKey)}> + {variables.map(v => (<Tab eventKey={v.key} title={<TabTitleText>{v.key}</TabTitleText>}/>))} + </Tabs> + {getVariableType()} + </> + } + <div className="scrollable"> + {tab === 'variables' && getVariableValue()} + {tab === 'body' && getBody()} + {tab === 'headers' && getHeaders()} + {tab === 'properties' && getProperties()} + </div> + </div> + // <Panel isScrollable> + // <PanelMain tabIndex={0}> + // <PanelHeader> + // <DescriptionList isHorizontal> + // <DescriptionListGroup> + // <DescriptionListTerm>Headers</DescriptionListTerm> + // </DescriptionListGroup> + + // <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> + ); +} diff --git a/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx b/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx index af950b60..862e1fbd 100644 --- a/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx +++ b/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceModal.tsx @@ -16,12 +16,14 @@ */ import React, {useState} from 'react'; import { - Flex, FlexItem, - Modal, ModalVariant, DescriptionListGroup, DescriptionListTerm, DescriptionList, Button + Modal, + ModalVariant, + JumpLinksItem, + JumpLinks, + TextContent, TextVariants, Text } from '@patternfly/react-core'; -import '../../designer/karavan.css'; -import {RunnerInfoTraceNode} from "./RunnerInfoTraceNode"; -import ArrowRightIcon from "@patternfly/react-icons/dist/esm/icons/arrow-right-icon"; +import './trace.css'; +import {RunnerInfoTraceMessage} from "./RunnerInfoTraceMessage"; interface Props { exchangeId: string @@ -34,49 +36,37 @@ export function 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.exchangeId} + width={"90%"} + className="trace-modal" variant={ModalVariant.large} isOpen={props.isOpen} onClose={() => props.onClose()} - actions={[ - ]} + 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, 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)}}> - {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> + <div className="container"> + <div className="panel1"> + <TextContent className="title"> + <Text component={TextVariants.h3}>Nodes</Text> + </TextContent> + <div className="scrollable"> + <JumpLinks isVertical> + {[...props.nodes].map((node: any, index: number) => ( + <JumpLinksItem key={node.uid + "-" + index} + isActive={node.uid === activeNode.uid} + onClick={_ => {setActiveNode(node)}}> + {node.nodeId ? node.nodeId : node.routeId} + </JumpLinksItem> + ))} + {/*{Array.from(Array(100).keys())*/} + {/* .map(_ => (<JumpLinksItem>Inactive section</JumpLinksItem>))}*/} + </JumpLinks> + </div> + </div> + <RunnerInfoTraceMessage trace={activeNode}/> + </div> </Modal> ); } diff --git a/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx b/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx deleted file mode 100644 index 73181663..00000000 --- a/karavan-app/src/main/webui/src/project/trace/RunnerInfoTraceNode.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -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 function RunnerInfoTraceNode (props: Props) { - - const type = props.trace?.message?.body?.type; - const body = props.trace?.message?.body?.value; - const headers: any[] = [...props.trace?.message?.headers]; - 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, index: number) => ( - <DataListItem key={header[0] + "-" + index} 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> - ); -} diff --git a/karavan-app/src/main/webui/src/project/trace/trace.css b/karavan-app/src/main/webui/src/project/trace/trace.css new file mode 100644 index 00000000..401585ee --- /dev/null +++ b/karavan-app/src/main/webui/src/project/trace/trace.css @@ -0,0 +1,43 @@ +.trace-modal { + height: 90%; +} + +.trace-no-padding { + padding: 0; +} + +.trace-padding-bottom-only { + padding: 0 0 var(--pf-v5-c-panel__header--PaddingBottom) 0; +} + +.trace-modal .pf-v5-c-modal-box__body { + display: flex; +} + +.trace-modal .container { + display: flex; + padding: 0; + flex: 1; +} + +.trace-modal .panel1 { + flex: 1; + padding: 10px; +} + +.trace-modal .panel1 .scrollable, +.trace-modal .panel2 .scrollable { + overflow-y: auto; + height: 95%; + padding-top: 10px; +} + +.trace-modal .panel2 { + flex: 4; + padding: 10px; +} + +/*.trace-modal .panel2 .pf-v5-c-tab-content {*/ +/* overflow-y: auto;*/ +/* height: 100%;*/ +/*}*/ \ No newline at end of file