forked from cerc-io/laconic-console
Signal graph (#49)
* Initial signal graph * Minor update * Change graph using object mutator * Added SignalServer graph * Remove d3 dependencies * fixed signal kube system information * updated gem * Minor fix * update configuration * /api for signal * apollo1 * Added visx network graph * Remove info table. * Fixed tooltip zIndex Co-authored-by: Martin Acosta <Martín Acosta> Co-authored-by: Thomas E Lackey <telackey@bozemanpass.com> Co-authored-by: Thomas E Lackey <thomas@wireline.io>
This commit is contained in:
parent
afa99a564c
commit
e099fca2f8
@ -30,11 +30,11 @@ services:
|
||||
|
||||
signal:
|
||||
server: 'wss://kube.local/dxos/signal'
|
||||
api: 'https://kube.local/dxos/signal'
|
||||
api: 'https://kube.local/dxos/signal/api'
|
||||
|
||||
ipfs:
|
||||
server: 'https://kube.local/dxos/ipfs/api'
|
||||
gateway: 'https://kube.local/dxos/ipfs/gateway'
|
||||
|
||||
wellknown:
|
||||
endpoint: 'https://kube.local/.well-known/dxos'
|
||||
endpoint: 'https://kube.local/.well-known/dxos'
|
@ -30,11 +30,11 @@ services:
|
||||
|
||||
signal:
|
||||
server: 'ws://127.0.0.1:4000'
|
||||
api: 'http://127.0.0.1:4000'
|
||||
api: 'http://127.0.0.1:4000/api'
|
||||
|
||||
ipfs:
|
||||
server: 'http://127.0.0.1:5001'
|
||||
gateway: 'http://127.0.0.1:8888/ipfs/'
|
||||
|
||||
wellknown:
|
||||
endpoint: 'http://127.0.0.1:9000/.well-known/dxos'
|
||||
endpoint: 'http://127.0.0.1:9000/.well-known/dxos'
|
@ -27,11 +27,11 @@ routes:
|
||||
webui: '/dxos/wns/console'
|
||||
|
||||
signal:
|
||||
api: '/dxos/signal'
|
||||
api: '/dxos/signal/api'
|
||||
|
||||
ipfs:
|
||||
server: '/dxos/ipfs/api'
|
||||
gateway: '/dxos/ipfs/gateway'
|
||||
|
||||
wellknown:
|
||||
endpoint: '/.well-known/dxos'
|
||||
endpoint: '/.well-known/dxos'
|
@ -30,7 +30,7 @@ services:
|
||||
|
||||
signal:
|
||||
server: 'wss://apollo1.kube.moon.dxos.network/dxos/signal'
|
||||
api: 'https://apollo1.kube.moon.dxos.network/dxos/signal'
|
||||
api: 'https://apollo1.kube.moon.dxos.network/dxos/signal/api'
|
||||
|
||||
ipfs:
|
||||
server: 'https://apollo1.kube.moon.dxos.network/dxos/ipfs/api'
|
||||
|
@ -19,7 +19,7 @@
|
||||
"author": "DXOS.org",
|
||||
"license": "GPL-3.0",
|
||||
"browserslist": [
|
||||
"> 5%"
|
||||
"> 2%"
|
||||
],
|
||||
"jest": {
|
||||
"testEnvironment": "node"
|
||||
@ -28,19 +28,25 @@
|
||||
"@apollo/react-components": "^3.1.5",
|
||||
"@apollo/react-hooks": "^3.1.5",
|
||||
"@babel/runtime": "^7.8.7",
|
||||
"@dxos/debug": "^1.0.0-beta.20",
|
||||
"@dxos/gem-core": "^1.0.0-beta.11",
|
||||
"@dxos/debug": "^1.0.0-beta.2",
|
||||
"@dxos/gem-core": "^1.0.0-beta.25",
|
||||
"@dxos/react-ux": "^1.1.0-beta.0",
|
||||
"@material-ui/core": "^4.10.0",
|
||||
"@material-ui/icons": "^4.9.1",
|
||||
"@material-ui/lab": "^4.0.0-alpha.54",
|
||||
"@rehooks/component-size": "^1.0.3",
|
||||
"@visx/network": "^1.0.0",
|
||||
"@visx/tooltip": "^1.0.0",
|
||||
"@visx/zoom": "^1.0.0",
|
||||
"@wirelineio/registry-client": "^1.1.0-beta.2",
|
||||
"apollo-cache-inmemory": "^1.6.6",
|
||||
"apollo-client": "^2.6.10",
|
||||
"apollo-link": "^1.2.14",
|
||||
"apollo-link-http": "^1.5.17",
|
||||
"build-url": "^2.0.0",
|
||||
"clsx": "^1.1.0",
|
||||
"compare-versions": "^3.6.0",
|
||||
"d3-force": "^2.1.1",
|
||||
"debug": "^4.1.1",
|
||||
"graphql-tag": "^2.10.3",
|
||||
"lodash.defaultsdeep": "^4.6.1",
|
||||
|
@ -3,6 +3,7 @@
|
||||
//
|
||||
|
||||
import { ApolloClient } from 'apollo-client';
|
||||
import { ApolloLink } from 'apollo-link';
|
||||
import { createHttpLink } from 'apollo-link-http';
|
||||
import { InMemoryCache } from 'apollo-cache-inmemory';
|
||||
|
||||
@ -26,7 +27,7 @@ export const graphqlApi = config => {
|
||||
*/
|
||||
export const clientFactory = config => {
|
||||
// https://www.apollographql.com/docs/link/
|
||||
const link = createHttpLink({
|
||||
const defaultLink = createHttpLink({
|
||||
uri: graphqlApi(config),
|
||||
|
||||
// TODO(burdon): Authentication: send signed message to server (from client wallet).
|
||||
@ -36,11 +37,21 @@ export const clientFactory = config => {
|
||||
}
|
||||
});
|
||||
|
||||
const serviceLinks = {
|
||||
signal: createHttpLink({
|
||||
uri: config.services.signal.api
|
||||
})
|
||||
};
|
||||
|
||||
// https://www.apollographql.com/docs/react/api/apollo-client/
|
||||
return new ApolloClient({
|
||||
connectToDevTools: true,
|
||||
cache: new InMemoryCache(),
|
||||
resolvers: createResolvers(config),
|
||||
link
|
||||
link: ApolloLink.split(
|
||||
operation => operation.getContext().api && serviceLinks[operation.getContext().api],
|
||||
operation => serviceLinks[operation.getContext().api].request(operation),
|
||||
defaultLink
|
||||
)
|
||||
});
|
||||
};
|
||||
|
173
packages/console-app/src/components/NetworkGraph.js
Normal file
173
packages/console-app/src/components/NetworkGraph.js
Normal file
@ -0,0 +1,173 @@
|
||||
import React, { useEffect, useRef, useReducer, useMemo, useCallback } from 'react';
|
||||
import { forceLink, forceSimulation, forceCenter, forceCollide, forceManyBody, forceRadial } from 'd3-force';
|
||||
|
||||
import { Graph } from '@visx/network';
|
||||
import { Tooltip, useTooltip, defaultStyles } from '@visx/tooltip';
|
||||
import { Zoom } from '@visx/zoom';
|
||||
|
||||
import * as colors from '@material-ui/core/colors';
|
||||
|
||||
const kNodes = Symbol('nodes');
|
||||
const kLinks = Symbol('links');
|
||||
const kUpdate = Symbol('update');
|
||||
|
||||
const background = '#101020';
|
||||
|
||||
const nodeStyle = {
|
||||
default: {
|
||||
fill: colors.pink[400],
|
||||
r: 20
|
||||
},
|
||||
root: {
|
||||
fill: colors.blue[400],
|
||||
r: 25
|
||||
},
|
||||
adjacent: {
|
||||
fill: colors.red[400],
|
||||
r: 20
|
||||
},
|
||||
detach: {
|
||||
fill: colors.grey[400],
|
||||
r: 15
|
||||
}
|
||||
};
|
||||
|
||||
const tooltipStyles = {
|
||||
...defaultStyles,
|
||||
backgroundColor: 'rgba(53,71,125,0.9)',
|
||||
color: 'white',
|
||||
padding: 12,
|
||||
zIndex: 1000
|
||||
};
|
||||
|
||||
const useForceUpdate = () => useReducer(x => !x, false)[1];
|
||||
|
||||
const useForce = ({ width, height, graph }) => {
|
||||
const forceUpdate = useForceUpdate();
|
||||
const d3force = useRef(null);
|
||||
|
||||
if (d3force.current) {
|
||||
const oldNodes = d3force.current[kNodes];
|
||||
const newNodes = graph.nodes.map(n => n.id);
|
||||
let update = newNodes.filter(id => !oldNodes.includes(id)).length !== oldNodes.filter(id => !newNodes.includes(id)).length;
|
||||
if (!update) {
|
||||
const oldLinks = d3force.current[kLinks];
|
||||
const newLinks = graph.links.map(l => l.id);
|
||||
update = newLinks.filter(id => !oldLinks.includes(id)).length !== oldLinks.filter(id => !newLinks.includes(id)).length;
|
||||
}
|
||||
if (update) {
|
||||
d3force.current[kUpdate] = true;
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
let restart = true;
|
||||
|
||||
if (!d3force.current) {
|
||||
restart = false;
|
||||
|
||||
d3force.current = forceSimulation(graph.nodes)
|
||||
.force('link', forceLink().id(d => d.id).links(graph.links))
|
||||
.force('charge', forceManyBody().strength(-2000))
|
||||
.force('collision', forceCollide().strength(1));
|
||||
|
||||
d3force.current.on('tick', () => {
|
||||
forceUpdate();
|
||||
});
|
||||
}
|
||||
|
||||
d3force.current
|
||||
.force('center', forceCenter(width / 2, height / 2).strength(0))
|
||||
.force('r', forceRadial(200).strength(1));
|
||||
|
||||
d3force.current[kNodes] = graph.nodes.map(n => n.id);
|
||||
d3force.current[kLinks] = graph.links.map(l => l.id);
|
||||
|
||||
if (!restart) {
|
||||
return;
|
||||
}
|
||||
|
||||
d3force.current.nodes(graph.nodes);
|
||||
d3force.current.force('link').links(graph.links);
|
||||
if (d3force.current[kUpdate]) {
|
||||
d3force.current[kUpdate] = false;
|
||||
d3force.current.alpha(1).restart();
|
||||
} else {
|
||||
d3force.current.restart();
|
||||
}
|
||||
}, [width, height, graph]);
|
||||
};
|
||||
|
||||
const useNode = (handlers) => useMemo(() => function Node ({ node }) {
|
||||
const { label, type = 'default', ...positions } = node;
|
||||
const style = nodeStyle[type] || {};
|
||||
|
||||
const handleMouseEnter = useCallback((e) => handlers.onMouseEnter(node, e), [node]);
|
||||
const handleMouseLeave = useCallback((e) => handlers.onMouseLeave(node, e), [node]);
|
||||
|
||||
return (
|
||||
<g>
|
||||
<circle r={style.r} fill={style.fill} {...positions} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} />
|
||||
{label &&
|
||||
<text dy={style.r} dx={style.r + 2} fill='white' fontFamily='arial'>
|
||||
{label}
|
||||
</text>}
|
||||
</g>
|
||||
);
|
||||
}, []);
|
||||
|
||||
export default function NetworkGraph ({ width, height, graph, onTooltip = () => {} }) {
|
||||
useForce({ width, height, graph });
|
||||
|
||||
const { showTooltip, hideTooltip, tooltipOpen, tooltipData, tooltipLeft = 0, tooltipTop = 0 } = useTooltip();
|
||||
|
||||
const Node = useNode({
|
||||
onMouseEnter: (node, e) => {
|
||||
showTooltip({
|
||||
tooltipTop: e.clientY,
|
||||
tooltipLeft: e.clientX,
|
||||
tooltipData: node
|
||||
});
|
||||
},
|
||||
onMouseLeave: () => {
|
||||
hideTooltip();
|
||||
}
|
||||
});
|
||||
|
||||
return (width <= 0 || height <= 0 || !graph) ? null : (
|
||||
<div style={{ width, height }}>
|
||||
{tooltipData && tooltipData.data && tooltipOpen &&
|
||||
<Tooltip key={Math.random()} left={tooltipLeft} top={tooltipTop} style={tooltipStyles}>
|
||||
{onTooltip(tooltipData.data)}
|
||||
</Tooltip>}
|
||||
<Zoom
|
||||
width={width}
|
||||
height={height}
|
||||
scaleXMin={1 / 2}
|
||||
scaleXMax={4}
|
||||
scaleYMin={1 / 2}
|
||||
scaleYMax={4}
|
||||
>
|
||||
{zoom => (
|
||||
<svg width={width} height={height}>
|
||||
<rect
|
||||
width={width}
|
||||
height={height}
|
||||
fill={background}
|
||||
style={{ cursor: zoom.isDragging ? 'grabbing' : 'grab' }}
|
||||
onTouchStart={zoom.dragStart} // eslint-disable-line
|
||||
onTouchMove={zoom.dragMove} // eslint-disable-line
|
||||
onTouchEnd={zoom.dragEnd} // eslint-disable-line
|
||||
onMouseDown={zoom.dragStart} // eslint-disable-line
|
||||
onMouseMove={zoom.dragMove} // eslint-disable-line
|
||||
onMouseUp={zoom.dragEnd} // eslint-disable-line
|
||||
/>
|
||||
<g transform={zoom.toString()}>
|
||||
<Graph graph={graph} top={height / 2} left={width / 2} nodeComponent={Node} />
|
||||
</g>
|
||||
</svg>
|
||||
)}
|
||||
</Zoom>
|
||||
</div>
|
||||
);
|
||||
}
|
@ -6,7 +6,6 @@ import React, { useContext } from 'react';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableContainer from '@material-ui/core/TableContainer';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
|
||||
@ -19,38 +18,53 @@ import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||
|
||||
const SignalChannels = () => {
|
||||
const { config } = useContext(ConsoleContext);
|
||||
const data = useQueryStatusReducer(useQuery(SIGNAL_STATUS, { pollInterval: config.api.intervalQuery }));
|
||||
const data = useQueryStatusReducer(useQuery(SIGNAL_STATUS, { fetchPolicy: 'no-cache', pollInterval: config.api.pollInterval, context: { api: 'signal' } }));
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const { json: { channels = [] } } = data.signal_status;
|
||||
const { nodes = [] } = data.signal_status;
|
||||
|
||||
const channels = new Map();
|
||||
nodes.forEach(node => {
|
||||
const { signal: { topics = [] } } = node;
|
||||
topics.forEach(topic => {
|
||||
if (!channels.has(topic.id)) {
|
||||
channels.set(topic.id, {
|
||||
id: topic.id,
|
||||
peers: topic.peers
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const ch = channels.get(topic.id);
|
||||
ch.peers = [...ch.peers, ...topic.peers];
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Channel</TableCell>
|
||||
<TableCell size='small'>Participants</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{channels.map(({ channel, peers = [] }) => {
|
||||
return (
|
||||
<TableRow key={channel} size='small'>
|
||||
<TableCell monospace>
|
||||
{channel}
|
||||
</TableCell>
|
||||
<TableCell monospace>
|
||||
{peers.length}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Channel</TableCell>
|
||||
<TableCell size='small'>Participants</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{Array.from(channels.values()).map(({ id, peers = [] }) => {
|
||||
return (
|
||||
<TableRow key={id} size='small'>
|
||||
<TableCell monospace>
|
||||
{id}
|
||||
</TableCell>
|
||||
<TableCell monospace>
|
||||
{peers.length}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -2,52 +2,184 @@
|
||||
// Copyright 2020 DXOS.org
|
||||
//
|
||||
|
||||
import React, { useContext } from 'react';
|
||||
import React, { useContext, useRef, useEffect, useState, useCallback } from 'react';
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import useComponentSize from '@rehooks/component-size';
|
||||
import moment from 'moment';
|
||||
|
||||
import Grid from '@material-ui/core/Grid';
|
||||
import TableBody from '@material-ui/core/TableBody';
|
||||
import TableContainer from '@material-ui/core/TableContainer';
|
||||
import TableHead from '@material-ui/core/TableHead';
|
||||
import TableRow from '@material-ui/core/TableRow';
|
||||
import { makeStyles } from '@material-ui/core/styles';
|
||||
|
||||
import Box from '@material-ui/core/Box';
|
||||
import Collapse from '@material-ui/core/Collapse';
|
||||
import IconButton from '@material-ui/core/IconButton';
|
||||
import Typography from '@material-ui/core/Typography';
|
||||
import KeyboardArrowDownIcon from '@material-ui/icons/KeyboardArrowDown';
|
||||
import KeyboardArrowUpIcon from '@material-ui/icons/KeyboardArrowUp';
|
||||
|
||||
import Table from '../../../components/Table';
|
||||
import TableCell from '../../../components/TableCell';
|
||||
import NetworkGraph from '../../../components/NetworkGraph';
|
||||
|
||||
import SIGNAL_STATUS from '../../../gql/signal_status.graphql';
|
||||
|
||||
import { ConsoleContext, useQueryStatusReducer } from '../../../hooks';
|
||||
|
||||
const SignalServers = () => {
|
||||
const { config } = useContext(ConsoleContext);
|
||||
const data = useQueryStatusReducer(useQuery(SIGNAL_STATUS, { pollInterval: config.api.intervalQuery }));
|
||||
if (!data) {
|
||||
return null;
|
||||
}
|
||||
const buildDataGraph = (rootId, prevGraph, nodes) => {
|
||||
const newGraph = { nodes: [], links: [] };
|
||||
|
||||
const { json: { signals = [] } } = data.signal_status;
|
||||
const rootNode = nodes.find(n => n.id === rootId);
|
||||
|
||||
return (
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Signal Server</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{signals.map((signal) => {
|
||||
return (
|
||||
<TableRow key={signal} size='small'>
|
||||
<TableCell monospace>
|
||||
{signal}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
);
|
||||
nodes.forEach(node => {
|
||||
let type = 'detach';
|
||||
if (rootId === node.id) {
|
||||
type = 'root';
|
||||
} else {
|
||||
const isAdjacent = rootNode.connections.find(conn => conn.target === node.id) || node.connections.find(conn => conn.target === rootId);
|
||||
if (isAdjacent) {
|
||||
type = 'adjacent';
|
||||
}
|
||||
}
|
||||
|
||||
const oldNode = prevGraph.nodes.find(n => n.id === node.id) || {};
|
||||
const newNode = { ...oldNode, id: node.id, label: node.id.slice(0, 6), type, data: node };
|
||||
if (type === 'root') {
|
||||
newNode.fx = 0;
|
||||
newNode.fy = 0;
|
||||
}
|
||||
newGraph.nodes.push(newNode);
|
||||
});
|
||||
|
||||
nodes.forEach(node => {
|
||||
node.connections.forEach(conn => {
|
||||
newGraph.links.push({ id: conn.id, source: node.id, target: conn.target });
|
||||
});
|
||||
});
|
||||
|
||||
return newGraph;
|
||||
};
|
||||
|
||||
const useDataGraph = (response) => {
|
||||
const [dataGraph, setDataGraph] = useState({ updatedAt: 0, nodes: [], links: [] });
|
||||
|
||||
useEffect(() => {
|
||||
if (!response) return;
|
||||
const { id: rootId, nodes = [] } = response.signal_status;
|
||||
const updatedAt = moment(response.signal_status.updatedAt).valueOf();
|
||||
|
||||
if (dataGraph.updatedAt >= updatedAt) return;
|
||||
|
||||
const graph = buildDataGraph(rootId, dataGraph, nodes);
|
||||
setDataGraph({
|
||||
updatedAt,
|
||||
...graph
|
||||
});
|
||||
}, [response && response.signal_status.updatedAt]);
|
||||
|
||||
return dataGraph;
|
||||
};
|
||||
|
||||
const useRowStyles = makeStyles({
|
||||
root: {
|
||||
'& > *': {
|
||||
borderBottom: 'unset'
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function Row (props) {
|
||||
const { row } = props;
|
||||
|
||||
const classes = useRowStyles();
|
||||
|
||||
const system = row.kubeStatus.system;
|
||||
|
||||
return (
|
||||
<>
|
||||
<TableRow className={classes.root}>
|
||||
<TableCell component='th' scope='row'>
|
||||
{row.id}
|
||||
</TableCell>
|
||||
<TableCell align='right'>{row.signal.topics.reduce((prev, curr) => prev + curr.peers.length, 0)}</TableCell>
|
||||
<TableCell align='right'>{system?.version || '-'}</TableCell>
|
||||
<TableCell align='right'>{system?.nodejs?.version || '-'}</TableCell>
|
||||
<TableCell align='right'>{system?.memory?.used || '-'}</TableCell>
|
||||
<TableCell align='right'>{system?.memory?.total || '-'}</TableCell>
|
||||
<TableCell align='right'>{system?.time?.up ? moment(system?.time?.up).format('lll') : '-'}</TableCell>
|
||||
</TableRow>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function SignalServers () {
|
||||
const { config } = useContext(ConsoleContext);
|
||||
const response = useQueryStatusReducer(useQuery(SIGNAL_STATUS, { fetchPolicy: 'no-cache', pollInterval: config.api.pollInterval, context: { api: 'signal' } }));
|
||||
|
||||
const data = useDataGraph(response);
|
||||
|
||||
const sizeRef = useRef(null);
|
||||
const { width, height } = useComponentSize(sizeRef);
|
||||
|
||||
const [open, setOpen] = useState(null);
|
||||
|
||||
const handleOpen = useCallback(
|
||||
(id) => {
|
||||
if (open && open === id) {
|
||||
setOpen(null);
|
||||
} else {
|
||||
setOpen(id);
|
||||
}
|
||||
},
|
||||
[open]
|
||||
);
|
||||
|
||||
return (
|
||||
<Grid container spacing={0} direction='column' alignItems='stretch' ref={sizeRef}>
|
||||
<Grid item xs>
|
||||
<NetworkGraph
|
||||
width={width}
|
||||
height={height / 2}
|
||||
graph={data}
|
||||
onTooltip={(node) => {
|
||||
return (
|
||||
<>
|
||||
<strong>WebRTC Peers:</strong> {node.signal.topics.reduce((prev, curr) => prev + curr.peers.length, 0)}
|
||||
<br />
|
||||
{node.kubeStatus.services.map((service) => {
|
||||
return <span key={service.name}><strong>{service.name}:</strong> {service.status}<br /></span>;
|
||||
})}
|
||||
</>);
|
||||
}}
|
||||
/>
|
||||
</Grid>
|
||||
<Grid item xs>
|
||||
<TableContainer>
|
||||
<Table>
|
||||
<TableHead>
|
||||
<TableRow>
|
||||
<TableCell>Signal</TableCell>
|
||||
<TableCell align='right'>Peers (WebRTC)</TableCell>
|
||||
<TableCell align='right'>Kube version</TableCell>
|
||||
<TableCell align='right'>Node.JS version</TableCell>
|
||||
<TableCell align='right'>Memory usage</TableCell>
|
||||
<TableCell align='right'>Memory total</TableCell>
|
||||
<TableCell align='right'>Uptime</TableCell>
|
||||
</TableRow>
|
||||
</TableHead>
|
||||
<TableBody>
|
||||
{data && data.nodes.map(({ data }) => {
|
||||
return <Row key={data.id} row={data} open={open && open === data.id} setOpen={handleOpen} />;
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
</TableContainer>
|
||||
</Grid>
|
||||
</Grid>
|
||||
);
|
||||
}
|
||||
|
||||
export default SignalServers;
|
||||
|
@ -3,8 +3,41 @@
|
||||
#
|
||||
|
||||
query {
|
||||
signal_status @client {
|
||||
timestamp
|
||||
json
|
||||
signal_status: status {
|
||||
id
|
||||
updatedAt,
|
||||
nodes {
|
||||
id
|
||||
kubeStatus {
|
||||
system {
|
||||
memory {
|
||||
total
|
||||
used
|
||||
}
|
||||
|
||||
time {
|
||||
up
|
||||
}
|
||||
|
||||
nodejs {
|
||||
version
|
||||
}
|
||||
}
|
||||
services {
|
||||
name
|
||||
status
|
||||
}
|
||||
}
|
||||
connections {
|
||||
id
|
||||
target
|
||||
}
|
||||
signal {
|
||||
topics {
|
||||
id
|
||||
peers
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"build": {
|
||||
"name": "@dxos/console-app",
|
||||
"buildDate": "2020-08-27T19:33:06.925Z",
|
||||
"version": "1.1.0-beta.1"
|
||||
"buildDate": "2020-10-07T16:33:05.270Z",
|
||||
"version": "1.1.0-beta.6"
|
||||
}
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ services:
|
||||
webui: 'https://kube.local/dxos/wns/console'
|
||||
|
||||
signal:
|
||||
server: 'wss://kube.local/dxos/signal'
|
||||
server: 'wss://kube.local/dxos/signal/api'
|
||||
api: 'https://kube.local/dxos/signal'
|
||||
|
||||
ipfs:
|
||||
|
@ -30,7 +30,7 @@ services:
|
||||
|
||||
signal:
|
||||
server: 'wss://apollo1.kube.moon.dxos.network/dxos/signal'
|
||||
api: 'https://apollo1.kube.moon.dxos.network/dxos/signal'
|
||||
api: 'https://apollo1.kube.moon.dxos.network/dxos/signal/api'
|
||||
|
||||
ipfs:
|
||||
server: 'https://apollo1.kube.moon.dxos.network/dxos/ipfs/api'
|
||||
|
@ -30,7 +30,7 @@ services:
|
||||
|
||||
signal:
|
||||
server: 'ws://127.0.0.1:4000'
|
||||
api: 'http://127.0.0.1:4000'
|
||||
api: 'http://127.0.0.1:4000/api'
|
||||
|
||||
ipfs:
|
||||
server: 'http://127.0.0.1:5001'
|
||||
|
Loading…
Reference in New Issue
Block a user