From 9e56a04804511294118003da4e1dfc2dfc81ce31 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Thu, 30 Nov 2023 03:48:26 -0800 Subject: [PATCH 1/2] feat: PeersTable can be filtered --- src/peers/PeersTable/PeersTable.js | 274 ++++++++++++++++------------- 1 file changed, 150 insertions(+), 124 deletions(-) diff --git a/src/peers/PeersTable/PeersTable.js b/src/peers/PeersTable/PeersTable.js index 58a6f0e5e..93de11880 100644 --- a/src/peers/PeersTable/PeersTable.js +++ b/src/peers/PeersTable/PeersTable.js @@ -1,5 +1,4 @@ -import React from 'react' -import PropTypes from 'prop-types' +import React, { useCallback, useEffect, useMemo, useState } from 'react' import classNames from 'classnames' import ms from 'milliseconds' import { connect } from 'redux-bundler-react' @@ -12,79 +11,60 @@ import { sortByProperty } from '../../lib/sort.js' import './PeersTable.css' -export class PeersTable extends React.Component { - static propTypes = { - peerLocationsForSwarm: PropTypes.array, - className: PropTypes.string, - t: PropTypes.func.isRequired - } - - constructor (props) { - super(props) - - this.state = { - sortBy: 'latency', - sortDirection: SortDirection.ASC, - peerLocationsForSwarm: [] - } - - this.sort = this.sort.bind(this) - } - - flagRenderer = (flagCode, isPrivate) => { - // Check if the OS is Windows to render the flags as SVGs - // Windows doesn't render the flags as emojis ¯\_(ツ)_/¯ - const isWindows = window.navigator.appVersion.indexOf('Win') !== -1 - return ( +const flagRenderer = (flagCode, isPrivate) => { + // Check if the OS is Windows to render the flags as SVGs + // Windows doesn't render the flags as emojis ¯\_(ツ)_/¯ + const isWindows = window.navigator.appVersion.indexOf('Win') !== -1 + return ( {isPrivate ? '🤝' : flagCode ? : '🌐'} - ) - } + ) +} - locationCellRenderer = ({ rowData }) => { - const ref = React.createRef() - const location = rowData.isPrivate - ? this.props.t('localNetwork') - : rowData.location - ? rowData.isNearby - ? {rowData.location} ({this.props.t('nearby')}) - : rowData.location - : {this.props.t('app:terms.unknown')} - const value = rowData.location || this.props.t('app:terms.unknown') - return ( - copyFeedback(ref, this.props.t)}> +const locationCellRenderer = (t) => ({ rowData }) => { + const ref = React.createRef() + const location = rowData.isPrivate + ? t('localNetwork') + : rowData.location + ? rowData.isNearby + ? {rowData.location} ({t('nearby')}) + : rowData.location + : {t('app:terms.unknown')} + const value = rowData.location || t('app:terms.unknown') + return ( + copyFeedback(ref, t)}> - { this.flagRenderer(rowData.flagCode, rowData.isPrivate) } + { flagRenderer(rowData.flagCode, rowData.isPrivate) } { location } - ) - } + ) +} - latencyCellRenderer = ({ cellData, rowData }) => { - const style = { width: '60px' } - const latency = `${cellData}ms` - if (cellData == null) return (-) - return ({latency}) - } +const latencyCellRenderer = ({ cellData }) => { + const style = { width: '60px' } + const latency = `${cellData}ms` + if (cellData == null) return (-) + return ({latency}) +} - peerIdCellRenderer = ({ cellData: peerId }) => { - const ref = React.createRef() - const p2pMultiaddr = `/p2p/${peerId}` - return ( - copyFeedback(ref, this.props.t)}> +const peerIdCellRenderer = (t) => ({ cellData: peerId }) => { + const ref = React.createRef() + const p2pMultiaddr = `/p2p/${peerId}` + return ( + copyFeedback(ref, t)}> - ) - } + ) +} - protocolsCellRenderer = ({ rowData, cellData }) => { - const ref = React.createRef() - const { protocols } = rowData - const title = protocols.split(', ').join('\n') - return ( - copyFeedback(ref, this.props.t)}> +const protocolsCellRenderer = (t) => ({ rowData }) => { + const ref = React.createRef() + const { protocols } = rowData + const title = protocols.split(', ').join('\n') + return ( + copyFeedback(ref, t)}> - ) - } + ) +} - connectionCellRenderer = ({ rowData }) => { - const ref = React.createRef() - const { address, direction, peerId } = rowData - const p2pMultiaddr = `${address}/p2p/${peerId}` - const title = direction != null - ? `${address}\n(${renderDirection(direction, this.props.t)})` - : address +const connectionCellRenderer = (t) => ({ rowData }) => { + const ref = React.createRef() + const { address, direction, peerId } = rowData + const p2pMultiaddr = `${address}/p2p/${peerId}` + const title = direction != null + ? `${address}\n(${renderDirection(direction, t)})` + : address - return ( - copyFeedback(ref, this.props.t)}> + return ( + copyFeedback(ref, t)}> - ) - } - - rowClassRenderer = ({ index }, peers = []) => { - const { selectedPeers } = this.props - const shouldAddHoverEffect = selectedPeers?.peerIds?.includes(peers[index]?.peerId) - - return classNames('bb b--near-white peersTableItem', index === -1 && 'bg-near-white', shouldAddHoverEffect && 'bg-light-gray') - } - - sort ({ sortBy, sortDirection }) { - this.setState({ sortBy, sortDirection }) - } + ) +} - componentWillReceiveProps (nextProps) { - if (nextProps.peerLocationsForSwarm) { - nextProps.peerLocationsForSwarm?.then?.((peerLocationsForSwarm) => { - if (peerLocationsForSwarm !== this.state.peerLocationsForSwarm) { - this.setState({ peerLocationsForSwarm }) - } - }) - } - } +const rowClassRenderer = ({ index }, peers = [], selectedPeers) => { + const shouldAddHoverEffect = selectedPeers?.peerIds?.includes(peers[index]?.peerId) - render () { - const { className, t } = this.props - const { sortBy, sortDirection, peerLocationsForSwarm } = this.state + return classNames('bb b--near-white peersTableItem', index === -1 && 'bg-near-white', shouldAddHoverEffect && 'bg-light-gray') +} - const sortedList = peerLocationsForSwarm.sort(sortByProperty(sortBy, sortDirection === SortDirection.ASC ? 1 : -1)) - const tableHeight = 400 +const FilterInput = ({ setFilter, t, filteredCount }) => { + return ( +
+ setFilter(e.target.value)} + /> + {/* Now to display the total number of peers filtered out on the right side of the inside of the input */} +
{filteredCount}
+
+ ) +} - return ( -
- { peerLocationsForSwarm && +export const PeersTable = ({ className, t, peerLocationsForSwarm, selectedPeers }) => { + const tableHeight = 400 + const [awaitedPeerLocationsForSwarm, setAwaitedPeerLocationsForSwarm] = useState([]) + const [sortBy, setSortBy] = useState('latency') + const [sortDirection, setSortDirection] = useState(SortDirection.ASC) + const [filter, setFilter] = useState('') + + const sort = useCallback(({ sortBy, sortDirection }) => { + setSortBy(sortBy) + setSortDirection(sortDirection) + }, []) + const filterCb = useCallback((value) => { + setFilter(value) + }, []) + + useEffect(() => { + peerLocationsForSwarm?.then?.((peerLocationsForSwarm) => { + setAwaitedPeerLocationsForSwarm(peerLocationsForSwarm) + }) + }, [peerLocationsForSwarm]) + + const filteredPeerList = useMemo(() => { + const filterLower = filter.toLowerCase() + if (filterLower === '') return awaitedPeerLocationsForSwarm + return awaitedPeerLocationsForSwarm.filter(({ location, latency, peerId, connection, protocols }) => { + if (location != null && location.toLowerCase().includes(filterLower)) { + return true + } + if (latency != null && [latency, `${latency}ms`].some((str) => str.toString().includes(filterLower))) { + return true + } + if (peerId != null && peerId.toString().includes(filter)) { + return true + } + console.log('connection: ', connection) + if (connection != null && connection.toLowerCase().includes(filterLower)) { + return true + } + if (protocols != null && protocols.toLowerCase().includes(filterLower)) { + return true + } + + return false + }) + }, [awaitedPeerLocationsForSwarm, filter]) + + const sortedList = useMemo( + () => filteredPeerList.sort(sortByProperty(sortBy, sortDirection === SortDirection.ASC ? 1 : -1)), + [filteredPeerList, sortBy, sortDirection] + ) + + return ( +
+ + { awaitedPeerLocationsForSwarm && {({ width }) => ( - this.rowClassRenderer(rowInfo, peerLocationsForSwarm)} - width={width} - height={tableHeight} - headerHeight={32} - rowHeight={36} - rowCount={peerLocationsForSwarm.length} - rowGetter={({ index }) => sortedList[index]} - sort={this.sort} - sortBy={sortBy} - sortDirection={sortDirection}> - - - - - -
+ <> + rowClassRenderer(rowInfo, awaitedPeerLocationsForSwarm, selectedPeers)} + width={width} + height={tableHeight} + headerHeight={32} + rowHeight={36} + rowCount={sortedList.length} + rowGetter={({ index }) => sortedList[index]} + sort={sort} + sortBy={sortBy} + sortDirection={sortDirection}> + + + + + +
+ )}
}
- ) - } + ) } // API returns integer atm, but that may change in the future From 108ab0cf241f7c07b5c99e228d5e05a77457e4f9 Mon Sep 17 00:00:00 2001 From: Russell Dempsey <1173416+SgtPooki@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:36:46 -0800 Subject: [PATCH 2/2] fix: error loading scaleway template URL --- src/constants/pinning.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/constants/pinning.js b/src/constants/pinning.js index 7d13134fc..128836b85 100644 --- a/src/constants/pinning.js +++ b/src/constants/pinning.js @@ -57,10 +57,15 @@ const pinningServiceTemplates = [ visitServiceUrl: 'https://www.scaleway.com/en/docs/labs/ipfs/api-cli/ipfs-desktop/' } ].map((service) => { - const domain = new URL(service.apiEndpoint).hostname - service.complianceReportUrl = `${complianceReportsHomepage}/${domain}.html` - return service -}).map(service => ({ service, sort: Math.random() })).sort((a, b) => a.sort - b.sort).map(({ service }) => service) + try { + const domain = new URL(service.apiEndpoint).hostname + service.complianceReportUrl = `${complianceReportsHomepage}/${domain}.html` + } catch (e) { + // if apiEndpoint is not a valid URL, don't add complianceReportUrl + // TODO: fix support for template apiEndpoints + } + return { service, sort: Math.random() } +}).sort((a, b) => a.sort - b.sort).map(({ service }) => service) export { complianceReportsHomepage,