From 98a745039eae11ebbbe8b4fa12755c06478a93eb Mon Sep 17 00:00:00 2001 From: ajvpot <553597+ajvpot@users.noreply.github.com> Date: Sat, 23 Aug 2025 03:43:20 +0200 Subject: [PATCH] fullscreen graph --- src/components/ChatMessageItem.tsx | 146 +++++++++++++++++++---------- 1 file changed, 99 insertions(+), 47 deletions(-) diff --git a/src/components/ChatMessageItem.tsx b/src/components/ChatMessageItem.tsx index ab8c8f9..ab68fc1 100644 --- a/src/components/ChatMessageItem.tsx +++ b/src/components/ChatMessageItem.tsx @@ -1,8 +1,10 @@ "use client"; import React, { useState, useEffect, useMemo, useCallback } from "react"; +import { createPortal } from "react-dom"; import { useConfig } from "./ConfigContext"; import { decryptMeshcoreGroupMessage } from "../lib/meshcore"; import Tree from 'react-d3-tree'; +import { ArrowsPointingOutIcon, ArrowsPointingInIcon } from "@heroicons/react/24/outline"; export interface ChatMessage { ingest_timestamp: string; @@ -25,6 +27,8 @@ interface PathGroup { interface TreeNode { name: string; children?: TreeNode[]; + attributes?: Record; + [key: string]: any; } function formatHex(hex: string): string { @@ -47,6 +51,7 @@ function ChatMessageItem({ msg, showErrorRow }: { msg: ChatMessage, showErrorRow const [error, setError] = useState(null); const [originsExpanded, setOriginsExpanded] = useState(false); const [showGraph, setShowGraph] = useState(false); + const [graphFullscreen, setGraphFullscreen] = useState(false); useEffect(() => { let cancelled = false; @@ -148,6 +153,10 @@ function ChatMessageItem({ msg, showErrorRow }: { msg: ChatMessage, showErrorRow setShowGraph(prev => !prev); }, []); + const handleFullscreenToggle = useCallback(() => { + setGraphFullscreen(prev => !prev); + }, []); + const OriginsBox = useCallback(() => (
@@ -169,9 +178,9 @@ function ChatMessageItem({ msg, showErrorRow }: { msg: ChatMessage, showErrorRow {originsCount > 0 && ( )}
@@ -199,52 +208,95 @@ function ChatMessageItem({ msg, showErrorRow }: { msg: ChatMessage, showErrorRow
), [originsExpanded, originsCount, showGraph, originKeyPathArray, handleOriginsToggle, handleGraphToggle]); - const GraphView = useCallback(() => ( - showGraph && originsCount > 0 && ( -
-
Message Propagation Tree
-
- {treeData && ( - { - const isRoot = nodeDatum.name === "??"; - // Check if this node represents an origin pubkey (final 2-char hex from pubkey) - const isOriginPubkey = originKeyPathArray.some(([origin, pubkey, path]) => { - const pubkeyPrefix = pubkey.substring(0, 2); - return nodeDatum.name === pubkeyPrefix; - }); - - return ( - - - - {nodeDatum.name} - - - ); - }} - /> - )} + const GraphView = useCallback(() => { + if (!showGraph || originsCount === 0) return null; + + const treeComponent = ( + { + const isRoot = nodeDatum.name === "??"; + // Check if this node represents an origin pubkey (final 2-char hex from pubkey) + const isOriginPubkey = originKeyPathArray.some(([origin, pubkey, path]) => { + const pubkeyPrefix = pubkey.substring(0, 2); + return nodeDatum.name === pubkeyPrefix; + }); + + return ( + + + + {nodeDatum.name} + + + ); + }} + /> + ); + + if (graphFullscreen && typeof window !== 'undefined') { + return createPortal( +
+
e.stopPropagation()} + > +
+

Message Propagation Tree

+ +
+
+ {treeData ? treeComponent : null} +
+
+
, + document.body + ); + } + + return ( +
+ +
+ {treeData && treeComponent} +
-
- ) - ), [showGraph, originsCount, treeData, msg.ingest_timestamp]); + ); + }, [showGraph, originsCount, treeData, msg.ingest_timestamp, graphFullscreen, handleFullscreenToggle, originKeyPathArray]); if (parsed) { return (