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 c82c7b4423b5705ce4181923d37eafbc3aef66d6 Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Tue Feb 6 19:13:30 2024 -0500 Fix #1109 --- karavan-designer/src/DesignerPage.tsx | 3 + karavan-designer/src/designer/KaravanDesigner.tsx | 2 + .../src/designer/route/DslConnections.tsx | 14 ++- .../src/designer/utils/InfrastructureAPI.ts | 5 + karavan-space/src/space/SpacePage.tsx | 3 + karavan-vscode/webview/App.tsx | 3 + .../webview/topology/TopologyPropertiesPanel.tsx | 103 ++++++++++++++++----- karavan-vscode/webview/topology/TopologyStore.ts | 8 ++ karavan-vscode/webview/topology/TopologyTab.tsx | 5 +- karavan-vscode/webview/topology/topology.css | 16 +++- .../main/webui/src/designer/KaravanDesigner.tsx | 2 + .../webui/src/designer/route/DslConnections.tsx | 14 ++- .../webui/src/designer/utils/InfrastructureAPI.ts | 5 + .../src/main/webui/src/project/FileEditor.tsx | 3 + 14 files changed, 157 insertions(+), 29 deletions(-) diff --git a/karavan-designer/src/DesignerPage.tsx b/karavan-designer/src/DesignerPage.tsx index c8b3cb35..56bde9e3 100644 --- a/karavan-designer/src/DesignerPage.tsx +++ b/karavan-designer/src/DesignerPage.tsx @@ -82,6 +82,9 @@ export const DesignerPage = (props: Props) => { ]} onSavePropertyPlaceholder={(key, value) => console.log("onSavePropertyPlaceholder", key, value)} beans={[]} + onInternalConsumerClick={(uri, name) => { + console.log("onInternalConsumerClick", uri, name) + }} /> ) } diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx b/karavan-designer/src/designer/KaravanDesigner.tsx index 11bf8b6c..05831a38 100644 --- a/karavan-designer/src/designer/KaravanDesigner.tsx +++ b/karavan-designer/src/designer/KaravanDesigner.tsx @@ -48,6 +48,7 @@ interface Props { onSaveCustomCode: (name: string, code: string) => void onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined> onSavePropertyPlaceholder: (key: string, value: string) => void + onInternalConsumerClick: (uri: string, name: string) => void filename: string yaml: string dark: boolean @@ -74,6 +75,7 @@ export function KaravanDesigner(props: Props) { InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode); InfrastructureAPI.setOnSave(props.onSave); InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder); + InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick); setSelectedStep(undefined); const i = makeIntegration(props.yaml, props.filename); diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx index 0cfb4d78..ebb89933 100644 --- a/karavan-designer/src/designer/route/DslConnections.tsx +++ b/karavan-designer/src/designer/route/DslConnections.tsx @@ -24,6 +24,9 @@ import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt" import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; import {v4 as uuidv4} from "uuid"; +import {DeleteElementIcon} from "../utils/ElementIcons"; +import {Button} from "@patternfly/react-core"; +import {InfrastructureAPI} from "../utils/InfrastructureAPI"; const overlapGap: number = 40; @@ -191,7 +194,7 @@ export function DslConnections() { const step = (pos.step as any); const uri = step?.uri; const directOrSeda = step && uri && step?.dslName === 'ToDefinition' && ['direct','seda'].includes(uri); - const label = directOrSeda ? (step?.parameters?.name) : ''; + const name = directOrSeda ? (step?.parameters?.name) : ''; const r = pos.headerRect.height / 2; const outgoingX = width - 20; const outgoingY = data[1] + 15; @@ -201,7 +204,14 @@ export function DslConnections() { <div key={pos.step.uuid + "-icon"} style={{display: "block", position: "absolute", top: imageY, left: imageX}}> {CamelUi.getConnectionIcon(pos.step)} - {directOrSeda && <div style={{position: 'absolute', right: 27, top: -10, whiteSpace: 'nowrap'}}>{label}</div>} + {directOrSeda && + <Button style={{position: 'absolute', right: 27, top: -12, whiteSpace: 'nowrap', zIndex: 300, padding: 0}} + variant={'link'} + aria-label="Goto" + onClick={_ => InfrastructureAPI.onInternalConsumerClick(uri, name)}> + {name} + </Button> + } </div> ) } diff --git a/karavan-designer/src/designer/utils/InfrastructureAPI.ts b/karavan-designer/src/designer/utils/InfrastructureAPI.ts index c2d5ca7c..77ef1bd3 100644 --- a/karavan-designer/src/designer/utils/InfrastructureAPI.ts +++ b/karavan-designer/src/designer/utils/InfrastructureAPI.ts @@ -21,6 +21,7 @@ export class InfrastructureAPI { static onSaveCustomCode: (name: string, code: string) => void; static onSave: (filename: string, yaml: string, propertyOnly: boolean) => void; static onSavePropertyPlaceholder: (key: string, value: string) => void; + static onInternalConsumerClick: (uri: string, name: string) => void; static setOnGetCustomCode(onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>){ this.onGetCustomCode = onGetCustomCode @@ -38,6 +39,10 @@ export class InfrastructureAPI { this.onSavePropertyPlaceholder = onSavePropertyPlaceholder } + static setOnInternalConsumerClick(onInternalConsumerClick:(uri: string, name: string) => void){ + this.onInternalConsumerClick = onInternalConsumerClick + } + // Kubernetes/Docker API static infrastructure: 'kubernetes' | 'docker' | 'local' = 'local'; static configMaps: string[] = []; diff --git a/karavan-space/src/space/SpacePage.tsx b/karavan-space/src/space/SpacePage.tsx index f3004565..24c62b66 100644 --- a/karavan-space/src/space/SpacePage.tsx +++ b/karavan-space/src/space/SpacePage.tsx @@ -111,6 +111,9 @@ export class SpacePage extends React.Component<Props, State> { propertyPlaceholders={[]} beans={[]} onSavePropertyPlaceholder={(key, value) => {}} + onInternalConsumerClick={(uri, name) => { + console.log("onInternalConsumerClick", uri, name) + }} /> ) } diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx index 8addc851..b19b03c7 100644 --- a/karavan-vscode/webview/App.tsx +++ b/karavan-vscode/webview/App.tsx @@ -233,6 +233,9 @@ class App extends React.Component<Props, State> { propertyPlaceholders={this.state.propertyPlaceholders} onSavePropertyPlaceholder={(key, value) => this.savePropertyPlaceholder(key, value)} beans={this.state.beans} + onInternalConsumerClick={(uri, name) => { + console.log("onInternalConsumerClick", uri, name) + }} /> } {loaded && page === "knowledgebase" && <KnowledgebasePage dark={dark} />} diff --git a/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx b/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx index 8387ce1f..67edb46c 100644 --- a/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx +++ b/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx @@ -20,32 +20,93 @@ import {shallow} from "zustand/shallow"; import {TopologySideBar} from "@patternfly/react-topology"; import {useTopologyStore} from "./TopologyStore"; import {DslProperties} from "../designer/property/DslProperties"; -import {Button, Flex, FlexItem, Text, Tooltip, TooltipPosition} from "@patternfly/react-core"; +import { + Button, DescriptionList, + DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, + Flex, + FlexItem, Panel, PanelHeader, PanelMain, PanelMainBody, + Text, TextContent, TextVariants, + Tooltip, + TooltipPosition +} from "@patternfly/react-core"; import CloseIcon from "@patternfly/react-icons/dist/esm/icons/times-icon"; interface Props { onSetFile: (fileName: string) => void } -export function TopologyPropertiesPanel (props: Props) { +export function TopologyPropertiesPanel(props: Props) { - const [selectedIds, setSelectedIds, fileName] = useTopologyStore((s) => - [s.selectedIds, s.setSelectedIds, s.fileName], shallow); + const [selectedIds, setSelectedIds, fileName, nodeData] = useTopologyStore((s) => + [s.selectedIds, s.setSelectedIds, s.fileName, s.nodeData], shallow); + + console.log(nodeData) + + function isRoute() { + if (nodeData && nodeData.type === 'route') { + const uri: string = nodeData?.step?.from.uri || ''; + return uri !== undefined; + } + return false; + } + + function isKamelet() { + if (nodeData && nodeData.type === 'step') { + const uri: string = nodeData?.step?.uri || ''; + return uri.startsWith("kamelet"); + } + return false; + } + + function getFromInfo() { + if (isRoute()) { + const uri: string = nodeData?.step?.from.uri || ''; + const name: string = nodeData?.step?.from.parameters?.name || ''; + if (['direct','seda'].includes(uri)) { + return uri.concat(":").concat(name); + } else { + return uri; + } + } + return "" + } + + function getTitle () { + return isRoute() ? "Route" : (isKamelet() ? "Kamelet" : "Component"); + } function getHeader() { return ( - <Flex className="properties-header" direction={{default: "row"}} justifyContent={{default: "justifyContentFlexStart"}}> + <Flex direction={{default: "row"}} justifyContent={{default: "justifyContentFlexStart"}}> <FlexItem spacer={{ default: 'spacerNone' }}> - <Text>Filename:</Text> - </FlexItem> - <FlexItem> - <Button variant="link" onClick={event => { - if (fileName) { - props.onSetFile(fileName); - } - }} - >{fileName} - </Button> + <Panel> + <PanelHeader> + <TextContent> + <Text component={TextVariants.h3}>{getTitle()}</Text> + </TextContent> + </PanelHeader> + <PanelMain> + <PanelMainBody> + <DescriptionList isHorizontal> + <DescriptionListGroup> + <DescriptionListTerm>File</DescriptionListTerm> + <DescriptionListDescription> + <Button className="file-button" variant="link" onClick={_ => { + if (fileName) { + props.onSetFile(fileName); + } + }}>{fileName} + </Button> + </DescriptionListDescription> + </DescriptionListGroup> + {isRoute() && <DescriptionListGroup> + <DescriptionListTerm>From</DescriptionListTerm> + <DescriptionListDescription>{getFromInfo()}</DescriptionListDescription> + </DescriptionListGroup>} + </DescriptionList> + </PanelMainBody> + </PanelMain> + </Panel> </FlexItem> <FlexItem align={{ default: 'alignRight' }}> <Tooltip content={"Close"} position={TooltipPosition.top}> @@ -58,11 +119,11 @@ export function TopologyPropertiesPanel (props: Props) { return ( <TopologySideBar - className="topology-sidebar" - show={selectedIds.length > 0} - header={getHeader()} - > - <DslProperties designerType={'routes'}/> - </TopologySideBar> + className="topology-sidebar" + show={selectedIds.length > 0} + header={getHeader()} + > + <DslProperties designerType={'routes'}/> + </TopologySideBar> ) } diff --git a/karavan-vscode/webview/topology/TopologyStore.ts b/karavan-vscode/webview/topology/TopologyStore.ts index 73aead9f..4e9ee643 100644 --- a/karavan-vscode/webview/topology/TopologyStore.ts +++ b/karavan-vscode/webview/topology/TopologyStore.ts @@ -35,6 +35,8 @@ interface TopologyState { setFileName: (fileName?: string) => void ranker: string setRanker: (ranker: string) => void + nodeData: any + setNodeData: (nodeData: any) => void } export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({ @@ -55,4 +57,10 @@ export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({ return {ranker: ranker}; }); }, + nodeData: undefined, + setNodeData: (nodeData: any) => { + set((state: TopologyState) => { + return {nodeData: nodeData}; + }); +}, }), shallow) diff --git a/karavan-vscode/webview/topology/TopologyTab.tsx b/karavan-vscode/webview/topology/TopologyTab.tsx index 727905cc..1f2d165e 100644 --- a/karavan-vscode/webview/topology/TopologyTab.tsx +++ b/karavan-vscode/webview/topology/TopologyTab.tsx @@ -47,8 +47,8 @@ interface Props { export function TopologyTab(props: Props) { - const [selectedIds, setSelectedIds, setFileName, ranker, setRanker] = useTopologyStore((s) => - [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, s.setRanker], shallow); + const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, setNodeData] = useTopologyStore((s) => + [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, s.setRanker, s.setNodeData], shallow); const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], shallow) function setTopologySelected(model: Model, ids: string []) { @@ -57,6 +57,7 @@ export function TopologyTab(props: Props) { const node = model.nodes?.filter(node => node.id === ids[0]); if (node && node.length > 0) { const data = node[0].data; + setNodeData(data); setFileName(data.fileName) if (data.step) { setSelectedStep(data.step) diff --git a/karavan-vscode/webview/topology/topology.css b/karavan-vscode/webview/topology/topology.css index cb261e21..24fe7679 100644 --- a/karavan-vscode/webview/topology/topology.css +++ b/karavan-vscode/webview/topology/topology.css @@ -41,8 +41,8 @@ overflow: auto; } -.karavan .topology-panel .properties-header { - padding: 10px; +.karavan .topology-panel .properties .headers { + display: none; } .karavan .topology-panel .common-node .icon { @@ -50,6 +50,14 @@ width: 32px; } +.karavan .topology-panel .pf-v5-c-panel__header { + padding-bottom: 0; +} + +.karavan .topology-panel .file-button { + padding: 0; +} + .karavan .topology-sidebar .pf-topology-side-bar__header { margin-right: 0; } @@ -72,4 +80,8 @@ .karavan .topology-sidebar .properties .pf-v5-c-form { pointer-events: none; opacity: 0.7; +} +.karavan .topology-sidebar .properties .pf-v5-c-form .pf-v5-c-form__group-label-help { + pointer-events: auto; + opacity: 1; } \ No newline at end of file diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx index 11bf8b6c..05831a38 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/KaravanDesigner.tsx @@ -48,6 +48,7 @@ interface Props { onSaveCustomCode: (name: string, code: string) => void onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined> onSavePropertyPlaceholder: (key: string, value: string) => void + onInternalConsumerClick: (uri: string, name: string) => void filename: string yaml: string dark: boolean @@ -74,6 +75,7 @@ export function KaravanDesigner(props: Props) { InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode); InfrastructureAPI.setOnSave(props.onSave); InfrastructureAPI.setOnSavePropertyPlaceholder(props.onSavePropertyPlaceholder); + InfrastructureAPI.setOnInternalConsumerClick(props.onInternalConsumerClick); setSelectedStep(undefined); const i = makeIntegration(props.yaml, props.filename); diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx index 0cfb4d78..ebb89933 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/designer/route/DslConnections.tsx @@ -24,6 +24,9 @@ import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt" import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition"; import {v4 as uuidv4} from "uuid"; +import {DeleteElementIcon} from "../utils/ElementIcons"; +import {Button} from "@patternfly/react-core"; +import {InfrastructureAPI} from "../utils/InfrastructureAPI"; const overlapGap: number = 40; @@ -191,7 +194,7 @@ export function DslConnections() { const step = (pos.step as any); const uri = step?.uri; const directOrSeda = step && uri && step?.dslName === 'ToDefinition' && ['direct','seda'].includes(uri); - const label = directOrSeda ? (step?.parameters?.name) : ''; + const name = directOrSeda ? (step?.parameters?.name) : ''; const r = pos.headerRect.height / 2; const outgoingX = width - 20; const outgoingY = data[1] + 15; @@ -201,7 +204,14 @@ export function DslConnections() { <div key={pos.step.uuid + "-icon"} style={{display: "block", position: "absolute", top: imageY, left: imageX}}> {CamelUi.getConnectionIcon(pos.step)} - {directOrSeda && <div style={{position: 'absolute', right: 27, top: -10, whiteSpace: 'nowrap'}}>{label}</div>} + {directOrSeda && + <Button style={{position: 'absolute', right: 27, top: -12, whiteSpace: 'nowrap', zIndex: 300, padding: 0}} + variant={'link'} + aria-label="Goto" + onClick={_ => InfrastructureAPI.onInternalConsumerClick(uri, name)}> + {name} + </Button> + } </div> ) } diff --git a/karavan-web/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts b/karavan-web/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts index c2d5ca7c..77ef1bd3 100644 --- a/karavan-web/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts +++ b/karavan-web/karavan-app/src/main/webui/src/designer/utils/InfrastructureAPI.ts @@ -21,6 +21,7 @@ export class InfrastructureAPI { static onSaveCustomCode: (name: string, code: string) => void; static onSave: (filename: string, yaml: string, propertyOnly: boolean) => void; static onSavePropertyPlaceholder: (key: string, value: string) => void; + static onInternalConsumerClick: (uri: string, name: string) => void; static setOnGetCustomCode(onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>){ this.onGetCustomCode = onGetCustomCode @@ -38,6 +39,10 @@ export class InfrastructureAPI { this.onSavePropertyPlaceholder = onSavePropertyPlaceholder } + static setOnInternalConsumerClick(onInternalConsumerClick:(uri: string, name: string) => void){ + this.onInternalConsumerClick = onInternalConsumerClick + } + // Kubernetes/Docker API static infrastructure: 'kubernetes' | 'docker' | 'local' = 'local'; static configMaps: string[] = []; diff --git a/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx b/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx index 9ca0e26c..20b6a53e 100644 --- a/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx +++ b/karavan-web/karavan-app/src/main/webui/src/project/FileEditor.tsx @@ -94,6 +94,9 @@ export function FileEditor (props: Props) { propertyPlaceholders={propertyPlaceholders} onSavePropertyPlaceholder={onSavePropertyPlaceholder} beans={beans} + onInternalConsumerClick={(uri, name) => { + console.log("onInternalConsumerClick", uri, name) + }} /> ) }