| 1 | import './list.css' |
| 2 | import { useState } from 'react' |
| 3 | import disclosureTriangleClosed from '../../../public/img/icon-disclosure-triangle-closed.svg' |
| 4 | import disclosureTriangleOpen from '../../../public/img/icon-disclosure-triangle-open.svg' |
| 5 | import { getAgent } from '../../utils/get-agent.js' |
| 6 | import { DeleteIcon } from '../icons/icon-delete.js' |
| 7 | import { SpinnerIcon } from '../icons/icon-spinner.js' |
| 8 | import { MultiaddrList } from '../multiaddr-list.js' |
| 9 | import { Panel } from '../panel.js' |
| 10 | import type { Peer as PeerType, MetricsRPC } from '@ipshipyard/libp2p-inspector-metrics' |
| 11 | import type { ReactElement } from 'react' |
| 12 | |
| 13 | export interface PeersProps { |
| 14 | peers: PeerType[] |
| 15 | metrics: MetricsRPC |
| 16 | } |
| 17 | |
| 18 | export function PeerList ({ peers, metrics }: PeersProps): ReactElement { |
| 19 | if (peers.length === 0) { |
| 20 | return ( |
| 21 | <Panel> |
| 22 | <p>This node is not connected to any peers.</p> |
| 23 | </Panel> |
| 24 | ) |
| 25 | } |
| 26 | |
| 27 | return ( |
| 28 | <> |
| 29 | { |
| 30 | peers.map(peer => <Peer key={peer.id.toString()} peer={peer} metrics={metrics} />) |
| 31 | } |
| 32 | </> |
| 33 | ) |
| 34 | } |
| 35 | |
| 36 | interface PeerProps { |
| 37 | peer: PeerType |
| 38 | metrics: MetricsRPC |
| 39 | key?: string |
| 40 | } |
| 41 | |
| 42 | function Peer ({ peer, metrics }: PeerProps): ReactElement { |
| 43 | const [expanded, setExpanded] = useState(false) |
| 44 | const [disconnecting, setDisconnecting] = useState(false) |
| 45 | |
| 46 | function closeConnection (evt: any): void { |
| 47 | evt.preventDefault() |
| 48 | |
| 49 | setDisconnecting(true) |
| 50 | metrics.closeConnection(peer.id) |
| 51 | .catch(err => { |
| 52 | // eslint-disable-next-line |
| 53 | console.error('could not close connection', err) |
| 54 | }) |
| 55 | .finally(() => { |
| 56 | setDisconnecting(false) |
| 57 | }) |
| 58 | } |
| 59 | |
| 60 | let disconnectIcon = <DeleteIcon onClick={closeConnection} /> |
| 61 | |
| 62 | if (disconnecting) { |
| 63 | disconnectIcon = <SpinnerIcon /> |
| 64 | } |
| 65 | |
| 66 | if (expanded) { |
| 67 | return ( |
| 68 | <Panel> |
| 69 | <h2><img src={disclosureTriangleOpen} height={12} width={12} className='DisclosureTriangle' onClick={() => { setExpanded(false) }} /> {disconnectIcon} <PeerAgent peer={peer} /> <span className='PeerId'>{peer.id.toString()}</span></h2> |
| 70 | <p> |
| 71 | <PeerTags peer={peer} /> |
| 72 | </p> |
| 73 | <h3>Multiaddrs</h3> |
| 74 | <MultiaddrList addresses={peer.addresses} includeCertification /> |
| 75 | <PeerProtocols peer={peer} /> |
| 76 | </Panel> |
| 77 | ) |
| 78 | } |
| 79 | |
| 80 | return ( |
| 81 | <Panel> |
| 82 | <h2><img src={disclosureTriangleClosed} height={12} width={12} className='DisclosureTriangle' onClick={() => { setExpanded(true) }} /> {disconnectIcon} <PeerAgent peer={peer} /> <span className='PeerId'>{peer.id.toString()}</span></h2> |
| 83 | <p> |
| 84 | <PeerTags peer={peer} /> |
| 85 | </p> |
| 86 | </Panel> |
| 87 | ) |
| 88 | } |
| 89 | |
| 90 | function PeerAgent ({ peer }: Pick<PeerProps, 'peer'>): ReactElement | undefined { |
| 91 | if (peer.metadata.AgentVersion == null) { |
| 92 | return undefined |
| 93 | } |
| 94 | |
| 95 | return ( |
| 96 | <span className='PeerAgent'>{getAgent(peer.metadata)}</span> |
| 97 | ) |
| 98 | } |
| 99 | |
| 100 | function PeerTags ({ peer }: Pick<PeerProps, 'peer'>): ReactElement | undefined { |
| 101 | const entries = Object.entries(peer.tags) |
| 102 | |
| 103 | if (entries.length === 0) { |
| 104 | return undefined |
| 105 | } |
| 106 | |
| 107 | return ( |
| 108 | <> |
| 109 | {entries.map(([key, value], index) => <span key={index} className='PeerTag'>{key}</span>)} |
| 110 | </> |
| 111 | ) |
| 112 | } |
| 113 | |
| 114 | function PeerProtocols ({ peer }: Pick<PeerProps, 'peer'>): ReactElement | undefined { |
| 115 | if (peer.protocols.length === 0) { |
| 116 | return undefined |
| 117 | } |
| 118 | |
| 119 | return ( |
| 120 | <> |
| 121 | <h3>Protocols</h3> |
| 122 | <ul> |
| 123 | {peer.protocols.map((proto, index) => <li key={`proto-${index}`}>{proto}</li>)} |
| 124 | </ul> |
| 125 | </> |
| 126 | ) |
| 127 | } |