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 197b4f5d Fix #1362 197b4f5d is described below commit 197b4f5d856dd665e75eb1d6dd3918c6dd3a153b Author: Marat Gubaidullin <ma...@talismancloud.io> AuthorDate: Fri Aug 16 13:58:31 2024 -0400 Fix #1362 --- .../src/main/webui/src/project/ProjectPanel.tsx | 2 + .../src/main/webui/src/topology/CustomGroup.tsx | 6 +- .../src/main/webui/src/topology/TopologyApi.tsx | 119 ++++++++++++--------- .../src/main/webui/src/topology/TopologyTab.tsx | 5 +- .../main/webui/src/topology/TopologyToolbar.tsx | 7 ++ .../src/main/webui/src/topology/topology.css | 4 + karavan-core/src/core/api/TopologyUtils.ts | 12 +-- karavan-designer/src/topology/CustomGroup.tsx | 6 +- karavan-designer/src/topology/TopologyApi.tsx | 119 ++++++++++++--------- karavan-designer/src/topology/TopologyTab.tsx | 5 +- karavan-designer/src/topology/TopologyToolbar.tsx | 7 ++ karavan-designer/src/topology/topology.css | 4 + karavan-space/src/topology/CustomGroup.tsx | 6 +- karavan-space/src/topology/TopologyApi.tsx | 119 ++++++++++++--------- karavan-space/src/topology/TopologyTab.tsx | 5 +- karavan-space/src/topology/TopologyToolbar.tsx | 7 ++ karavan-space/src/topology/topology.css | 4 + 17 files changed, 269 insertions(+), 168 deletions(-) diff --git a/karavan-app/src/main/webui/src/project/ProjectPanel.tsx b/karavan-app/src/main/webui/src/project/ProjectPanel.tsx index f41d5710..9b46a45c 100644 --- a/karavan-app/src/main/webui/src/project/ProjectPanel.tsx +++ b/karavan-app/src/main/webui/src/project/ProjectPanel.tsx @@ -45,6 +45,7 @@ export function ProjectPanel() { const [setFile] = useFileStore((s) => [s.setFile], shallow); const [files, setFiles] = useFilesStore((s) => [s.files, s.setFiles], shallow); const [setShowWizard] = useWizardStore((s) => [s.setShowWizard], shallow) + const isDev = config.environment === 'dev'; useEffect(() => { onRefresh(); @@ -90,6 +91,7 @@ export function ProjectPanel() { setShowWizard(true) }} onSetFile={(fileName) => selectFile(fileName)} + isDev={isDev} /> <CreateIntegrationModal/> <BeanWizard/> diff --git a/karavan-app/src/main/webui/src/topology/CustomGroup.tsx b/karavan-app/src/main/webui/src/topology/CustomGroup.tsx index 9e366c7c..595250a8 100644 --- a/karavan-app/src/main/webui/src/topology/CustomGroup.tsx +++ b/karavan-app/src/main/webui/src/topology/CustomGroup.tsx @@ -18,13 +18,11 @@ import * as React from 'react'; import './topology.css'; -import { DefaultGroup, observer} from '@patternfly/react-topology'; - +import {DefaultGroup, observer} from '@patternfly/react-topology'; const CustomGroup: React.FC<any> = observer(({ element, ...rest }) => { - return ( - <DefaultGroup element={element} {...rest}> + <DefaultGroup element={element} className={"topology-group"} {...rest}> </DefaultGroup> ) }) diff --git a/karavan-app/src/main/webui/src/topology/TopologyApi.tsx b/karavan-app/src/main/webui/src/topology/TopologyApi.tsx index 174ad6a6..a5342a37 100644 --- a/karavan-app/src/main/webui/src/topology/TopologyApi.tsx +++ b/karavan-app/src/main/webui/src/topology/TopologyApi.tsx @@ -33,13 +33,7 @@ import CustomNode from "./CustomNode"; import {Integration, IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition"; import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml"; import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; -import { - TopologyIncomingNode, - TopologyOutgoingNode, - TopologyRestNode, - TopologyRouteConfigurationNode, - TopologyRouteNode -} from "karavan-core/lib/model/TopologyDefinition"; +import {TopologyIncomingNode, TopologyOutgoingNode, TopologyRestNode, TopologyRouteConfigurationNode, TopologyRouteNode} from "karavan-core/lib/model/TopologyDefinition"; import CustomEdge from "./CustomEdge"; import CustomGroup from "./CustomGroup"; @@ -174,16 +168,18 @@ export function getExternalEdges(tons: TopologyOutgoingNode[], tins: TopologyInc tons.filter(ton => ton.type === 'external').forEach((ton, index) => { const uniqueUri = ton.uniqueUri; if (uniqueUri) { - const target = TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri); - const node: EdgeModel = { - id: 'external-' + ton.id + '-' + index, - type: 'edge', - source: ton.id, - target: target, - edgeStyle: EdgeStyle.dotted, - animationSpeed: EdgeAnimationSpeed.slow - } - if (target) result.push(node); + TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri).forEach(target => { + const node: EdgeModel = { + id: 'external-' + ton.id + '-' + target, + type: 'edge', + source: ton.id, + target: target, + edgeStyle: EdgeStyle.dotted, + animationSpeed: EdgeAnimationSpeed.medium, + data : {groupName: uniqueUri} + } + result.push(node); + }); } }); return result; @@ -280,33 +276,6 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { const trcons = TopologyUtils.findTopologyRouteConfigurationOutgoingNodes(integrations); const nodes: NodeModel[] = []; - const groups: NodeModel[] = []; - - const children1: string[] = []; - children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); - children1.push(...trestns.map(i => i.id)); - groups.push({ - id: 'consumer-group', - children: children1, - type: 'group', - group: true, - label: 'Consumer group', - style: { - padding: 25, - } - }) - - const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; - groups.push({ - id: 'producer-group', - children: children2, - type: 'group', - group: true, - label: 'Producer group', - style: { - padding: 25, - } - }) nodes.push(...getRestNodes(trestns)) nodes.push(...getIncomingNodes(tins)) @@ -315,17 +284,69 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { nodes.push(...getOutgoingNodes(tons)) nodes.push(...getOutgoingNodes(trcons)) - if (grouping === true) { - nodes.push(...groups) - } - const edges: EdgeModel[] = []; edges.push(...getIncomingEdges(tins)); edges.push(...getOutgoingEdges(tons)); edges.push(...getRestEdges(trestns, tins)); edges.push(...getInternalEdges(tons, tins)); edges.push(...getInternalEdges(trcons, tins)); - // edges.push(...getExternalEdges(tons,tins)); + + + // Groups + const groups: NodeModel[] = []; + if (grouping === true) { + const children1: string[] = []; + children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); + children1.push(...trestns.map(i => i.id)); + groups.push({ + id: 'consumer-group', + children: children1, + type: 'group', + group: true, + label: 'Consumer group', + style: { + padding: 20, + } + }) + + const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; + groups.push({ + id: 'producer-group', + children: children2, + type: 'group', + group: true, + label: 'Producer group', + style: { + padding: 20, + }, + }) + } else { + const externalEdges = getExternalEdges(tons,tins); + edges.push(...externalEdges); + const uniqueGroups: Map<string, string[]> = new Map(); + + externalEdges.forEach(edge => { + const groupName = edge.data.groupName; + const children = uniqueGroups.get(groupName) || []; + if (edge.source) children.push(edge.source) + if (edge.target) children.push(edge.target) + uniqueGroups.set(groupName, [...new Set(children)]); + }); + + uniqueGroups.forEach((children, groupName) => { + groups.push({ + id: groupName + '-group', + children: children, + type: 'group', + group: true, + // label: edge.id + ' group', + style: { + padding: 20, + } + }) + }) + } + nodes.push(...groups) return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', layout: 'Dagre'}}; } diff --git a/karavan-app/src/main/webui/src/topology/TopologyTab.tsx b/karavan-app/src/main/webui/src/topology/TopologyTab.tsx index cc189e29..d8408a99 100644 --- a/karavan-app/src/main/webui/src/topology/TopologyTab.tsx +++ b/karavan-app/src/main/webui/src/topology/TopologyTab.tsx @@ -45,6 +45,7 @@ interface Props { onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyTab(props: Props) { @@ -146,7 +147,9 @@ export function TopologyTab(props: Props) { ? <TopologyToolbar onClickAddRoute={props.onClickAddRoute} onClickAddBean={props.onClickAddBean} onClickAddKamelet={props.onClickAddKamelet} - onClickAddREST={props.onClickAddREST}/> + onClickAddREST={props.onClickAddREST} + isDev={props.isDev} + /> : undefined} sideBar={<TopologyPropertiesPanel onSetFile={props.onSetFile}/>} controlBar={ diff --git a/karavan-app/src/main/webui/src/topology/TopologyToolbar.tsx b/karavan-app/src/main/webui/src/topology/TopologyToolbar.tsx index 0b23c542..2ac6eda9 100644 --- a/karavan-app/src/main/webui/src/topology/TopologyToolbar.tsx +++ b/karavan-app/src/main/webui/src/topology/TopologyToolbar.tsx @@ -24,17 +24,20 @@ import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon"; import {useTopologyStore} from "./TopologyStore"; import {shallow} from "zustand/shallow"; + interface Props { onClickAddRoute: () => void onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyToolbar (props: Props) { const [showGroups, setShowGroups] = useTopologyStore((s) => [s.showGroups, s.setShowGroups], shallow); + const isDev = props.isDev return ( <div className='topology-toolbar'> @@ -52,6 +55,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Integration Route"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"primary"} icon={<PlusIcon/>} onClick={e => props.onClickAddRoute()} @@ -63,6 +67,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add REST API"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddREST()} @@ -74,6 +79,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Kamelet"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddKamelet()} @@ -85,6 +91,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Bean"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddBean()} diff --git a/karavan-app/src/main/webui/src/topology/topology.css b/karavan-app/src/main/webui/src/topology/topology.css index 1828bd1e..6edc633d 100644 --- a/karavan-app/src/main/webui/src/topology/topology.css +++ b/karavan-app/src/main/webui/src/topology/topology.css @@ -115,4 +115,8 @@ .karavan .topology-panel .auto-start .text { fill: var(--pf-topology__node__label__text--Fill); +} + +.karavan .topology-group .pf-topology__group__label { + display: none; } \ No newline at end of file diff --git a/karavan-core/src/core/api/TopologyUtils.ts b/karavan-core/src/core/api/TopologyUtils.ts index 1788f740..bfe60e22 100644 --- a/karavan-core/src/core/api/TopologyUtils.ts +++ b/karavan-core/src/core/api/TopologyUtils.ts @@ -38,6 +38,7 @@ import { ComponentApi } from './ComponentApi'; import { CamelDefinitionApiExt } from './CamelDefinitionApiExt'; import { CamelDisplayUtil } from './CamelDisplayUtil'; import { CamelUtil } from './CamelUtil'; +import { notDeepEqual } from 'node:assert'; const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"]; @@ -342,12 +343,11 @@ export class TopologyUtils { } } - static getNodeIdByUniqueUri(tins: TopologyIncomingNode[], uniqueUri: string): string | undefined { - const node = tins - .filter(r => r.uniqueUri === uniqueUri).at(0); - if (node) { - return node.id; - } + static getNodeIdByUniqueUri(tins: TopologyIncomingNode[], uniqueUri: string): string [] { + const result: string[] = []; + tins.filter(r => r.uniqueUri === uniqueUri) + ?.forEach(node => result.push(node.id)) + return result; } static getRouteIdByUri(tins: TopologyIncomingNode[], uri: string): string | undefined { diff --git a/karavan-designer/src/topology/CustomGroup.tsx b/karavan-designer/src/topology/CustomGroup.tsx index 9e366c7c..595250a8 100644 --- a/karavan-designer/src/topology/CustomGroup.tsx +++ b/karavan-designer/src/topology/CustomGroup.tsx @@ -18,13 +18,11 @@ import * as React from 'react'; import './topology.css'; -import { DefaultGroup, observer} from '@patternfly/react-topology'; - +import {DefaultGroup, observer} from '@patternfly/react-topology'; const CustomGroup: React.FC<any> = observer(({ element, ...rest }) => { - return ( - <DefaultGroup element={element} {...rest}> + <DefaultGroup element={element} className={"topology-group"} {...rest}> </DefaultGroup> ) }) diff --git a/karavan-designer/src/topology/TopologyApi.tsx b/karavan-designer/src/topology/TopologyApi.tsx index 174ad6a6..a5342a37 100644 --- a/karavan-designer/src/topology/TopologyApi.tsx +++ b/karavan-designer/src/topology/TopologyApi.tsx @@ -33,13 +33,7 @@ import CustomNode from "./CustomNode"; import {Integration, IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition"; import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml"; import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; -import { - TopologyIncomingNode, - TopologyOutgoingNode, - TopologyRestNode, - TopologyRouteConfigurationNode, - TopologyRouteNode -} from "karavan-core/lib/model/TopologyDefinition"; +import {TopologyIncomingNode, TopologyOutgoingNode, TopologyRestNode, TopologyRouteConfigurationNode, TopologyRouteNode} from "karavan-core/lib/model/TopologyDefinition"; import CustomEdge from "./CustomEdge"; import CustomGroup from "./CustomGroup"; @@ -174,16 +168,18 @@ export function getExternalEdges(tons: TopologyOutgoingNode[], tins: TopologyInc tons.filter(ton => ton.type === 'external').forEach((ton, index) => { const uniqueUri = ton.uniqueUri; if (uniqueUri) { - const target = TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri); - const node: EdgeModel = { - id: 'external-' + ton.id + '-' + index, - type: 'edge', - source: ton.id, - target: target, - edgeStyle: EdgeStyle.dotted, - animationSpeed: EdgeAnimationSpeed.slow - } - if (target) result.push(node); + TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri).forEach(target => { + const node: EdgeModel = { + id: 'external-' + ton.id + '-' + target, + type: 'edge', + source: ton.id, + target: target, + edgeStyle: EdgeStyle.dotted, + animationSpeed: EdgeAnimationSpeed.medium, + data : {groupName: uniqueUri} + } + result.push(node); + }); } }); return result; @@ -280,33 +276,6 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { const trcons = TopologyUtils.findTopologyRouteConfigurationOutgoingNodes(integrations); const nodes: NodeModel[] = []; - const groups: NodeModel[] = []; - - const children1: string[] = []; - children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); - children1.push(...trestns.map(i => i.id)); - groups.push({ - id: 'consumer-group', - children: children1, - type: 'group', - group: true, - label: 'Consumer group', - style: { - padding: 25, - } - }) - - const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; - groups.push({ - id: 'producer-group', - children: children2, - type: 'group', - group: true, - label: 'Producer group', - style: { - padding: 25, - } - }) nodes.push(...getRestNodes(trestns)) nodes.push(...getIncomingNodes(tins)) @@ -315,17 +284,69 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { nodes.push(...getOutgoingNodes(tons)) nodes.push(...getOutgoingNodes(trcons)) - if (grouping === true) { - nodes.push(...groups) - } - const edges: EdgeModel[] = []; edges.push(...getIncomingEdges(tins)); edges.push(...getOutgoingEdges(tons)); edges.push(...getRestEdges(trestns, tins)); edges.push(...getInternalEdges(tons, tins)); edges.push(...getInternalEdges(trcons, tins)); - // edges.push(...getExternalEdges(tons,tins)); + + + // Groups + const groups: NodeModel[] = []; + if (grouping === true) { + const children1: string[] = []; + children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); + children1.push(...trestns.map(i => i.id)); + groups.push({ + id: 'consumer-group', + children: children1, + type: 'group', + group: true, + label: 'Consumer group', + style: { + padding: 20, + } + }) + + const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; + groups.push({ + id: 'producer-group', + children: children2, + type: 'group', + group: true, + label: 'Producer group', + style: { + padding: 20, + }, + }) + } else { + const externalEdges = getExternalEdges(tons,tins); + edges.push(...externalEdges); + const uniqueGroups: Map<string, string[]> = new Map(); + + externalEdges.forEach(edge => { + const groupName = edge.data.groupName; + const children = uniqueGroups.get(groupName) || []; + if (edge.source) children.push(edge.source) + if (edge.target) children.push(edge.target) + uniqueGroups.set(groupName, [...new Set(children)]); + }); + + uniqueGroups.forEach((children, groupName) => { + groups.push({ + id: groupName + '-group', + children: children, + type: 'group', + group: true, + // label: edge.id + ' group', + style: { + padding: 20, + } + }) + }) + } + nodes.push(...groups) return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', layout: 'Dagre'}}; } diff --git a/karavan-designer/src/topology/TopologyTab.tsx b/karavan-designer/src/topology/TopologyTab.tsx index cc189e29..d8408a99 100644 --- a/karavan-designer/src/topology/TopologyTab.tsx +++ b/karavan-designer/src/topology/TopologyTab.tsx @@ -45,6 +45,7 @@ interface Props { onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyTab(props: Props) { @@ -146,7 +147,9 @@ export function TopologyTab(props: Props) { ? <TopologyToolbar onClickAddRoute={props.onClickAddRoute} onClickAddBean={props.onClickAddBean} onClickAddKamelet={props.onClickAddKamelet} - onClickAddREST={props.onClickAddREST}/> + onClickAddREST={props.onClickAddREST} + isDev={props.isDev} + /> : undefined} sideBar={<TopologyPropertiesPanel onSetFile={props.onSetFile}/>} controlBar={ diff --git a/karavan-designer/src/topology/TopologyToolbar.tsx b/karavan-designer/src/topology/TopologyToolbar.tsx index 0b23c542..2ac6eda9 100644 --- a/karavan-designer/src/topology/TopologyToolbar.tsx +++ b/karavan-designer/src/topology/TopologyToolbar.tsx @@ -24,17 +24,20 @@ import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon"; import {useTopologyStore} from "./TopologyStore"; import {shallow} from "zustand/shallow"; + interface Props { onClickAddRoute: () => void onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyToolbar (props: Props) { const [showGroups, setShowGroups] = useTopologyStore((s) => [s.showGroups, s.setShowGroups], shallow); + const isDev = props.isDev return ( <div className='topology-toolbar'> @@ -52,6 +55,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Integration Route"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"primary"} icon={<PlusIcon/>} onClick={e => props.onClickAddRoute()} @@ -63,6 +67,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add REST API"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddREST()} @@ -74,6 +79,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Kamelet"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddKamelet()} @@ -85,6 +91,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Bean"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddBean()} diff --git a/karavan-designer/src/topology/topology.css b/karavan-designer/src/topology/topology.css index 1828bd1e..6edc633d 100644 --- a/karavan-designer/src/topology/topology.css +++ b/karavan-designer/src/topology/topology.css @@ -115,4 +115,8 @@ .karavan .topology-panel .auto-start .text { fill: var(--pf-topology__node__label__text--Fill); +} + +.karavan .topology-group .pf-topology__group__label { + display: none; } \ No newline at end of file diff --git a/karavan-space/src/topology/CustomGroup.tsx b/karavan-space/src/topology/CustomGroup.tsx index 9e366c7c..595250a8 100644 --- a/karavan-space/src/topology/CustomGroup.tsx +++ b/karavan-space/src/topology/CustomGroup.tsx @@ -18,13 +18,11 @@ import * as React from 'react'; import './topology.css'; -import { DefaultGroup, observer} from '@patternfly/react-topology'; - +import {DefaultGroup, observer} from '@patternfly/react-topology'; const CustomGroup: React.FC<any> = observer(({ element, ...rest }) => { - return ( - <DefaultGroup element={element} {...rest}> + <DefaultGroup element={element} className={"topology-group"} {...rest}> </DefaultGroup> ) }) diff --git a/karavan-space/src/topology/TopologyApi.tsx b/karavan-space/src/topology/TopologyApi.tsx index 174ad6a6..a5342a37 100644 --- a/karavan-space/src/topology/TopologyApi.tsx +++ b/karavan-space/src/topology/TopologyApi.tsx @@ -33,13 +33,7 @@ import CustomNode from "./CustomNode"; import {Integration, IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition"; import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml"; import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils"; -import { - TopologyIncomingNode, - TopologyOutgoingNode, - TopologyRestNode, - TopologyRouteConfigurationNode, - TopologyRouteNode -} from "karavan-core/lib/model/TopologyDefinition"; +import {TopologyIncomingNode, TopologyOutgoingNode, TopologyRestNode, TopologyRouteConfigurationNode, TopologyRouteNode} from "karavan-core/lib/model/TopologyDefinition"; import CustomEdge from "./CustomEdge"; import CustomGroup from "./CustomGroup"; @@ -174,16 +168,18 @@ export function getExternalEdges(tons: TopologyOutgoingNode[], tins: TopologyInc tons.filter(ton => ton.type === 'external').forEach((ton, index) => { const uniqueUri = ton.uniqueUri; if (uniqueUri) { - const target = TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri); - const node: EdgeModel = { - id: 'external-' + ton.id + '-' + index, - type: 'edge', - source: ton.id, - target: target, - edgeStyle: EdgeStyle.dotted, - animationSpeed: EdgeAnimationSpeed.slow - } - if (target) result.push(node); + TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri).forEach(target => { + const node: EdgeModel = { + id: 'external-' + ton.id + '-' + target, + type: 'edge', + source: ton.id, + target: target, + edgeStyle: EdgeStyle.dotted, + animationSpeed: EdgeAnimationSpeed.medium, + data : {groupName: uniqueUri} + } + result.push(node); + }); } }); return result; @@ -280,33 +276,6 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { const trcons = TopologyUtils.findTopologyRouteConfigurationOutgoingNodes(integrations); const nodes: NodeModel[] = []; - const groups: NodeModel[] = []; - - const children1: string[] = []; - children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); - children1.push(...trestns.map(i => i.id)); - groups.push({ - id: 'consumer-group', - children: children1, - type: 'group', - group: true, - label: 'Consumer group', - style: { - padding: 25, - } - }) - - const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; - groups.push({ - id: 'producer-group', - children: children2, - type: 'group', - group: true, - label: 'Producer group', - style: { - padding: 25, - } - }) nodes.push(...getRestNodes(trestns)) nodes.push(...getIncomingNodes(tins)) @@ -315,17 +284,69 @@ export function getModel(files: IntegrationFile[], grouping?: boolean): Model { nodes.push(...getOutgoingNodes(tons)) nodes.push(...getOutgoingNodes(trcons)) - if (grouping === true) { - nodes.push(...groups) - } - const edges: EdgeModel[] = []; edges.push(...getIncomingEdges(tins)); edges.push(...getOutgoingEdges(tons)); edges.push(...getRestEdges(trestns, tins)); edges.push(...getInternalEdges(tons, tins)); edges.push(...getInternalEdges(trcons, tins)); - // edges.push(...getExternalEdges(tons,tins)); + + + // Groups + const groups: NodeModel[] = []; + if (grouping === true) { + const children1: string[] = []; + children1.push(...tins.filter(i => i.type === 'external').map(i => i.id)); + children1.push(...trestns.map(i => i.id)); + groups.push({ + id: 'consumer-group', + children: children1, + type: 'group', + group: true, + label: 'Consumer group', + style: { + padding: 20, + } + }) + + const children2 = [...tons.filter(i => i.type === 'external').map(i => i.id)]; + groups.push({ + id: 'producer-group', + children: children2, + type: 'group', + group: true, + label: 'Producer group', + style: { + padding: 20, + }, + }) + } else { + const externalEdges = getExternalEdges(tons,tins); + edges.push(...externalEdges); + const uniqueGroups: Map<string, string[]> = new Map(); + + externalEdges.forEach(edge => { + const groupName = edge.data.groupName; + const children = uniqueGroups.get(groupName) || []; + if (edge.source) children.push(edge.source) + if (edge.target) children.push(edge.target) + uniqueGroups.set(groupName, [...new Set(children)]); + }); + + uniqueGroups.forEach((children, groupName) => { + groups.push({ + id: groupName + '-group', + children: children, + type: 'group', + group: true, + // label: edge.id + ' group', + style: { + padding: 20, + } + }) + }) + } + nodes.push(...groups) return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', layout: 'Dagre'}}; } diff --git a/karavan-space/src/topology/TopologyTab.tsx b/karavan-space/src/topology/TopologyTab.tsx index cc189e29..d8408a99 100644 --- a/karavan-space/src/topology/TopologyTab.tsx +++ b/karavan-space/src/topology/TopologyTab.tsx @@ -45,6 +45,7 @@ interface Props { onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyTab(props: Props) { @@ -146,7 +147,9 @@ export function TopologyTab(props: Props) { ? <TopologyToolbar onClickAddRoute={props.onClickAddRoute} onClickAddBean={props.onClickAddBean} onClickAddKamelet={props.onClickAddKamelet} - onClickAddREST={props.onClickAddREST}/> + onClickAddREST={props.onClickAddREST} + isDev={props.isDev} + /> : undefined} sideBar={<TopologyPropertiesPanel onSetFile={props.onSetFile}/>} controlBar={ diff --git a/karavan-space/src/topology/TopologyToolbar.tsx b/karavan-space/src/topology/TopologyToolbar.tsx index 0b23c542..2ac6eda9 100644 --- a/karavan-space/src/topology/TopologyToolbar.tsx +++ b/karavan-space/src/topology/TopologyToolbar.tsx @@ -24,17 +24,20 @@ import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon"; import {useTopologyStore} from "./TopologyStore"; import {shallow} from "zustand/shallow"; + interface Props { onClickAddRoute: () => void onClickAddREST: () => void onClickAddKamelet: () => void onClickAddBean: () => void + isDev?: boolean } export function TopologyToolbar (props: Props) { const [showGroups, setShowGroups] = useTopologyStore((s) => [s.showGroups, s.setShowGroups], shallow); + const isDev = props.isDev return ( <div className='topology-toolbar'> @@ -52,6 +55,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Integration Route"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"primary"} icon={<PlusIcon/>} onClick={e => props.onClickAddRoute()} @@ -63,6 +67,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add REST API"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddREST()} @@ -74,6 +79,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Kamelet"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddKamelet()} @@ -85,6 +91,7 @@ export function TopologyToolbar (props: Props) { <ToolbarItem align={{default:"alignRight"}}> <Tooltip content={"Add Bean"} position={"bottom"}> <Button className="dev-action-button" size="sm" + isDisabled={!isDev} variant={"secondary"} icon={<PlusIcon/>} onClick={e => props.onClickAddBean()} diff --git a/karavan-space/src/topology/topology.css b/karavan-space/src/topology/topology.css index 1828bd1e..6edc633d 100644 --- a/karavan-space/src/topology/topology.css +++ b/karavan-space/src/topology/topology.css @@ -115,4 +115,8 @@ .karavan .topology-panel .auto-start .text { fill: var(--pf-topology__node__label__text--Fill); +} + +.karavan .topology-group .pf-topology__group__label { + display: none; } \ No newline at end of file