diff --git a/images/firefly_explorer.png b/images/firefly_explorer.png
index 06cc36c4..8d8ae2a3 100644
Binary files a/images/firefly_explorer.png and b/images/firefly_explorer.png differ
diff --git a/src/components/Charts/DiagramFireFlyNode.tsx b/src/components/Charts/DiagramFireFlyNode.tsx
index 2b24a4b5..5edea0e5 100644
--- a/src/components/Charts/DiagramFireFlyNode.tsx
+++ b/src/components/Charts/DiagramFireFlyNode.tsx
@@ -1,20 +1,36 @@
-import { Grid, Typography } from '@mui/material';
+import { Box, Grid, styled, Typography } from '@mui/material';
import { memo } from 'react';
import { Handle, Position } from 'react-flow-renderer';
-import { IStatus, IWebsocketConnection } from '../../interfaces';
+import { IStatus } from '../../interfaces';
import { APP_PREFIX, HANDLE_PREFIX, PLUGIN_PREFIX } from './MyNodeDiagram';
+import { ReactComponent as LogoSVG } from '../..//svg/ff-logo-symbol-white.svg';
+import i18next from 'i18next';
+
+export const FFLogo: React.FC = () => {
+ const StyledLogo = styled(LogoSVG)({
+ width: 60,
+ });
+ return (
+
+
+
+ );
+};
interface FFNodeProps {
data: {
- applications: IWebsocketConnection[];
+ applications: IStatus['plugins'];
plugins: IStatus['plugins'];
- label: string;
- subtitle: string;
+ nodeName: string;
};
}
export const DiagramFireFlyNode = memo((children: FFNodeProps) => {
if (
- children.data.applications?.length &&
+ Object.keys(children.data.applications)?.length &&
Object.keys(children.data.plugins)?.length
) {
return (
@@ -28,41 +44,53 @@ export const DiagramFireFlyNode = memo((children: FFNodeProps) => {
width={'100%'}
>
- {children.data.label}
+ {i18next.t('firefly')}
+
+
+ {i18next.t('core')}
+
- {children.data.subtitle}
+ {children.data.nodeName}
- {children.data.applications.map((_, idx) => {
- return (
-
- );
+ {Object.keys(children.data.applications).map((k, idx) => {
+ // Only show events on left side
+ if (k === 'events') {
+ return (
+
+ );
+ }
})}
- {Object.keys(children.data.plugins).map((_, idx) => {
- return (
-
- );
+ {Object.keys(children.data.plugins).map((k, idx) => {
+ if (k !== 'events') {
+ return (
+
+ );
+ }
})}
>
);
diff --git a/src/components/Charts/MyNodeDiagram.tsx b/src/components/Charts/MyNodeDiagram.tsx
index acde5301..98e2417f 100644
--- a/src/components/Charts/MyNodeDiagram.tsx
+++ b/src/components/Charts/MyNodeDiagram.tsx
@@ -5,7 +5,6 @@ import i18next from 'i18next';
import React, { useContext, useEffect, useState } from 'react';
import ReactFlow, {
Edge,
- MarkerType,
Node,
NodeTypes,
Position,
@@ -14,7 +13,7 @@ import ReactFlow, {
useNodesState,
} from 'react-flow-renderer';
import { ApplicationContext } from '../../contexts/ApplicationContext';
-import { IStatus, IWebsocketConnection } from '../../interfaces';
+import { IStatus } from '../../interfaces';
import { DEFAULT_BORDER_RADIUS, FFColors } from '../../theme';
import { FFCircleLoader } from '../Loaders/FFCircleLoader';
import { DiagramFireFlyNode } from './DiagramFireFlyNode';
@@ -45,10 +44,13 @@ const edgeStyle = {
const dagreGraph = new dagre.graphlib.Graph();
dagreGraph.setDefaultEdgeLabel(() => ({}));
-const nodeWidth = 350;
-const nodeHeight = 25;
-
-const getLayoutedElements = (nodes: Node[], edges: Edge[]) => {
+const getLayoutedElements = (
+ nodes: Node[],
+ edges: Edge[],
+ isSmall: boolean
+) => {
+ const nodeWidth = isSmall ? 175 : 350;
+ const nodeHeight = 25;
dagreGraph.setGraph({ rankdir: 'LR' });
nodes.forEach((node) => {
@@ -86,24 +88,29 @@ const getLayoutedElements = (nodes: Node[], edges: Edge[]) => {
};
const makeInitialNodes = (
- applications: any[],
+ applications: IStatus['plugins'],
plugins: IStatus['plugins'],
nodeName: string
) => {
let nodes: Node[] = [];
// Applications (Left side)
- nodes = nodes.concat(
- applications.map((a, idx) => {
- return {
- id: `${APP_PREFIX}${idx}`,
- sourcePosition: Position.Right,
- type: 'input',
- style: nodeStyle,
- data: { label: a.remoteAddress },
- position,
- };
- })
- );
+ Object.entries(applications).map(([k, v]) => {
+ // Only show events on left side
+ if (k === 'events') {
+ nodes = nodes.concat(
+ v.map((plugin, idx) => {
+ return {
+ id: `${APP_PREFIX}${k}_${idx}`,
+ sourcePosition: Position.Right,
+ type: 'input',
+ style: nodeStyle,
+ data: { label: plugin.name ? plugin.name : plugin.pluginType },
+ position,
+ };
+ })
+ );
+ }
+ });
// Firefly
nodes.push({
type: 'fireflyNode',
@@ -114,85 +121,104 @@ const makeInitialNodes = (
data: {
applications,
plugins,
- label: i18next.t('firefly'),
- subtitle: nodeName,
+ nodeName,
},
position,
});
// Plugins (Right side)
Object.entries(plugins).map(([k, v]) => {
- nodes = nodes.concat(
- v.map((plugin, idx) => {
- return {
- id: `${PLUGIN_PREFIX}${k}_${idx}`,
- targetPosition: Position.Left,
- type: 'output',
- data: { label: plugin.connection },
- position,
- style: nodeStyle,
- };
- })
- );
+ if (k !== 'events') {
+ nodes = nodes.concat(
+ v.map((plugin, idx) => {
+ return {
+ id: `${PLUGIN_PREFIX}${k}_${idx}`,
+ targetPosition: Position.Left,
+ type: 'output',
+ data: { label: plugin.name ? plugin.name : plugin.pluginType },
+ position,
+ style: nodeStyle,
+ };
+ })
+ );
+ }
});
return nodes;
};
const makeInitialEdges = (
- applications: IWebsocketConnection[],
- plugins: IStatus['plugins']
+ applications: IStatus['plugins'],
+ plugins: IStatus['plugins'],
+ isSmall: boolean
) => {
let edges: Edge[] = [];
// Apps
- edges = edges.concat(
- applications.map((_, idx): Edge => {
- return {
- id: `${APP_PREFIX}${FF_NODE_PREFIX}${idx}`,
- source: `${APP_PREFIX}${idx}`,
- targetHandle: `${HANDLE_PREFIX}${APP_PREFIX}${idx}`,
- target: FF_NODE_PREFIX,
- style: edgeStyle,
- markerEnd: {
- type: MarkerType.ArrowClosed,
- color: FFColors.Orange,
- },
- label: i18next.t('websocket'),
- labelBgPadding: [8, 4],
- labelBgBorderRadius: 4,
- labelBgStyle: {
- fill: '#1e242a',
- fillOpacity: 0.97,
- },
- labelStyle: { fill: '#FFFFFF', fontWeight: 700 },
- };
- })
- );
+ // Applications
+ Object.entries(applications).map(([k, v], pIdx) => {
+ // Only show events on left side
+ if (k === 'events') {
+ edges = edges.concat(
+ v.map((_, idx) => {
+ let edge: Edge = {
+ id: `${APP_PREFIX}${FF_NODE_PREFIX}${k}_${idx}`,
+ source: `${APP_PREFIX}${k}_${idx}`,
+ targetHandle: `${HANDLE_PREFIX}${APP_PREFIX}${pIdx}`,
+ target: FF_NODE_PREFIX,
+ style: edgeStyle,
+ };
+
+ if (!isSmall) {
+ edge = {
+ ...edge,
+ label: i18next.t(k),
+ labelBgPadding: [8, 4],
+ labelBgBorderRadius: 4,
+ labelBgStyle: {
+ fill: '#1e242a',
+ fillOpacity: 0.97,
+ },
+ labelStyle: { fill: '#FFFFFF', fontWeight: 700 },
+ };
+ }
+
+ return edge;
+ })
+ );
+ }
+ });
+
// Plugins
Object.entries(plugins).map(([k, v], pIdx) => {
- edges = edges.concat(
- v.map((_, idx) => {
- return {
- id: `${PLUGIN_PREFIX}${FF_NODE_PREFIX}${k}_${idx}`,
- source: FF_NODE_PREFIX,
- sourceHandle: `${HANDLE_PREFIX}${PLUGIN_PREFIX}${pIdx}`,
- target: `${PLUGIN_PREFIX}${k}_${idx}`,
- style: edgeStyle,
- markerEnd: {
- type: MarkerType.ArrowClosed,
- color: FFColors.Orange,
- },
- label: i18next.t(k),
- labelBgPadding: [8, 4],
- labelBgBorderRadius: 4,
- labelBgStyle: {
- fill: '#1e242a',
- fillOpacity: 0.97,
- },
- labelStyle: { fill: '#FFFFFF', fontWeight: 700 },
- };
- })
- );
+ if (k !== 'events') {
+ edges = edges.concat(
+ v.map((_, idx) => {
+ let edge: Edge = {
+ id: `${PLUGIN_PREFIX}${FF_NODE_PREFIX}${k}_${idx}`,
+ source: FF_NODE_PREFIX,
+ sourceHandle: `${HANDLE_PREFIX}${PLUGIN_PREFIX}${pIdx}`,
+ target: `${PLUGIN_PREFIX}${k}_${idx}`,
+ style: edgeStyle,
+ };
+
+ if (!isSmall) {
+ edge = {
+ ...edge,
+ label: i18next.t(k),
+ labelBgPadding: [8, 4],
+ labelBgBorderRadius: 4,
+ labelBgStyle: {
+ fill: '#1e242a',
+ fillOpacity: 0.97,
+ },
+ labelStyle: { fill: '#FFFFFF', fontWeight: 700 },
+ };
+ }
+
+ return edge;
+ })
+ );
+ }
});
return edges;
@@ -203,11 +229,14 @@ const nodeTypes: NodeTypes = {
};
interface Props {
- applications: IWebsocketConnection[];
plugins: IStatus['plugins'];
+ isSmall?: boolean;
}
-export const MyNodeDiagram: React.FC = ({ applications, plugins }) => {
+export const MyNodeDiagram: React.FC = ({
+ plugins,
+ isSmall = false,
+}) => {
const { nodeName } = useContext(ApplicationContext);
const [isMounted, setIsMounted] = useState(false);
@@ -219,19 +248,15 @@ export const MyNodeDiagram: React.FC = ({ applications, plugins }) => {
}, []);
const { nodes: layoutedNodes, edges: layoutedEdges } = getLayoutedElements(
- makeInitialNodes(applications, plugins, nodeName),
- makeInitialEdges(applications, plugins)
+ makeInitialNodes(plugins, plugins, nodeName),
+ makeInitialEdges(plugins, plugins, isSmall),
+ isSmall
);
const [nodes, , onNodesChange] = useNodesState(layoutedNodes);
const [edges, , onEdgesChange] = useEdgesState(layoutedEdges);
- if (
- !plugins ||
- !applications ||
- applications.length === 0 ||
- Object.keys(plugins ?? {}).length === 0
- ) {
+ if (!plugins || Object.keys(plugins ?? {}).length === 0) {
return (
JSX.Element = () => {
const [recentEvents, setRecentEvents] = useState();
const [isHistLoading, setIsHistLoading] = useState(false);
- const [apps, setApps] = useState();
const [plugins, setPlugins] = useState();
const [isMyNodeLoading, setIsMyNodeLoading] = useState(true);
@@ -299,12 +296,10 @@ export const HomeDashboard: () => JSX.Element = () => {
headerText: t('myNode'),
component:
!isMyNodeLoading &&
- apps &&
- apps.length > 0 &&
plugins &&
Object.keys(plugins ?? {}).length > 0 &&
isMounted ? (
-
+
) : (
),
@@ -340,13 +335,6 @@ export const HomeDashboard: () => JSX.Element = () => {
useEffect(() => {
setIsMyNodeLoading(true);
if (isMounted) {
- fetchCatcher(`${FF_Paths.apiPrefix}/${FF_Paths.statusWebsockets}`)
- .then((wsRes: IWebsocketStatus) => {
- isMounted && setApps(wsRes.connections);
- })
- .catch((err) => {
- reportFetchError(err);
- });
fetchCatcher(`${FF_Paths.apiPrefix}/${FF_Paths.status}`)
.then((statusRes: IStatus) => {
isMounted && setPlugins(statusRes.plugins);
diff --git a/src/pages/MyNode/views/Dashboard.tsx b/src/pages/MyNode/views/Dashboard.tsx
index 03f845f1..2649cb13 100644
--- a/src/pages/MyNode/views/Dashboard.tsx
+++ b/src/pages/MyNode/views/Dashboard.tsx
@@ -20,19 +20,13 @@ import { useTranslation } from 'react-i18next';
import { MyNodeDiagram } from '../../../components/Charts/MyNodeDiagram';
import { Header } from '../../../components/Header';
import { SnackbarContext } from '../../../contexts/SnackbarContext';
-import {
- FF_Paths,
- IStatus,
- IWebsocketConnection,
- IWebsocketStatus,
-} from '../../../interfaces';
+import { FF_Paths, IStatus } from '../../../interfaces';
import { DEFAULT_PADDING } from '../../../theme';
import { fetchCatcher } from '../../../utils';
export const MyNodeDashboard: () => JSX.Element = () => {
const { reportFetchError } = useContext(SnackbarContext);
const { t } = useTranslation();
- const [apps, setApps] = useState();
const [plugins, setPlugins] = useState();
const [isLoading, setIsLoading] = useState(true);
@@ -48,13 +42,6 @@ export const MyNodeDashboard: () => JSX.Element = () => {
useEffect(() => {
setIsLoading(true);
if (isMounted) {
- fetchCatcher(`${FF_Paths.apiPrefix}/${FF_Paths.statusWebsockets}`)
- .then((wsRes: IWebsocketStatus) => {
- isMounted && setApps(wsRes.connections);
- })
- .catch((err) => {
- reportFetchError(err);
- });
fetchCatcher(`${FF_Paths.apiPrefix}/${FF_Paths.status}`)
.then((statusRes: IStatus) => {
isMounted && setPlugins(statusRes.plugins);
@@ -77,13 +64,9 @@ export const MyNodeDashboard: () => JSX.Element = () => {
{!isLoading &&
- apps &&
- apps.length > 0 &&
plugins &&
Object.keys(plugins ?? {}).length > 0 &&
- isMounted && (
-
- )}
+ isMounted && }
>
diff --git a/src/translations/en.json b/src/translations/en.json
index caa35f98..7347fd59 100644
--- a/src/translations/en.json
+++ b/src/translations/en.json
@@ -57,6 +57,7 @@
"contractListener": "Contract Listener",
"contractListeners": "Contract Listeners",
"copyToClipboard": "Copy to Clipboard",
+ "core": "Core",
"created": "Created",
"customRange": "Custom Range",
"dashboard": "Dashboard",