Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,14 @@ export function ConnectionNodeWidget(props: ConnectionNodeWidgetProps) {
setMenuAnchorEl(null);
};

const handleMenuMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};

const handleMenuMouseUp = (event: React.MouseEvent) => {
event.stopPropagation();
};

const getNodeTitle = () => {
return model.node.symbol;
};
Expand Down Expand Up @@ -199,7 +207,12 @@ export function ConnectionNodeWidget(props: ConnectionNodeWidgetProps) {
<Title hovered={isHovered}>{getNodeTitle()}</Title>
<Description>{getNodeDescription()}</Description>
</Header>
<MenuButton appearance="icon" onClick={handleOnMenuClick}>
<MenuButton
appearance="icon"
onClick={handleOnMenuClick}
onMouseDown={handleMenuMouseDown}
onMouseUp={handleMenuMouseUp}
>
<MoreVertIcon />
</MenuButton>
</ClickableArea>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ export function AIServiceWidget({ model, engine }: BaseNodeWidgetProps) {
setMenuAnchorEl(null);
};

const handleMenuMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};

const handleMenuMouseUp = (event: React.MouseEvent) => {
event.stopPropagation();
};

const menuItems: Item[] = [
{ id: "edit", label: "Edit", onClick: () => handleOnClick() },
{ id: "delete", label: "Delete", onClick: () => onDeleteComponent(model.node) },
Expand All @@ -101,7 +109,12 @@ export function AIServiceWidget({ model, engine }: BaseNodeWidgetProps) {
<Title hovered={isHovered}>{getNodeTitle(model)}</Title>
<Description>{getNodeDescription(model)}</Description>
</Header>
<MenuButton appearance="icon" onClick={handleOnMenuClick}>
<MenuButton
appearance="icon"
onClick={handleOnMenuClick}
onMouseDown={handleMenuMouseDown}
onMouseUp={handleMenuMouseUp}
>
<MoreVertIcon />
</MenuButton>
</ServiceBox>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,14 @@ export function GeneralServiceWidget({ model, engine }: BaseNodeWidgetProps) {
setMenuAnchorEl(null);
};

const handleMenuMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};

const handleMenuMouseUp = (event: React.MouseEvent) => {
event.stopPropagation();
};

const menuItems: Item[] = [
{ id: "edit", label: "Edit", onClick: () => handleOnClick() },
{ id: "delete", label: "Delete", onClick: () => onDeleteComponent(model.node) },
Expand Down Expand Up @@ -251,7 +259,12 @@ export function GeneralServiceWidget({ model, engine }: BaseNodeWidgetProps) {
<Title hovered={isHovered}>{getNodeTitle(model)}</Title>
<Description>{getNodeDescription(model)}</Description>
</Header>
<MenuButton appearance="icon" onClick={handleOnMenuClick}>
<MenuButton
appearance="icon"
onClick={handleOnMenuClick}
onMouseDown={handleMenuMouseDown}
onMouseUp={handleMenuMouseUp}
>
<MoreVertIcon />
</MenuButton>
</ServiceBox>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,14 @@ export function GraphQLServiceWidget({ model, engine }: BaseNodeWidgetProps) {
setMenuAnchorEl(null);
};

const handleMenuMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};

const handleMenuMouseUp = (event: React.MouseEvent) => {
event.stopPropagation();
};

const menuItems: Item[] = [
{ id: "edit", label: "Edit", onClick: () => handleOnClick() },
{ id: "delete", label: "Delete", onClick: () => onDeleteComponent(model.node) },
Expand Down Expand Up @@ -245,7 +253,12 @@ export function GraphQLServiceWidget({ model, engine }: BaseNodeWidgetProps) {
<Title hovered={isHovered}>{getNodeTitle(model)}</Title>
<Description>{getNodeDescription(model)}</Description>
</Header>
<MenuButton appearance="icon" onClick={handleOnMenuClick}>
<MenuButton
appearance="icon"
onClick={handleOnMenuClick}
onMouseDown={handleMenuMouseDown}
onMouseUp={handleMenuMouseUp}
>
<MoreVertIcon />
</MenuButton>
</ServiceBox>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,14 @@ export function ListenerNodeWidget(props: ListenerNodeWidgetProps) {
setMenuAnchorEl(null);
};

const handleMenuMouseDown = (event: React.MouseEvent) => {
event.stopPropagation();
};

const handleMenuMouseUp = (event: React.MouseEvent) => {
event.stopPropagation();
};

const menuItems: Item[] = [
{ id: "edit", label: "Edit", onClick: () => handleOnClick() },

Expand All @@ -196,7 +204,12 @@ export function ListenerNodeWidget(props: ListenerNodeWidgetProps) {

<RightPortWidget port={model.getPort("out")!} engine={engine} />
</Circle>
<MenuButton appearance="icon" onClick={handleOnMenuClick}>
<MenuButton
appearance="icon"
onClick={handleOnMenuClick}
onMouseDown={handleMenuMouseDown}
onMouseUp={handleMenuMouseUp}
>
<MoreVertIcon />
</MenuButton>
<Header>
Expand Down
40 changes: 35 additions & 5 deletions workspaces/ballerina/component-diagram/src/utils/diagram.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import { NodeModel } from "./types";
import { EntryNodeFactory, EntryNodeModel } from "../components/nodes/EntryNode";
import { ConnectionNodeFactory } from "../components/nodes/ConnectionNode/ConnectionNodeFactory";
import { ListenerNodeFactory } from "../components/nodes/ListenerNode/ListenerNodeFactory";
import { LISTENER_NODE_WIDTH, NodeTypes, NODE_GAP_X, ENTRY_NODE_WIDTH } from "../resources/constants";
import { LISTENER_NODE_WIDTH, NodeTypes, NODE_GAP_X, ENTRY_NODE_WIDTH, NODE_GAP_Y, LISTENER_NODE_HEIGHT } from "../resources/constants";
import { ListenerNodeModel } from "../components/nodes/ListenerNode";
import { ConnectionNodeModel } from "../components/nodes/ConnectionNode";
import { CDConnection, CDResourceFunction, CDFunction, CDService } from "@wso2/ballerina-core";
Expand Down Expand Up @@ -64,16 +64,26 @@ export function autoDistribute(engine: DiagramEngine) {
const entryX = listenerX + LISTENER_NODE_WIDTH + NODE_GAP_X;
const connectionX = entryX + ENTRY_NODE_WIDTH + NODE_GAP_X;

// Position listeners while maintaining relative Y positions of their services
// Separate listeners into connected and unconnected
const connectedListeners: ListenerNodeModel[] = [];
const unconnectedListeners: ListenerNodeModel[] = [];

listenerNodes.forEach((node) => {
const listenerNode = node as ListenerNodeModel;
const attachedServices = listenerNode.node.attachedServices;

// Find the average Y position of attached services
// Find the attached service nodes
const serviceNodes = entryNodes.filter((n) => attachedServices.includes(n.getID()));
const avgY = serviceNodes.reduce((sum, n) => sum + n.getY(), 0) / serviceNodes.length;

listenerNode.setPosition(listenerX, avgY);
if (serviceNodes.length > 0) {
// Has attached services - position at average Y of services
const avgY = serviceNodes.reduce((sum, n) => sum + n.getY(), 0) / serviceNodes.length;
listenerNode.setPosition(listenerX, avgY);
connectedListeners.push(listenerNode);
} else {
// No attached services - will position later
unconnectedListeners.push(listenerNode);
}
});

// Update X positions for entry nodes while keeping their Y positions
Expand All @@ -88,6 +98,26 @@ export function autoDistribute(engine: DiagramEngine) {
connectionNode.setPosition(connectionX, node.getY());
});

// Position unconnected listeners below all other nodes
if (unconnectedListeners.length > 0) {
// Find the maximum Y position among all nodes
const allNodes = [...connectedListeners, ...entryNodes, ...connectionNodes];
let maxY = 100; // Default starting position if no other nodes

if (allNodes.length > 0) {
maxY = Math.max(...allNodes.map(node => {
const nodeHeight = node.height || LISTENER_NODE_HEIGHT;
return node.getY() + nodeHeight;
}));
}

// Position unconnected listeners below, with spacing
unconnectedListeners.forEach((listenerNode, index) => {
const yPosition = maxY + NODE_GAP_Y/2 + (index * (LISTENER_NODE_HEIGHT + NODE_GAP_Y/2));
listenerNode.setPosition(listenerX, yPosition);
});
}

engine.repaintCanvas();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ export interface ButtonProps {
sx?: React.CSSProperties;
buttonSx?: React.CSSProperties;
onClick?: (() => void) | ((event: React.MouseEvent<HTMLElement | SVGSVGElement>) => void);
onMouseDown?: (event: React.MouseEvent) => void;
onMouseUp?: (event: React.MouseEvent) => void;
}

export const IconLabel = styled.div`
Expand Down
Loading