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 64470747 Fix #1309
64470747 is described below

commit 64470747568c1ee4e87a15c81b9979b0be6220ee
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Mon Jun 3 17:29:11 2024 -0400

    Fix #1309
---
 .../src/main/webui/src/editor/DesignerEditor.tsx   |  2 +-
 .../apache/camel/karavan/project/CodeService.java  |  5 +-
 karavan-vscode/src/utils.ts                        |  2 +-
 karavan-vscode/webview/topology/CustomNode.tsx     |  2 +-
 karavan-vscode/webview/topology/TopologyApi.tsx    | 84 +++++++++++++++++-----
 .../webview/topology/TopologyPropertiesPanel.tsx   | 21 +++++-
 karavan-vscode/webview/topology/TopologyStore.ts   | 15 ++--
 karavan-vscode/webview/topology/TopologyTab.tsx    | 14 ++--
 .../webview/topology/TopologyToolbar.tsx           | 22 +++++-
 karavan-vscode/webview/topology/topology.css       | 17 ++++-
 10 files changed, 141 insertions(+), 43 deletions(-)

diff --git a/karavan-app/src/main/webui/src/editor/DesignerEditor.tsx 
b/karavan-app/src/main/webui/src/editor/DesignerEditor.tsx
index 104321e6..cb182328 100644
--- a/karavan-app/src/main/webui/src/editor/DesignerEditor.tsx
+++ b/karavan-app/src/main/webui/src/editor/DesignerEditor.tsx
@@ -99,7 +99,7 @@ export function DesignerEditor(props: Props) {
                 }
             }
         } else {
-            const nodes = TopologyUtils.findTopologyOutgoingNodes(integrations)
+            const nodes = 
TopologyUtils.findTopologyRouteOutgoingNodes(integrations)
                 .filter(t => t.routeId === routeId);
             for (const node of nodes) {
                 const switchToFile = files.filter(f => f.name === 
node.fileName).at(0);
diff --git 
a/karavan-projects/src/main/java/org/apache/camel/karavan/project/CodeService.java
 
b/karavan-projects/src/main/java/org/apache/camel/karavan/project/CodeService.java
index b17ddd91..7ae0d662 100644
--- 
a/karavan-projects/src/main/java/org/apache/camel/karavan/project/CodeService.java
+++ 
b/karavan-projects/src/main/java/org/apache/camel/karavan/project/CodeService.java
@@ -173,10 +173,11 @@ public class CodeService {
 //                result.put(APPLICATION_PROPERTIES_FILENAME, 
getResourceFile(TEMPLATES_PATH + "openshift-" + 
APPLICATION_PROPERTIES_FILENAME));
 //                result.put(BUILD_SCRIPT_FILENAME, 
getResourceFile(TEMPLATES_PATH + "openshift-" + BUILD_SCRIPT_FILENAME));
 //            } else {
-                result.put(APPLICATION_PROPERTIES_FILENAME, 
getResourceFile(TEMPLATES_PATH + "kubernetes-" + 
APPLICATION_PROPERTIES_FILENAME));
-                result.put(BUILD_SCRIPT_FILENAME, 
getResourceFile(TEMPLATES_PATH + "kubernetes-" + BUILD_SCRIPT_FILENAME));
+            result.put(APPLICATION_PROPERTIES_FILENAME, 
getResourceFile(TEMPLATES_PATH + "kubernetes-" + 
APPLICATION_PROPERTIES_FILENAME));
+            result.put(BUILD_SCRIPT_FILENAME, getResourceFile(TEMPLATES_PATH + 
"kubernetes-" + BUILD_SCRIPT_FILENAME));
 //            }
             result.put(BUILDER_ENV_MAPPING_FILENAME, 
getResourceFile(TEMPLATES_PATH + BUILDER_ENV_MAPPING_FILENAME));
+            result.put(PROJECT_DEPLOYMENT_JKUBE_FILENAME, 
getResourceFile(TEMPLATES_PATH + PROJECT_DEPLOYMENT_JKUBE_FILENAME));
         } else {
             result.put(APPLICATION_PROPERTIES_FILENAME, 
getResourceFile(TEMPLATES_PATH + "docker-" + APPLICATION_PROPERTIES_FILENAME));
             result.put(BUILD_SCRIPT_FILENAME, getResourceFile(TEMPLATES_PATH + 
"docker-" + BUILD_SCRIPT_FILENAME));
diff --git a/karavan-vscode/src/utils.ts b/karavan-vscode/src/utils.ts
index 2cb0b402..f6eeac96 100644
--- a/karavan-vscode/src/utils.ts
+++ b/karavan-vscode/src/utils.ts
@@ -512,7 +512,7 @@ export async function getFileWithIntegnalConsumer(fullPath: 
string, uri: string,
 export async function getFileWithInternalProducer(fullPath: string, routeId: 
string) {
     try {
         const integrations = await getIntegrations(path.dirname(fullPath))
-        const route = TopologyUtils.findTopologyOutgoingNodes(integrations)
+        const route = 
TopologyUtils.findTopologyRouteOutgoingNodes(integrations)
                 .filter(t => t.routeId === routeId).at(0);
         if (route) {
             return path.join(path.dirname(fullPath), route.fileName);
diff --git a/karavan-vscode/webview/topology/CustomNode.tsx 
b/karavan-vscode/webview/topology/CustomNode.tsx
index d683d04f..88263966 100644
--- a/karavan-vscode/webview/topology/CustomNode.tsx
+++ b/karavan-vscode/webview/topology/CustomNode.tsx
@@ -24,7 +24,7 @@ import {CamelUi} from "../designer/utils/CamelUi";
 import './topology.css';
 
 function getIcon(data: any) {
-    if (['route', 'rest'].includes(data.icon)) {
+    if (['route', 'rest', 'routeConfiguration'].includes(data.icon)) {
         return (
             <g transform={`translate(14, 14)`}>
                 {getDesignerIcon(data.icon)}
diff --git a/karavan-vscode/webview/topology/TopologyApi.tsx 
b/karavan-vscode/webview/topology/TopologyApi.tsx
index a00ac286..90302a02 100644
--- a/karavan-vscode/webview/topology/TopologyApi.tsx
+++ b/karavan-vscode/webview/topology/TopologyApi.tsx
@@ -26,20 +26,21 @@ import {
     NodeModel,
     NodeShape,
     NodeStatus,
-    withPanZoom, withSelection
+    withPanZoom,
+    withSelection
 } from '@patternfly/react-topology';
 import CustomNode from "./CustomNode";
-import {Integration} from "core/model/IntegrationDefinition";
+import {Integration, IntegrationFile} from "core/model/IntegrationDefinition";
 import {CamelDefinitionYaml} from "core/api/CamelDefinitionYaml";
 import {TopologyUtils} from "core/api/TopologyUtils";
 import {
     TopologyIncomingNode,
     TopologyOutgoingNode,
     TopologyRestNode,
+    TopologyRouteConfigurationNode,
     TopologyRouteNode
 } from "core/model/TopologyDefinition";
 import CustomEdge from "./CustomEdge";
-import {IntegrationFile} from "core/model/IntegrationDefinition";
 import CustomGroup from "./CustomGroup";
 
 const NODE_DIAMETER = 60;
@@ -94,6 +95,28 @@ export function getRoutes(tins: TopologyRouteNode[]): 
NodeModel[] {
         return node;
     });
 }
+export function getRouteConfigurations(trcs: 
TopologyRouteConfigurationNode[]): NodeModel[] {
+    return trcs.map(tin => {
+        const node: NodeModel = {
+            id: tin.id,
+            type: 'node',
+            label: tin.title,
+            width: NODE_DIAMETER,
+            height: NODE_DIAMETER,
+            shape: NodeShape.rect,
+            status: NodeStatus.default,
+            data: {
+                isAlternate: false,
+                type: 'routeConfiguration',
+                icon: 'routeConfiguration',
+                step: tin.routeConfiguration,
+                routeConfigurationId: tin.routeConfigurationId,
+                fileName: tin.fileName,
+            }
+        }
+        return node;
+    });
+}
 
 export function getOutgoingNodes(tons: TopologyOutgoingNode[]): NodeModel[] {
     return tons.filter(tin => tin.type === 'external').map(tin => {
@@ -227,41 +250,64 @@ export function getInternalEdges(tons: 
TopologyOutgoingNode[], tins: TopologyInc
     return result;
 }
 
-export function getModel(files: IntegrationFile[]): Model {
+export function getModel(files: IntegrationFile[], grouping?: boolean): Model {
     const integrations = getIntegrations(files);
     const tins = TopologyUtils.findTopologyIncomingNodes(integrations);
     const troutes = TopologyUtils.findTopologyRouteNodes(integrations);
-    const tons = TopologyUtils.findTopologyOutgoingNodes(integrations);
+    const tons = TopologyUtils.findTopologyRouteOutgoingNodes(integrations);
     const trestns = TopologyUtils.findTopologyRestNodes(integrations);
 
+    const trcs = 
TopologyUtils.findTopologyRouteConfigurationNodes(integrations);
+    const trcons = 
TopologyUtils.findTopologyRouteConfigurationOutgoingNodes(integrations);
+
     const nodes: NodeModel[] = [];
-    const groups: NodeModel[] = troutes.map(r => {
-        const children = [r.id]
-        children.push(...tins.filter(i => i.routeId === r.routeId && i.type 
=== 'external').map(i => i.id));
-        children.push(...tons.filter(i => i.routeId === r.routeId && i.type 
=== 'external').map(i => i.id));
-        return   {
-            id: 'group-' + r.routeId,
-            children: children,
-            type: 'group',
-            group: true,
-            label: r.title,
-            style: {
-                padding: 40
-            }
+    const groups: NodeModel[] = [];
+
+    const children1 = []
+    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: 10,
+            strokeWidth: "2px",
+        }
+    })
+
+    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: 10,
+            strokeWidth: "2px"
         }
     })
 
     nodes.push(...getRestNodes(trestns))
     nodes.push(...getIncomingNodes(tins))
     nodes.push(...getRoutes(troutes))
+    nodes.push(...getRouteConfigurations(trcs))
     nodes.push(...getOutgoingNodes(tons))
-    // nodes.push(...groups)
+    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));
 
     return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', 
layout: 'Dagre'}};
diff --git a/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx 
b/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx
index 27ef71b5..a32d6969 100644
--- a/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx
+++ b/karavan-vscode/webview/topology/TopologyPropertiesPanel.tsx
@@ -48,6 +48,14 @@ export function TopologyPropertiesPanel(props: Props) {
         return false;
     }
 
+    function isRouteConfiguration() {
+        return (nodeData && nodeData.type === 'routeConfiguration');
+    }
+
+    function isRest() {
+        return (nodeData && nodeData.type === 'rest');
+    }
+
     function isKamelet() {
         if (nodeData && nodeData.type === 'step') {
             const uri: string = nodeData?.step?.uri || '';
@@ -70,7 +78,16 @@ export function TopologyPropertiesPanel(props: Props) {
     }
 
     function getTitle () {
-        return isRoute() ? "Route" : (isKamelet() ? "Kamelet" : "Component");
+        if (isRoute()) {
+            return "Route";
+        } else if (isKamelet()) {
+            return "Kamelet";
+        } else if (isRouteConfiguration()) {
+            return "Route Configuration";
+        } else if (isRest()) {
+            return "REST";
+        }
+        return "Component";
     }
 
     function getHeader() {
@@ -118,7 +135,7 @@ export function TopologyPropertiesPanel(props: Props) {
     return (
         <TopologySideBar
             className="topology-sidebar"
-            show={selectedIds.length > 0}
+            show={selectedIds.length > 0 && nodeData}
             header={getHeader()}
         >
             <DslProperties designerType={'routes'}/>
diff --git a/karavan-vscode/webview/topology/TopologyStore.ts 
b/karavan-vscode/webview/topology/TopologyStore.ts
index 517e2794..514f1b37 100644
--- a/karavan-vscode/webview/topology/TopologyStore.ts
+++ b/karavan-vscode/webview/topology/TopologyStore.ts
@@ -28,6 +28,8 @@ interface TopologyState {
     setRanker: (ranker: string) => void
     nodeData: any
     setNodeData: (nodeData: any) => void
+    showGroups?: boolean
+    setShowGroups: (showGroups: boolean) => void
 }
 
 export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({
@@ -50,8 +52,13 @@ export const useTopologyStore = 
createWithEqualityFn<TopologyState>((set) => ({
     },
     nodeData: undefined,
     setNodeData: (nodeData: any) => {
-    set((state: TopologyState) => {
-        return {nodeData: nodeData};
-    });
-},
+        set((state: TopologyState) => {
+            return {nodeData: nodeData};
+        });
+    },
+    setShowGroups: (showGroups: boolean) => {
+        set((state: TopologyState) => {
+            return {showGroups: showGroups};
+        });
+    },
 }), shallow)
diff --git a/karavan-vscode/webview/topology/TopologyTab.tsx 
b/karavan-vscode/webview/topology/TopologyTab.tsx
index 474899fc..51f5d24e 100644
--- a/karavan-vscode/webview/topology/TopologyTab.tsx
+++ b/karavan-vscode/webview/topology/TopologyTab.tsx
@@ -49,8 +49,8 @@ interface Props {
 
 export function TopologyTab(props: Props) {
 
-    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, 
setNodeData] = useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker, s.setNodeData], shallow);
+    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, 
setNodeData, showGroups] = useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker, s.setNodeData, s.showGroups], shallow);
     const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], 
shallow)
 
     function setTopologySelected(model: Model, ids: string []) {
@@ -60,8 +60,8 @@ export function TopologyTab(props: Props) {
             if (node && node.length > 0) {
                 const data = node[0].data;
                 setNodeData(data);
-                setFileName(data.fileName)
-                if (data.step) {
+                if (data && data.step) {
+                    setFileName(data.fileName)
                     setSelectedStep(data.step)
                 } else {
                     setSelectedStep(undefined);
@@ -72,7 +72,7 @@ export function TopologyTab(props: Props) {
     }
 
     const controller = React.useMemo(() => {
-        const model = getModel(props.files);
+        const model = getModel(props.files, showGroups);
         const newController = new Visualization();
         newController.registerLayoutFactory((_, graph) =>
             new DagreLayout(graph, {
@@ -99,9 +99,9 @@ export function TopologyTab(props: Props) {
 
     React.useEffect(() => {
         setSelectedIds([])
-        const model = getModel(props.files);
+        const model = getModel(props.files, showGroups);
         controller.fromModel(model, false);
-    }, [ranker, controller, setSelectedIds, props.files]);
+    }, [ranker, controller, setSelectedIds, props.files, showGroups]);
 
     const controlButtons = React.useMemo(() => {
         // const customButtons = [
diff --git a/karavan-vscode/webview/topology/TopologyToolbar.tsx 
b/karavan-vscode/webview/topology/TopologyToolbar.tsx
index 5dbe4949..0de61fee 100644
--- a/karavan-vscode/webview/topology/TopologyToolbar.tsx
+++ b/karavan-vscode/webview/topology/TopologyToolbar.tsx
@@ -17,10 +17,12 @@
 
 import * as React from 'react';
 import {
-    Button, ToolbarContent,
+    Button, Switch, ToolbarContent,
     ToolbarItem, Tooltip
 } from '@patternfly/react-core';
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {useTopologyStore} from "./TopologyStore";
+import {shallow} from "zustand/shallow";
 
 interface Props {
     onClickAddRoute: () => void
@@ -31,8 +33,22 @@ interface Props {
 
 export function TopologyToolbar (props: Props) {
 
+    const [showGroups, setShowGroups] = useTopologyStore((s) =>
+        [s.showGroups, s.setShowGroups], shallow);
+
     return (
-        <ToolbarContent>
+        <div className='topology-toolbar'>
+            <ToolbarItem className="group-switch">
+                <Tooltip content={"Show Consumer and Producer Groups"} 
position={"bottom-start"}>
+                    <Switch
+                        id="reversed-switch"
+                        label="Groups"
+                        isChecked={showGroups}
+                        onChange={(_, checked) => setShowGroups(checked)}
+                        isReversed
+                    />
+                </Tooltip>
+            </ToolbarItem>
             <ToolbarItem align={{default:"alignRight"}}>
                 <Tooltip content={"Add Integration Route"} position={"bottom"}>
                     <Button className="dev-action-button" size="sm"
@@ -77,6 +93,6 @@ export function TopologyToolbar (props: Props) {
                     </Button>
                 </Tooltip>
             </ToolbarItem>
-        </ToolbarContent>
+        </div>
     )
 }
\ No newline at end of file
diff --git a/karavan-vscode/webview/topology/topology.css 
b/karavan-vscode/webview/topology/topology.css
index 24fe7679..7d21c7b2 100644
--- a/karavan-vscode/webview/topology/topology.css
+++ b/karavan-vscode/webview/topology/topology.css
@@ -15,17 +15,28 @@
  * limitations under the License.
  */
 
+.karavan .topology-panel .topology-toolbar {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+}
+
+.karavan .topology-panel .topology-toolbar .group-switch {
+    flex-grow: 4;
+    margin-top: auto;
+    margin-bottom: auto;
+    margin-left: 6px;
+}
+
 .karavan .topology-panel .pf-v5-c-toolbar {
     padding: 0;
-    display: flex;
-    flex-direction: column;
-    align-items: flex-end;
     height: fit-content;
     row-gap: 0;
 }
 
 .karavan .topology-panel .pf-v5-c-toolbar .pf-v5-c-toolbar__content {
     padding: 0 6px 0 0;
+    width: 100%;
 }
 
 .karavan .topology-panel .pf-v5-c-toolbar .pf-v5-c-toolbar__content-section {

Reply via email to