diff --git a/pkgs/ui/src/components/sequence_diagram/helpers.ts b/pkgs/ui/src/components/sequence_diagram/helpers.ts
new file mode 100644
index 0000000..dcc513a
--- /dev/null
+++ b/pkgs/ui/src/components/sequence_diagram/helpers.ts
@@ -0,0 +1,133 @@
+export const generateMermaidString = (data: any) => {
+
+ if (!data || data.length === 0)
+ return '';
+
+ // Extract unique participants
+ const participants = Array.from(new Set(data.map((item: any) => item.src_did).concat(data.map((item: any) => item.des_did))));
+
+ // Begin the sequence diagram definition
+ let mermaidString = "sequenceDiagram\n";
+
+ // Add participants to the diagram
+ participants.forEach((participant, index) => {
+ mermaidString += ` participant ${String.fromCharCode(65 + index)} as ${participant}\n`;
+ });
+
+ // Add messages to the diagram
+ data.forEach((item: any, index: number) => {
+ const srcParticipant = String.fromCharCode(65 + participants.indexOf(item.src_did));
+ const desParticipant = String.fromCharCode(65 + participants.indexOf(item.des_did));
+ const timestamp = new Date(item.timestamp * 1000).toLocaleString(); // Convert Unix timestamp to readable date
+ const message = item.msg.text || `Event message ${index + 1}`;
+
+ // If group_name or group_id exists, start an 'alt' block
+ if (item.group_id != null) {
+ mermaidString += ` alt ${item.group_name || item.group_id}\n`;
+ mermaidString += ` rect rgb(191, 223, 255)\n`;
+ }
+
+ // Add the message interaction
+ mermaidString += ` ${srcParticipant}->>${desParticipant}: [${timestamp}] ${message}\n`;
+
+ // If there was an 'alt' block, close it
+ if (item.group_id != null) {
+ mermaidString += ` end\n`;
+ mermaidString += ` end\n`;
+ }
+ });
+
+ return mermaidString;
+};
+
+
+
+// Dummy Data
+
+export const dataFromBE = [
+ {
+ "id": 12,
+ "timestamp": 1704892813,
+ "group": 0,
+ "group_id": 12,
+ // "group_name": "Data",
+ "msg_type": 4,
+ "src_did": "did:sov:test:121",
+ // "src_name": "Entity A",
+ "des_did": "did:sov:test:120",
+ // "des_name": "Entity B",
+ "msg": {
+ text: 'Hello World'
+ }
+ },
+ {
+ "id": 60,
+ "timestamp": 1704892823,
+ "group": 1,
+ "group_id": 19,
+ "msg_type": 4,
+ "src_did": "did:sov:test:122",
+ "des_did": "did:sov:test:121",
+ "msg": {}
+ },
+ {
+ "id": 30162,
+ "timestamp": 1704892817,
+ "group": 1,
+ "group_id": 53,
+ "msg_type": 2,
+ "src_did": "did:sov:test:121",
+ "des_did": "did:sov:test:122",
+ "msg": {}
+ },
+ {
+ "id": 63043,
+ "timestamp": 1704892809,
+ "group": 0,
+ "group_id": 12,
+ "msg_type": 3,
+ "src_did": "did:sov:test:121",
+ "des_did": "did:sov:test:120",
+ "msg": {}
+ },
+ {
+ "id": 66251,
+ "timestamp": 1704892805,
+ "group": 0,
+ "group_id": 51,
+ "msg_type": 1,
+ "src_did": "did:sov:test:120",
+ "des_did": "did:sov:test:121",
+ "msg": {}
+ },
+ {
+ "id": 85434,
+ "timestamp": 1704892807,
+ "group": 0,
+ "group_id": 51,
+ "msg_type": 2,
+ "src_did": "did:sov:test:120",
+ "des_did": "did:sov:test:121",
+ "msg": {}
+ },
+ {
+ "id": 124842,
+ "timestamp": 1704892819,
+ "group": 1,
+ "group_id": 19,
+ "msg_type": 3,
+ "src_did": "did:sov:test:122",
+ "des_did": "did:sov:test:121",
+ "msg": {}
+ },
+ {
+ "id": 246326,
+ "timestamp": 1704892815,
+ "group": 1,
+ "group_id": 53,
+ "msg_type": 1,
+ "src_did": "did:sov:test:121",
+ "des_did": "did:sov:test:122",
+ "msg": {}
+ }
+]
\ No newline at end of file
diff --git a/pkgs/ui/src/components/sequence_diagram/index.tsx b/pkgs/ui/src/components/sequence_diagram/index.tsx
new file mode 100644
index 0000000..ab90d89
--- /dev/null
+++ b/pkgs/ui/src/components/sequence_diagram/index.tsx
@@ -0,0 +1,178 @@
+'use client';
+
+import { useRef, useEffect, useState } from 'react';
+import mermaid from 'mermaid';
+import { IconButton } from '@mui/material';
+import RefreshIcon from '@mui/icons-material/Refresh';
+import ZoomInIcon from '@mui/icons-material/ZoomIn';
+import ZoomOutIcon from '@mui/icons-material/ZoomOut';
+import FullscreenIcon from '@mui/icons-material/Fullscreen';
+import DownloadIcon from '@mui/icons-material/Download';
+import ResetIcon from '@mui/icons-material/Autorenew';
+import Tooltip from '@mui/material/Tooltip';
+import { NoDataOverlay } from '../noDataOverlay';
+import { useGetAllEventmessages } from '@/api/eventmessages/eventmessages';
+import { mutate } from 'swr';
+import { LoadingOverlay } from '../join/loadingOverlay';
+import { generateMermaidString, dataFromBE } from './helpers';
+
+const SequenceDiagram = () => {
+
+ const {
+ data: eventMessagesData,
+ isLoading: loadingEventMessages,
+ swrKey: eventMessagesKeyFunc,
+ } = useGetAllEventmessages();
+
+ const mermaidRef: any = useRef(null);
+ const [scale, setScale] = useState(1);
+ const hasData = eventMessagesData?.data && eventMessagesData?.data.length > 0;
+
+ const mermaidString = generateMermaidString(eventMessagesData?.data);
+
+ useEffect(() => {
+
+ if (!loadingEventMessages && hasData)
+ mermaid.initialize({
+ startOnLoad: false,
+ securityLevel: 'loose',
+ sequence: {
+ mirrorActors: false,
+ },
+ });
+
+ if (mermaidRef.current) {
+ mermaidRef.current.innerHTML = mermaidString;
+ mermaid.init(undefined, mermaidRef.current);
+ }
+ }, [loadingEventMessages, hasData, mermaidString]);
+
+ useEffect(() => {
+ if (mermaidRef.current) {
+ const svg = mermaidRef.current.querySelector('svg');
+ if (svg) {
+ svg.style.transform = `scale(${scale})`;
+ svg.style.transformOrigin = 'top left'; // Set transform origin to top left
+ mermaidRef.current.style.width = `${svg.getBoundingClientRect().width * scale}px`;
+ mermaidRef.current.style.height = `${svg.getBoundingClientRect().height * scale}px`;
+ }
+ }
+ }, [scale]);
+
+
+ const onRefresh = () => {
+ const eventMessagesKey =
+ typeof eventMessagesKeyFunc === "function"
+ ? eventMessagesKeyFunc()
+ : eventMessagesKeyFunc;
+
+ if (eventMessagesKey) {
+ mutate(eventMessagesKey);
+ }
+ };
+
+ const zoomIn = () => {
+ setScale((scale) => scale * 1.1);
+ };
+
+ const zoomOut = () => {
+ setScale((scale) => scale / 1.1);
+ };
+
+ const resetZoom = () => {
+ setScale(1);
+ };
+
+ const viewInFullScreen = () => {
+ if (mermaidRef.current) {
+ const svg = mermaidRef.current.querySelector('svg');
+ const serializer = new XMLSerializer();
+ const svgBlob = new Blob([serializer.serializeToString(svg)], {
+ type: 'image/svg+xml',
+ });
+ const url = URL.createObjectURL(svgBlob);
+ window.open(url, '_blank');
+ }
+ };
+
+ const downloadAsPng = () => {
+ if (mermaidRef.current) {
+ const svg = mermaidRef.current.querySelector('svg');
+ const svgData = new XMLSerializer().serializeToString(svg);
+
+ // Create a canvas element to convert SVG to PNG
+ const canvas = document.createElement('canvas');
+ const svgSize = svg.getBoundingClientRect();
+ canvas.width = svgSize.width;
+ canvas.height = svgSize.height;
+ const ctx = canvas.getContext('2d');
+ const img = document.createElement('img');
+
+ img.onload = () => {
+ ctx?.drawImage(img, 0, 0);
+ const pngData = canvas.toDataURL('image/png');
+
+ // Trigger download
+ const link = document.createElement('a');
+ link.download = 'sequence-diagram.png';
+ link.href = pngData;
+ link.click();
+ };
+
+ img.src =
+ 'data:image/svg+xml;base64,' +
+ btoa(unescape(encodeURIComponent(svgData)));
+ }
+ };
+
+ if (loadingEventMessages)
+ return
+
+ return (
+
+ {
+ hasData ? <>
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ > :
+
+
+ }
+
+ )
+}
+
+export default SequenceDiagram;
\ No newline at end of file
diff --git a/pkgs/ui/src/components/sequence_diagram/style.css b/pkgs/ui/src/components/sequence_diagram/style.css
new file mode 100644
index 0000000..d4d837e
--- /dev/null
+++ b/pkgs/ui/src/components/sequence_diagram/style.css
@@ -0,0 +1,21 @@
+.container {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-end;
+}
+
+.buttons-container {
+ display: flex;
+ justify-content: flex-end;
+ gap: 10px;
+ margin-bottom: 20px;
+}
+
+.diagram-container {
+ width: 100%;
+ height: 500px;
+ overflow: auto;
+ border: 1px solid #ddd;
+ padding: 10px;
+ box-sizing: border-box;
+}
diff --git a/pkgs/ui/src/components/table/index.tsx b/pkgs/ui/src/components/table/index.tsx
index 900b65c..b634040 100644
--- a/pkgs/ui/src/components/table/index.tsx
+++ b/pkgs/ui/src/components/table/index.tsx
@@ -44,8 +44,8 @@ const CustomTable = ({ configuration, data, loading, tkey }: ICustomTable) => {
};
return (
-
-
+
+
{configuration.map((header: CustomTableConfiguration) => (