Skip to content

Commit

Permalink
feat(core): added ability to turn channels on/off (#986)
Browse files Browse the repository at this point in the history
* feat(core): added ability to turn channels on/off

* Create rotten-numbers-admire.md

* feat(core): added ability to turn channels on/off

* feat(core): added ability to turn channels on/off
  • Loading branch information
boyney123 authored Dec 3, 2024
1 parent 8e95677 commit 920be57
Show file tree
Hide file tree
Showing 7 changed files with 189 additions and 74 deletions.
5 changes: 5 additions & 0 deletions .changeset/rotten-numbers-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@eventcatalog/core": patch
---

feat(core): added ability to turn channels on/off
65 changes: 27 additions & 38 deletions eventcatalog/src/components/MDX/NodeGraph/NodeGraph.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,6 @@ import ReactFlow, {
type Edge,
type Node,
useReactFlow,
getBezierPath,
BaseEdge,
SmoothStepEdge,
} from 'reactflow';
import 'reactflow/dist/style.css';

Expand All @@ -34,7 +31,7 @@ import DownloadButton from './DownloadButton';
import { buildUrl } from '@utils/url-builder';
import ChannelNode from './Nodes/Channel';
import { CogIcon } from '@heroicons/react/20/solid';

import { useEventCatalogVisualiser } from 'src/hooks/eventcatalog-visualizer';
interface Props {
nodes: any;
edges: any;
Expand Down Expand Up @@ -85,7 +82,7 @@ const NodeGraphBuilder = ({
const [isSettingsOpen, setIsSettingsOpen] = useState(false);
const [isAnimated, setIsAnimated] = useState(false);
const [animateMessages, setAnimateMessages] = useState(false);

const { hideChannels, toggleChannelsVisibility } = useEventCatalogVisualiser({ nodes, edges, setNodes, setEdges });
const { fitView } = useReactFlow();

const resetNodesAndEdges = useCallback(() => {
Expand Down Expand Up @@ -162,16 +159,6 @@ const NodeGraphBuilder = ({
[nodes, edges, setNodes, setEdges, resetNodesAndEdges, fitView]
);

const toggleAnimation = () => {
setIsAnimated(!isAnimated);
setEdges((eds) =>
eds.map((edge) => ({
...edge,
animated: !isAnimated,
}))
);
};

const toggleAnimateMessages = () => {
setAnimateMessages(!animateMessages);
localStorage.setItem('EventCatalog:animateMessages', JSON.stringify(!animateMessages));
Expand All @@ -196,6 +183,10 @@ const NodeGraphBuilder = ({
);
}, [animateMessages]);

useEffect(() => {
fitView({ duration: 800 });
}, [nodes, edges]);

const handlePaneClick = useCallback(() => {
setIsSettingsOpen(false);
resetNodesAndEdges();
Expand Down Expand Up @@ -319,6 +310,27 @@ const NodeGraphBuilder = ({
</div>
<p className="text-[10px] text-gray-500">Animate events, queries and commands.</p>
</div>
<div>
<div className="flex items-center justify-between">
<label htmlFor="message-animation-toggle" className="text-sm font-medium text-gray-700">
Hide Channels
</label>
<button
id="message-animation-toggle"
onClick={toggleChannelsVisibility}
className={`${
hideChannels ? 'bg-purple-600' : 'bg-gray-200'
} relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-purple-500 focus:ring-offset-2`}
>
<span
className={`${
hideChannels ? 'translate-x-6' : 'translate-x-1'
} inline-block h-4 w-4 transform rounded-full bg-white transition-transform`}
/>
</button>
</div>
<p className="text-[10px] text-gray-500">Show or hide channels in the visualizer.</p>
</div>
</div>
</div>
)}
Expand All @@ -341,29 +353,6 @@ const NodeGraphBuilder = ({
</li>
))}
</ul>
{/* <span className="font-bold">Key</span> */}
{/* <ul className="m-0 p-0">
<li className="flex space-x-2 items-center text-[10px]">
<span className="w-2 h-2 bg-orange-500 block" />
<span className="block">Events</span>
</li>
<li className="flex space-x-2 items-center text-[10px]">
<span className="w-2 h-2 bg-pink-500 block" />
<span className="block">Service</span>
</li>
<li className="flex space-x-2 items-center text-[10px]">
<span className="w-2 h-2 bg-blue-500 block" />
<span className="block">Command</span>
</li>
<li className="flex space-x-2 items-center text-[10px]">
<span className="w-2 h-2 bg-green-500 block" />
<span className="block">Query</span>
</li>
<li className="flex space-x-2 items-center text-[10px]">
<span className="w-2 h-2 bg-gray-500 block" />
<span className="block">Channel</span>
</li>
</ul> */}
</div>
</Panel>
)}
Expand Down
89 changes: 89 additions & 0 deletions eventcatalog/src/hooks/eventcatalog-visualizer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import { useCallback, useMemo, useState, useEffect } from 'react';
import { type Edge, type Node } from 'reactflow';
import {
createEdge,
generatedIdForEdge,
generateIdForNode,
getEdgeLabelForMessageAsSource,
getEdgeLabelForServiceAsTarget,
getNodesAndEdgesFromDagre,
} from '@utils/node-graphs/utils/utils';

interface EventCatalogVisualizerProps {
nodes: Node[];
edges: Edge[];
setNodes: (nodes: Node[]) => void;
setEdges: (edges: Edge[]) => void;
}

export const useEventCatalogVisualiser = ({ nodes, edges, setNodes, setEdges }: EventCatalogVisualizerProps) => {
const [hideChannels, setHideChannels] = useState(false);
const [initialNodes] = useState(nodes);
const [initialEdges] = useState(edges);

// Initialize hideChannels from localStorage
useEffect(() => {
const storedHideChannels = localStorage.getItem('EventCatalog:hideChannels');
if (storedHideChannels !== null) {
setHideChannels(storedHideChannels === 'true');
}
}, []);

const toggleChannelsVisibility = useCallback(() => {
setHideChannels((prev) => {
const newValue = !prev;
localStorage.setItem('EventCatalog:hideChannels', JSON.stringify(newValue));
return newValue;
});
}, []);

const channels = useMemo(() => nodes.filter((node) => node.type === 'channels'), [nodes]);
const updatedNodes = useMemo(() => nodes.filter((node) => node.type !== 'channels'), [nodes]);

const updatedEdges = useMemo(() => {
return edges.reduce<Edge[]>((acc, edge) => {
const { source, target, data } = edge;
const targetIsChannel = channels.some((channel) => channel.id === target);
const sourceIsChannel = channels.some((channel) => channel.id === source);

if (!sourceIsChannel && !targetIsChannel) {
return [...acc, edge];
}

if (sourceIsChannel) {
const edgeLabel =
data.target.collection === 'services'
? getEdgeLabelForMessageAsSource(data.source)
: getEdgeLabelForServiceAsTarget(data.target);

return [
...acc,
createEdge({
id: generatedIdForEdge(data.source, data.target),
source: generateIdForNode(data.source),
target: generateIdForNode(data.target),
label: edgeLabel,
}),
];
}

return [...acc, edge];
}, []);
}, [edges, channels]);

useEffect(() => {
if (hideChannels) {
const { nodes: newNodes, edges: newEdges } = getNodesAndEdgesFromDagre({ nodes: updatedNodes, edges: updatedEdges });
setNodes(newNodes);
setEdges(newEdges);
} else {
setNodes(initialNodes);
setEdges(initialEdges);
}
}, [hideChannels]);

return {
hideChannels,
toggleChannelsVisibility,
};
};
4 changes: 2 additions & 2 deletions eventcatalog/src/utils/__tests__/events/node-graph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ describe('Events NodeGraph', () => {
id: 'NotificationsService-0.0.1-EmailChannel-1.0.0-EmailVerified-1.0.0',
source: 'NotificationsService-0.0.1',
target: 'NotificationsService-0.0.1-EmailChannel-1.0.0-EmailVerified-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
{
label: 'publishes event',
Expand All @@ -289,7 +289,7 @@ describe('Events NodeGraph', () => {
id: 'EmailChannel-1.0.0-EmailVerified-1.0.0-NotificationsService-0.0.1',
source: 'NotificationsService-0.0.1-EmailChannel-1.0.0-EmailVerified-1.0.0',
target: 'EmailVerified-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
]);
});
Expand Down
8 changes: 4 additions & 4 deletions eventcatalog/src/utils/__tests__/services/node-graph.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ describe('Services NodeGraph', () => {
id: 'OrderDeletedEvent-2.0.0-OrderChannel-1.0.0-PaymentService-1.0.0',
source: 'OrderDeletedEvent-2.0.0',
target: 'OrderDeletedEvent-2.0.0-OrderChannel-1.0.0-PaymentService-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
{
label: 'receives event',
Expand All @@ -388,7 +388,7 @@ describe('Services NodeGraph', () => {
id: 'OrderChannel-1.0.0-PaymentService-1.0.0-OrderDeletedEvent-2.0.0',
source: 'OrderDeletedEvent-2.0.0-OrderChannel-1.0.0-PaymentService-1.0.0',
target: 'PaymentService-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
{
label: 'publishes event',
Expand Down Expand Up @@ -418,7 +418,7 @@ describe('Services NodeGraph', () => {
id: 'PaymentService-1.0.0-EmailChannel-1.0.0-EmailVerified-1.0.0',
source: 'PaymentService-1.0.0',
target: 'PaymentService-1.0.0-EmailChannel-1.0.0-EmailVerified-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
{
label: 'publishes event',
Expand All @@ -428,7 +428,7 @@ describe('Services NodeGraph', () => {
id: 'EmailChannel-1.0.0-EmailVerified-1.0.0-PaymentService-1.0.0',
source: 'PaymentService-1.0.0-EmailChannel-1.0.0-EmailVerified-1.0.0',
target: 'EmailVerified-1.0.0',
data: { message: expect.anything() },
data: { message: expect.anything(), source: expect.anything(), target: expect.anything(), channel: expect.anything() },
},
]);
});
Expand Down
29 changes: 2 additions & 27 deletions eventcatalog/src/utils/node-graphs/message-node-graph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import {
generatedIdForEdge,
generateIdForNode,
getChannelNodesAndEdges,
getEdgeLabelForMessageAsSource,
getEdgeLabelForServiceAsTarget,
} from './utils/utils';
import { MarkerType } from 'reactflow';
import { findMatchingNodes } from '@utils/collections/util';
Expand All @@ -26,33 +28,6 @@ interface Props {
collection?: CollectionEntry<CollectionMessageTypes>[];
}

const getEdgeLabelForServiceAsTarget = (data: CollectionEntry<CollectionMessageTypes>) => {
const type = data.collection;
switch (type) {
case 'commands':
return 'invokes';
case 'events':
return 'publishes event';
case 'queries':
return 'requests';
default:
return 'sends to';
}
};
const getEdgeLabelForMessageAsSource = (data: CollectionEntry<CollectionMessageTypes>) => {
const type = data.collection;
switch (type) {
case 'commands':
return 'accepts';
case 'events':
return 'subscribed by';
case 'queries':
return 'accepts';
default:
return 'sends to';
}
};

const getNodesAndEdges = async ({ id, version, defaultFlow, mode = 'simple', collection = [] }: Props) => {
const flow = defaultFlow || createDagreGraph({ ranksep: 300, nodesep: 50 });
const nodes = [] as any,
Expand Down
Loading

0 comments on commit 920be57

Please sign in to comment.