Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for filtering latest TX list for method type #1679

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
1 change: 1 addition & 0 deletions .changelog/1679.trivial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add support for filtering transactions by method type
260 changes: 149 additions & 111 deletions src/app/components/ConsensusTransactionMethod/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import Tooltip from '@mui/material/Tooltip'
import { tooltipDelay } from '../../../styles/theme'
import { ConsensusTxMethod } from '../../../oasis-nexus/api'
import { COLORS } from '../../../styles/theme/colors'
import { SelectOptionBase } from '../Select'
import { exhaustedTypeWarning } from '../../../types/errors'

type MethodIconProps = {
border?: boolean
Expand Down Expand Up @@ -170,6 +172,135 @@ const MethodIconWithTruncatedLabel: FC<MethodIconProps> = props => {
)
}

const getConsensusTransactionLabel = (t: TFunction, method: ConsensusTxMethod | undefined): string => {
// Please note: when updating this, keep it in sync
// with the knownConsensusTxMethods array below!

switch (method) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't this be better if there was an object map, having O(1) time complexity looking up each of the elements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe. We have the exact same system for Runtime transactions, here, introduced ages ago. If we want to refactor this, it should be done consistently, on both ends.

However it's not entirely trivial because we need to rely on a t function, which is not available by default in the module namespace, so we can only prepare the object map when the first call happens. Then maybe we can try to cache and reuse it, but I feel that this might be premature optimization and opens the possibility of race conditions at the time of first rendering... not sure it's worth the effort.

What do you think?

case ConsensusTxMethod.stakingTransfer:
return t('transactions.method.stakingTransfer')
case ConsensusTxMethod.stakingAddEscrow:
return t('transactions.method.stakingAddEscrow')
case ConsensusTxMethod.stakingReclaimEscrow:
return t('transactions.method.stakingReclaimEscrow')
case ConsensusTxMethod.stakingAmendCommissionSchedule:
return t('transactions.method.stakingAmendCommissionSchedule')
case ConsensusTxMethod.stakingAllow:
return t('transactions.method.stakingAllow')
case ConsensusTxMethod.stakingWithdraw:
return t('transactions.method.stakingWithdraw')
case ConsensusTxMethod.roothashExecutorCommit:
return t('transactions.method.roothashExecutorCommit')
case ConsensusTxMethod.roothashExecutorProposerTimeout:
return t('transactions.method.roothashExecutorProposerTimeout')
case ConsensusTxMethod.registryRegisterEntity:
return t('transactions.method.registryRegisterEntity')
case ConsensusTxMethod.registryRegisterNode:
return t('transactions.method.registryRegisterNode')
case ConsensusTxMethod.registryRegisterRuntime:
return t('transactions.method.registryRegisterRuntime')
case ConsensusTxMethod.governanceCastVote:
return t('transactions.method.governanceCastVote')
case ConsensusTxMethod.governanceSubmitProposal:
return t('transactions.method.governanceSubmitProposal')
case ConsensusTxMethod.beaconPVSSCommit:
return t('transactions.method.beaconPVSSCommit')
case ConsensusTxMethod.beaconPVSSReveal:
return t('transactions.method.beaconPVSSReveal')
case ConsensusTxMethod.beaconVRFProve:
return t('transactions.method.beaconVRFProve')
case ConsensusTxMethod.consensusMeta:
return t('transactions.method.consensus.meta')
case ConsensusTxMethod.keymanagerPublishEphemeralSecret:
return t('transactions.method.keyManager.publishEphemeralSecret')
case ConsensusTxMethod.keymanagerPublishMasterSecret:
return t('transactions.method.keyManager.publishMasterSecret')
case ConsensusTxMethod.keymanagerUpdatePolicy:
return t('transactions.method.keyManager.updatePolicy')
case ConsensusTxMethod['keymanager/churpApply']:
return t('transactions.method.keyManager.churp.apply')
case ConsensusTxMethod['keymanager/churpConfirm']:
return t('transactions.method.keyManager.churp.confirm')
case ConsensusTxMethod['keymanager/churpCreate']:
return t('transactions.method.keyManager.churp.create')
case ConsensusTxMethod['keymanager/churpUpdate']:
return t('transactions.method.keyManager.churp.update')
case ConsensusTxMethod.registryDeregisterEntity:
return t('transactions.method.registryDeregisterEntity')
case ConsensusTxMethod.registryProveFreshness:
return t('transactions.method.registryProveFreshness')
case ConsensusTxMethod.registryUnfreezeNode:
return t('transactions.method.registryUnfreezeNode')
case ConsensusTxMethod.roothashEvidence:
return t('transactions.method.roothashEvidence')
case ConsensusTxMethod.roothashSubmitMsg:
return t('transactions.method.roothashSubmitMessage')
case ConsensusTxMethod.stakingBurn:
return t('transactions.method.stakingBurn')
case ConsensusTxMethod.vaultAuthorizeAction:
return t('transactions.method.vault.authorizeAction')
case ConsensusTxMethod.vaultCancelAction:
return t('transactions.method.vault.cancelAction')
case ConsensusTxMethod.vaultCreate:
return t('transactions.method.vault.create')
case undefined:
return t('common.missing')
default:
exhaustedTypeWarning('Unexpected consensus transaction method', method)
return method || t('common.unknown')
csillag marked this conversation as resolved.
Show resolved Hide resolved
}
}

