From d06f0698ab8bb3b3293343896400f3715fb53385 Mon Sep 17 00:00:00 2001 From: Lathan Britz Date: Sat, 25 May 2024 00:14:08 -0400 Subject: [PATCH 1/3] sort the nodes table --- src/containers/Network/NodesTable.tsx | 179 +++++++++++++++++---- src/containers/Network/css/nodesTable.scss | 20 +++ 2 files changed, 172 insertions(+), 27 deletions(-) diff --git a/src/containers/Network/NodesTable.tsx b/src/containers/Network/NodesTable.tsx index 6ae11303a..3b8b88c43 100644 --- a/src/containers/Network/NodesTable.tsx +++ b/src/containers/Network/NodesTable.tsx @@ -1,4 +1,4 @@ -import { FC } from 'react' +import { FC, useState } from 'react' import { useTranslation } from 'react-i18next' import { Loader } from '../shared/components/Loader' import { durationToHuman } from '../shared/utils' @@ -15,21 +15,28 @@ const renderLastLedger = (ledger) => ) : ( unknown ) - -const renderLedgerHistory = (ledgers, range) => { +const getLedgerHistory = (ledgers, range, MAX_WIDTH = 160) => { let count = 0 - const MAX_WIDTH = 160 + let boxes = '' const min = Math.max(range[1] - 10000000, range[0]) const diff = range[1] - min if (ledgers) { - const boxes = ledgers.map((l) => { + boxes = ledgers.map((l) => { const [low, high] = l const width = Math.min((high - low + 1) / diff, 1) * MAX_WIDTH const left = Math.max((low - min) / diff, 0) * MAX_WIDTH count += high - low return
}) + } + return { boxes, count } +} +const renderLedgerHistory = (ledgers, range) => { + const MAX_WIDTH = 160 + + if (ledgers) { + const { boxes, count } = getLedgerHistory(ledgers, range, MAX_WIDTH) if (count < 0) { return null @@ -99,19 +106,38 @@ export const NodesTable: FC<{ nodes: NodeData[] }> = ({ }) => { const nodes = unformattedNodes ? formatLedgerHistory(unformattedNodes) : null const ledgerRange = nodes && getLedgerRange(nodes) + const [sortedField, setSortedField] = useState(null) + const [sortOrder, setSortOrder] = useState(null) + + const requestSort = (key) => { + let direction = 'desc' + if (sortedField === key && sortOrder === 'desc') { + direction = 'asc' + } + setSortOrder(direction) + setSortedField(key) + } const { t } = useTranslation() const renderNode = (node) => ( - {node.node_public_key} - {node.ip} - + + {node.node_public_key} + + {node.ip} + {node.server_state} - {getVersion(node.version)} - {renderLastLedger(node.validated_ledger)} - {durationToHuman(node.uptime)} - + + {getVersion(node.version)} + + + {renderLastLedger(node.validated_ledger)} + + + {durationToHuman(node.uptime)} + + {node.inbound_count + node.outbound_count} @@ -119,39 +145,138 @@ export const NodesTable: FC<{ nodes: NodeData[] }> = ({ ({node.inbound_count}:{node.outbound_count}) - + {renderLedgerHistory(node.ledgers, ledgerRange)} - {node.quorum} - + + {node.quorum} + + {node.load_factor && node.load_factor > 1 ? node.load_factor.toFixed(2) : ''} - + {node.io_latency_ms && node.io_latency_ms > 1} ) + if (nodes !== null) { + const sort = (key: any, order: string) => { + const returnValue = order === 'desc' ? 1 : -1 + + if (key === 'peers') { + nodes.sort((a, b) => + a.inbound_count + a.outbound_count > + b.inbound_count + b.outbound_count + ? returnValue * -1 + : returnValue, + ) + } else if (key === 'ledger_history') { + nodes.sort((a, b) => + getLedgerHistory(a.ledgers, ledgerRange).count > + getLedgerHistory(b.ledgers, ledgerRange).count + ? returnValue * -1 + : returnValue, + ) + } else { + nodes.sort((a, b) => (a[key] > b[key] ? returnValue * -1 : returnValue)) + } + } + + // console.log('sortingg....') + // console.log(nodes) + sort(sortedField, sortOrder) + } + + const getClassNamesFor = (name, order) => + sortedField === order ? `${name} sorted` : name + const getClassArrowFor = (field) => { + if (sortedField === field && sortOrder === 'desc') { + return 'arrow down' + } + if (sortedField === field && sortOrder === 'asc') { + return 'arrow up' + } + return '' + } + const content = nodes ? ( - - - - - - - + + + + + + + - - - - + + + + {nodes.map(renderNode)} diff --git a/src/containers/Network/css/nodesTable.scss b/src/containers/Network/css/nodesTable.scss index 7d8757b25..ed1d0962c 100644 --- a/src/containers/Network/css/nodesTable.scss +++ b/src/containers/Network/css/nodesTable.scss @@ -6,6 +6,26 @@ min-height: 150px; table { + .sorted { + background-color: $black-90; + } + + .arrow { + display: inline-block; + padding: 3px; + border: solid $white; + border-width: 0 3px 3px 0; + margin-right: 5px; + } + + .up { + transform: rotate(-135deg); + } + + .down { + transform: rotate(45deg); + } + .pubkey { max-width: 70px; From e8b9d40b360bb2cc43320ba4a77b580abb3926bd Mon Sep 17 00:00:00 2001 From: Lathan Britz Date: Sat, 25 May 2024 10:07:57 -0400 Subject: [PATCH 2/3] version column needed custom sort --- src/containers/Network/NodesTable.tsx | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/containers/Network/NodesTable.tsx b/src/containers/Network/NodesTable.tsx index 3b8b88c43..ac8d83b8d 100644 --- a/src/containers/Network/NodesTable.tsx +++ b/src/containers/Network/NodesTable.tsx @@ -162,6 +162,27 @@ export const NodesTable: FC<{ nodes: NodeData[] }> = ({ ) + const compareSemanticVersions = ( + a: string, + b: string, + returnValue: string, + ) => { + const a1 = a.split('.') + const b1 = b.split('.') + + const len = Math.min(a1.length, b1.length) + + for (let i = 0; i < len; i++) { + const a2 = +a1[i] || 0 + const b2 = +b1[i] || 0 + + if (a2 !== b2) { + return a2 > b2 ? returnValue : returnValue * -1 + } + } + return b1.length - a1.length + } + if (nodes !== null) { const sort = (key: any, order: string) => { const returnValue = order === 'desc' ? 1 : -1 @@ -180,13 +201,15 @@ export const NodesTable: FC<{ nodes: NodeData[] }> = ({ ? returnValue * -1 : returnValue, ) + } else if (key === 'rippled_version') { + nodes.sort((a, b) => + compareSemanticVersions(a.version, b.version, returnValue), + ) } else { nodes.sort((a, b) => (a[key] > b[key] ? returnValue * -1 : returnValue)) } } - // console.log('sortingg....') - // console.log(nodes) sort(sortedField, sortOrder) } From 2771dc9c471956114794f654615393fc8c43db92 Mon Sep 17 00:00:00 2001 From: Lathan Britz Date: Wed, 26 Jun 2024 15:32:11 -0400 Subject: [PATCH 3/3] add tests --- src/containers/Network/NodesTable.tsx | 2 +- src/containers/Network/test/nodes.test.js | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/containers/Network/NodesTable.tsx b/src/containers/Network/NodesTable.tsx index ac8d83b8d..bb20b02ee 100644 --- a/src/containers/Network/NodesTable.tsx +++ b/src/containers/Network/NodesTable.tsx @@ -165,7 +165,7 @@ export const NodesTable: FC<{ nodes: NodeData[] }> = ({ const compareSemanticVersions = ( a: string, b: string, - returnValue: string, + returnValue: number, ) => { const a1 = a.split('.') const b1 = b.split('.') diff --git a/src/containers/Network/test/nodes.test.js b/src/containers/Network/test/nodes.test.js index 7455912d5..30e955e56 100644 --- a/src/containers/Network/test/nodes.test.js +++ b/src/containers/Network/test/nodes.test.js @@ -76,6 +76,19 @@ describe('Nodes Page container', () => { expect(wrapper.find('.nodes-map .tooltip').length).toBe(0) expect(wrapper.find('.nodes-map path.node').length).toBe(2) expect(wrapper.find('.nodes-table table tr').length).toBe(4) + wrapper.find('.nodes-table table th.version a').simulate('click') + const rows = wrapper.find('.nodes-table table tbody tr td.version') + const expected = [ + '', + '', + '', + ] + let index = 0 + rows.forEach((element) => { + expect(element.html()).toBe(expected[index]) + // eslint-disable-next-line no-plusplus + index++ + }) wrapper.unmount() done() })
{t('node_pubkey')}{t('ip')}{t('state')}{t('rippled_version')}{t('last_ledger')}{t('uptime')}{t('peers')} + requestSort('pubkey')}> + + {t('node_pubkey')} + + + requestSort('ip')}> + + {t('ip')} + + + requestSort('server_state')}> + + {t('state')} + + + requestSort('rippled_version')}> + + {t('rippled_version')}{' '} + + + requestSort('last_ledger')}> + + {t('last_ledger')} + + + requestSort('uptime')}> + + {t('uptime')} + + + requestSort('peers')}> + + {t('peers')} + + {t('in_out')} {t('ledger_history')}{t('quorum')}{t('load')}{t('latency')} + requestSort('ledger_history')}> + + {t('ledger_history')} + + + requestSort('quorum')}> + + {t('quorum')} + + + requestSort('load')}> + + {t('load')} + + + requestSort('latency')}> + + {t('latency')} + +
1.1.21.2.0-rc21.2.0-rc2