Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
256731a
Structurally update the homepage to be tsx and hooks
ckniffen Jan 13, 2024
3699293
switched Ledgers.jsx to tsx and hooks
ckniffen Jan 13, 2024
085d05e
LedgerMetrics using hooks and typescript
ckniffen Jan 13, 2024
8e2011e
Fix tests and ledger hash output
ckniffen Jan 16, 2024
80e0cdd
refactor: Tooltip to hooks and Typescript
ckniffen Jan 17, 2024
b4a4845
additional tooltip cleanup
ckniffen Jan 17, 2024
c38355c
Merge branch 'refactor/tooltip-tsx-hooks' into refactor/homepage-tsx
ckniffen Jan 18, 2024
1b4439e
fix bug after merging tooltip PR
ckniffen Jan 18, 2024
b12f8a5
fix validator tool bug after merge
ckniffen Jan 18, 2024
55e2183
moved useTooltip to be along side Tooltip
ckniffen Jan 18, 2024
85f7113
optimize through useMemo and fix validator hexagon tooltip.
ckniffen Jan 18, 2024
6f1ae86
fix hexagon tooltip
ckniffen Jan 18, 2024
f37f357
Add pausing logic back.
ckniffen Jan 20, 2024
299afbe
Merge branch 'refactor/tooltip-tsx-hooks' into refactor/homepage-tsx
ckniffen Jan 20, 2024
42e46af
Fix linting error and code to appease tsc
ckniffen Jan 20, 2024
272e2c3
Merge branch 'staging' into refactor/tooltip-tsx-hooks
ckniffen Jan 20, 2024
9be4b0d
Merge branch 'refactor/tooltip-tsx-hooks' into refactor/homepage-tsx
ckniffen Jan 22, 2024
0ccd51f
start using new useStreams
ckniffen Jan 22, 2024
8281836
switch useStreams over to using a context to better share state
ckniffen Jan 23, 2024
1e61d0b
request most recent validated ledger on page load to reduce time scre…
ckniffen Jan 24, 2024
3736aaf
refactor network page to use `useStreams`
ckniffen Jan 24, 2024
1dc9690
move getting validators from VHS to a hook and move tooltip provider …
ckniffen Jan 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/containers/App/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
AMENDMENTS_ROUTE,
AMENDMENT_ROUTE,
} from './routes'
import Ledgers from '../Ledgers'
import { LedgersPage as Ledgers } from '../Ledgers'
import { Ledger } from '../Ledger'
import { AccountsRouter } from '../Accounts/AccountsRouter'
import { Transaction } from '../Transactions'
Expand Down
2 changes: 1 addition & 1 deletion src/containers/App/test/App.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Error } from '../../../rippled/lib/utils'

jest.mock('../../Ledgers/LedgerMetrics', () => ({
__esModule: true,
default: () => null,
LedgerMetrics: () => null,
}))