// List of known consensus ts types, to offer in filter
// Please keep them in alphabetical order
const knownConsensusTxMethods = [
ConsensusTxMethod.stakingAllow,
ConsensusTxMethod.stakingAmendCommissionSchedule,
ConsensusTxMethod.governanceCastVote,
ConsensusTxMethod.stakingBurn,
ConsensusTxMethod.consensusMeta,
ConsensusTxMethod.stakingWithdraw,
ConsensusTxMethod.registryDeregisterEntity,
ConsensusTxMethod.roothashExecutorCommit,
ConsensusTxMethod.roothashExecutorProposerTimeout,
ConsensusTxMethod['keymanager/churpApply'],
ConsensusTxMethod['keymanager/churpConfirm'],
ConsensusTxMethod['keymanager/churpCreate'],
ConsensusTxMethod['keymanager/churpUpdate'],
ConsensusTxMethod.keymanagerPublishEphemeralSecret,
ConsensusTxMethod.keymanagerPublishMasterSecret,
ConsensusTxMethod.keymanagerUpdatePolicy,
ConsensusTxMethod.beaconPVSSCommit,
ConsensusTxMethod.beaconPVSSReveal,
ConsensusTxMethod.registryRegisterEntity,
ConsensusTxMethod.registryRegisterNode,
ConsensusTxMethod.registryRegisterRuntime,
ConsensusTxMethod.registryProveFreshness,
ConsensusTxMethod.registryUnfreezeNode,
ConsensusTxMethod.roothashEvidence,
ConsensusTxMethod.roothashSubmitMsg,
ConsensusTxMethod.stakingAddEscrow,
ConsensusTxMethod.stakingReclaimEscrow,
ConsensusTxMethod.governanceSubmitProposal,
ConsensusTxMethod.stakingTransfer,
ConsensusTxMethod.beaconVRFProve,
ConsensusTxMethod.vaultAuthorizeAction,
ConsensusTxMethod.vaultCancelAction,
ConsensusTxMethod.vaultCreate,
] satisfies ConsensusTxMethod[]

// eslint-disable-next-line @typescript-eslint/no-unused-vars
const typeTestExhaustiveArray =
undefined as unknown as ConsensusTxMethod satisfies (typeof knownConsensusTxMethods)[number]

export const getConsensusTxMethodOptions = (t: TFunction): SelectOptionBase[] =>
knownConsensusTxMethods.map(
(method): SelectOptionBase => ({
value: method,
label: getConsensusTransactionLabel(t, method),
}),
)

const getConsensusTransactionMethod = (
t: TFunction,
method: ConsensusTxMethod | undefined,
Expand All @@ -178,135 +309,42 @@ const getConsensusTransactionMethod = (
const props = {
truncate,
}
const label = getConsensusTransactionLabel(t, method)
switch (method) {
case ConsensusTxMethod.stakingTransfer:
return (
<MethodIcon
color="green"
icon={<ArrowForwardIcon />}
label={t('transactions.method.stakingTransfer')}
{...props}
/>
)
return <MethodIcon color="green" icon={<ArrowForwardIcon />} label={label} {...props} />
case ConsensusTxMethod.stakingAddEscrow:
return (
<MethodIcon
color="green"
icon={<ExitToAppIcon />}
label={t('transactions.method.stakingAddEscrow')}
{...props}
/>
)
return <MethodIcon color="green" icon={<ExitToAppIcon />} label={label} {...props} />
case ConsensusTxMethod.stakingReclaimEscrow:
return (
<MethodIcon
icon={<ExitToAppIcon />}
label={t('transactions.method.stakingReclaimEscrow')}
{...props}
/>
)
return <MethodIcon icon={<ExitToAppIcon />} label={label} {...props} />
case ConsensusTxMethod.stakingAmendCommissionSchedule:
return (
<MethodIcon
icon={<PriceChangeIcon />}
label={t('transactions.method.stakingAmendCommissionSchedule')}
{...props}
/>
)
return <MethodIcon icon={<PriceChangeIcon />} label={label} {...props} />
case ConsensusTxMethod.stakingAllow:
return (
<MethodIcon icon={<LibraryAddCheckIcon />} label={t('transactions.method.stakingAllow')} {...props} />
)
return <MethodIcon icon={<LibraryAddCheckIcon />} label={label} {...props} />
case ConsensusTxMethod.stakingWithdraw:
return (
<MethodIcon
color="green"
icon={<ArrowDownwardIcon />}
label={t('transactions.method.stakingWithdraw')}
{...props}
/>
)
return <MethodIcon color="green" icon={<ArrowDownwardIcon />} label={label} {...props} />
case ConsensusTxMethod.roothashExecutorCommit:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.roothashExecutorCommit')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
case ConsensusTxMethod.roothashExecutorProposerTimeout:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.roothashExecutorProposerTimeout')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
case ConsensusTxMethod.registryRegisterEntity:
return (
<MethodIcon
icon={<PersonIcon />}
label={t('transactions.method.registryRegisterEntity')}
{...props}
/>
)
return <MethodIcon icon={<PersonIcon />} label={label} {...props} />
case ConsensusTxMethod.registryRegisterNode:
return (
<MethodIcon icon={<DnsIcon />} label={t('transactions.method.registryRegisterNode')} {...props} />
)
return <MethodIcon icon={<DnsIcon />} label={label} {...props} />
case ConsensusTxMethod.registryRegisterRuntime:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.registryRegisterRuntime')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
case ConsensusTxMethod.governanceCastVote:
return (
<MethodIcon icon={<HowToVoteIcon />} label={t('transactions.method.governanceCastVote')} {...props} />
)
return <MethodIcon icon={<HowToVoteIcon />} label={label} {...props} />
case ConsensusTxMethod.governanceSubmitProposal:
return (
<MethodIcon
icon={<AccountBalanceIcon />}
label={t('transactions.method.governanceSubmitProposal')}
{...props}
/>
)
return <MethodIcon icon={<AccountBalanceIcon />} label={label} {...props} />
case ConsensusTxMethod.beaconPVSSCommit:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.beaconPVSSCommit')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
case ConsensusTxMethod.beaconPVSSReveal:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.beaconPVSSReveal')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
case ConsensusTxMethod.beaconVRFProve:
return (
<MethodIcon
icon={<MiscellaneousServicesIcon />}
label={t('transactions.method.beaconVRFProve')}
{...props}
/>
)
return <MethodIcon icon={<MiscellaneousServicesIcon />} label={label} {...props} />
default:
return (
<MethodIcon
color="gray"
icon={<QuestionMarkIcon />}
label={method || t('common.unknown')}
{...props}
/>
)
return <MethodIcon color="gray" icon={<QuestionMarkIcon />} label={label} {...props} />
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/app/components/LinkableCardLayout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ type LinkableCardLayoutProps = {
children: ReactNode
containerId: string
title: ReactNode
action?: ReactNode | undefined
}
export const LinkableCardLayout: FC<LinkableCardLayoutProps> = ({ children, containerId, title }) => {
export const LinkableCardLayout: FC<LinkableCardLayoutProps> = ({ children, containerId, title, action }) => {
return (
<Card>
<LinkableDiv id={containerId}>
<CardHeader disableTypography component="h3" title={title} />
<CardHeader disableTypography component="h3" title={title} action={action} />
</LinkableDiv>
<CardContent>
<ErrorBoundary light={true}>{children}</ErrorBoundary>
Expand Down
28 changes: 26 additions & 2 deletions src/app/components/RuntimeTransactionMethod/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,16 @@ import LanIcon from '@mui/icons-material/Lan'
import LanOutlinedIcon from '@mui/icons-material/LanOutlined'
import { MethodIcon } from '../ConsensusTransactionMethod'
import { RuntimeTransaction } from '../../../oasis-nexus/api'
import { SelectOptionBase } from '../Select'

const getRuntimeTransactionLabel = (t: TFunction, method: string | undefined) => {
// TODO: when adding new types here, please also update knownRuntimeTxMethods below.
switch (method) {
case undefined:
// Method may be undefined if the transaction was malformed.
return t('transactions.method.unavailable')
case 'accounts.Transfer':
return t('transactions.method.accounts.transfer')
case 'evm.Call':
return t('transactions.method.evm.call')
case 'evm.Create':
Expand All @@ -26,8 +30,6 @@ const getRuntimeTransactionLabel = (t: TFunction, method: string | undefined) =>
return t('transactions.method.consensus.deposit')
case 'consensus.Withdraw':
return t('transactions.method.consensus.withdraw')
case 'accounts.Transfer':
return t('transactions.method.accounts.transfer')
case 'consensus.Delegate':
return t('transactions.method.consensus.delegate')
case 'consensus.Undelegate':
Expand All @@ -45,6 +47,28 @@ const getRuntimeTransactionLabel = (t: TFunction, method: string | undefined) =>
}
}

const knownRuntimeTxMethods: string[] = [
'accounts.Transfer',
'evm.Call',
'evm.Create',
'consensus.Deposit',
'consensus.Withdraw',
'consensus.Delegate',
'consensus.Undelegate',
'rofl.Create',
'rofl.Register',
'rofl.Remove',
'rofl.Update',
]

export const getRuntimeTxMethodOptions = (t: TFunction): SelectOptionBase[] =>
knownRuntimeTxMethods.map(
(method): SelectOptionBase => ({
value: method,
label: getRuntimeTransactionLabel(t, method),
}),
)

/**
* The method call body. Defined by the runtime.
*
Expand Down
Loading
Loading