jest.mock('xrpl-client', () => ({
Expand Down
39 changes: 39 additions & 0 deletions src/containers/Ledgers/LedgerEntryHash.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { useTranslation } from 'react-i18next'
import SuccessIcon from '../shared/images/success.svg'
import { LedgerEntryValidation } from './LedgerEntryValidator'
import { LedgerEntryHashTrustedCount } from './LedgerEntryHashTrustedCount'

export const LedgerEntryHash = ({ hash }: { hash: any }) => {
const { t } = useTranslation()
const shortHash = hash.hash.substr(0, 6)
const barStyle = { background: `#${shortHash}` }
const validated = hash.validated && <SuccessIcon className="validated" />
return (
<div
className={`hash ${hash.unselected ? 'unselected' : ''}`}
key={hash.hash}
>
<div className="bar" style={barStyle} />
<div className="ledger-hash">
<div className="hash-concat">{hash.hash.substr(0, 6)}</div>
{validated}
</div>
<div className="subtitle">
<div className="validation-total">
<div>{t('total')}:</div>
<b>{hash.validations.length}</b>
</div>
<LedgerEntryHashTrustedCount validations={hash.validations} />
</div>
<div className="validations">
{hash.validations.map((validation, i) => (
<LedgerEntryValidation
validation={validation}
index={i}
key={`${validation.validation_public_key}_${validation.cookie}`}
/>
))}
</div>
</div>
)
}
60 changes: 60 additions & 0 deletions src/containers/Ledgers/LedgerEntryHashTrustedCount.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { useTranslation } from 'react-i18next'
import classNames from 'classnames'
import { useMemo } from 'react'
import { ValidationStream } from 'xrpl'
import { useTooltip } from '../shared/components/Tooltip'
import { useVHSValidators } from '../shared/components/VHSValidators/VHSValidatorsContext'

export const LedgerEntryHashTrustedCount = ({
validations,
}: {
validations: ValidationStream[]
}) => {
const { t } = useTranslation()
const { hideTooltip, showTooltip } = useTooltip()
const { unl, validators } = useVHSValidators()

const status = useMemo(() => {
const missing = [...(unl || [])]
validations.forEach((v) => {
if (!validators?.[v.validation_public_key]) {
return
}

const missingIndex = missing.findIndex(
(assumedMissing) => assumedMissing === v.validation_public_key,
)
if (missingIndex !== -1) {
missing.splice(missingIndex, 1)
}
})

return {
missing: missing.map((v) => validators?.[v]),
trustedCount: (unl?.length || 0) - missing.length,
}
}, [unl, validations])

return status.trustedCount ? (
<span
tabIndex={0}
role="button"
className={classNames(
status.trustedCount < status.missing.length && 'missed',
)}
onMouseMove={(e) => {
const { missing } = status

missing.length && showTooltip('missing', e, { missing })
}}
onFocus={() => {}}
onKeyUp={() => {}}
onMouseLeave={() => hideTooltip()}
>
<div>{t('unl')}:</div>
<b>
{status.trustedCount}/{unl?.length}
</b>
</span>
) : null
}
34 changes: 34 additions & 0 deletions src/containers/Ledgers/LedgerEntryTransaction.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import classNames from 'classnames'
import { getAction, getCategory } from '../shared/components/Transaction'
import { TRANSACTION_ROUTE } from '../App/routes'
import { TransactionActionIcon } from '../shared/components/TransactionActionIcon/TransactionActionIcon'
import { RouteLink } from '../shared/routing'
import { useTooltip } from '../shared/components/Tooltip'

export const LedgerEntryTransaction = ({
transaction,
}: {
transaction: any
}) => {
const { hideTooltip, showTooltip } = useTooltip()

return (
<RouteLink
key={transaction.hash}
className={classNames(
`txn transaction-type transaction-dot bg`,
`tx-category-${getCategory(transaction.type)}`,
`transaction-action-${getAction(transaction.type)}`,
`${transaction.result}`,
)}
onMouseOver={(e) => showTooltip('tx', e, transaction)}
onFocus={() => {}}
onMouseLeave={() => hideTooltip()}
to={TRANSACTION_ROUTE}
params={{ identifier: transaction.hash }}
>
<TransactionActionIcon type={transaction.type} />
<span>{transaction.hash}</span>
</RouteLink>
)
}
20 changes: 20 additions & 0 deletions src/containers/Ledgers/LedgerEntryTransactions.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { memo } from 'react'
import { Loader } from '../shared/components/Loader'
import { LedgerEntryTransaction } from './LedgerEntryTransaction'

export const LedgerEntryTransactions = memo(
({ transactions }: { transactions: any[] }) => (
<>
{!transactions && <Loader />}
<div className="transactions">
{transactions?.map((tx) => (
<LedgerEntryTransaction transaction={tx} key={tx.hash} />
))}
</div>
</>
),
(prevProps, nextProps) =>
prevProps.transactions &&
nextProps.transactions &&
prevProps.transactions.length === nextProps.transactions.length,
)
49 changes: 49 additions & 0 deletions src/containers/Ledgers/LedgerEntryValidator.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import classNames from 'classnames'
import { useSelectedValidator } from './useSelectedValidator'
import { useTooltip } from '../shared/components/Tooltip'
import { useVHSValidators } from '../shared/components/VHSValidators/VHSValidatorsContext'

export const LedgerEntryValidation = ({
validation,
index,
}: {
validation: any
index: number
}) => {
const { showTooltip, hideTooltip } = useTooltip()
const { selectedValidator, setSelectedValidator } = useSelectedValidator()
const { validators } = useVHSValidators()
const className = classNames(
'validation',
validators?.[validation.validation_public_key]?.unl && 'trusted',
selectedValidator && 'unselected',
selectedValidator === validation.validation_public_key && 'selected',
)

return (
<div
role="button"
tabIndex={index}
className={className}
onMouseOver={(e) =>
showTooltip('validator', e, {
...validation,
v: validators?.[validation.validation_public_key],
})
}
onFocus={() => {}}
onKeyUp={() => {}}
onMouseLeave={() => hideTooltip()}
onClick={() =>
setSelectedValidator(
selectedValidator &&
selectedValidator === validation.validation_public_key
? undefined
: validation.validation_public_key,
)
}
>
{validation.partial && <div className="partial" />}
</div>
)
}
74 changes: 74 additions & 0 deletions src/containers/Ledgers/LedgerListEntry.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useTranslation } from 'react-i18next'
import { RouteLink } from '../shared/routing'
import { LEDGER_ROUTE } from '../App/routes'
import { Amount } from '../shared/components/Amount'
import { LedgerEntryHash } from './LedgerEntryHash'
import { LedgerEntryTransactions } from './LedgerEntryTransactions'
import { Ledger } from '../shared/components/Streams/types'
import {
Tooltip,
TooltipProvider,
useTooltip,
} from '../shared/components/Tooltip'

const SIGMA = '\u03A3'

const LedgerIndex = ({ ledgerIndex }: { ledgerIndex: number }) => {
const { t } = useTranslation()
const flagLedger = ledgerIndex % 256 === 0
return (
<div
className={`ledger-index ${flagLedger ? 'flag-ledger' : ''}`}
title={flagLedger ? t('flag_ledger') : ''}
>
<RouteLink to={LEDGER_ROUTE} params={{ identifier: ledgerIndex }}>
{ledgerIndex}
</RouteLink>
</div>
)
}

export const LedgerListEntryInner = ({ ledger }: { ledger: Ledger }) => {
const { tooltip } = useTooltip()
const { t } = useTranslation()
const time = ledger.closeTime
? new Date(ledger.closeTime).toLocaleTimeString()
: null

return (
<div className="ledger" key={ledger.index}>
<div className="ledger-head">
<LedgerIndex ledgerIndex={ledger.index} />
<div className="close-time">{time}</div>
{/* Render Transaction Count (can be 0) */}
{ledger.txCount !== undefined && (
<div className="txn-count">
{t('txn_count')}:<b>{ledger.txCount.toLocaleString()}</b>
</div>
)}
{/* Render Total Fees (can be 0) */}
{ledger.totalFees !== undefined && (
<div className="fees">
{SIGMA} {t('fees')}:
<b>
<Amount value={{ currency: 'XRP', amount: ledger.totalFees }} />
</b>
</div>
)}
<LedgerEntryTransactions transactions={ledger.transactions} />
</div>
<div className="hashes">
{ledger.hashes.map((hash) => (
<LedgerEntryHash hash={hash} key={hash.hash} />
))}
</div>
<Tooltip tooltip={tooltip} />
</div>
)
}

export const LedgerListEntry = ({ ledger }: { ledger: Ledger }) => (
<TooltipProvider>
<LedgerListEntryInner ledger={ledger} />
</TooltipProvider>
)
Loading