Skip to content

Commit

Permalink
Proposal votes: add search by validator name
Browse files Browse the repository at this point in the history
  • Loading branch information
csillag committed May 9, 2024
1 parent f7c92ce commit 9b2a36a
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 16 deletions.
1 change: 0 additions & 1 deletion src/app/components/Search/TableSearchBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import InputAdornment from '@mui/material/InputAdornment'
import { COLORS } from '../../../styles/theme/colors'
import IconButton from '@mui/material/IconButton'
import { useScreenSize } from '../../hooks/useScreensize'
import Box from '@mui/material/Box'
import WarningIcon from '@mui/icons-material/WarningAmber'
import { typingDelay } from '../../../styles/theme'
import Typography from '@mui/material/Typography'
Expand Down
12 changes: 10 additions & 2 deletions src/app/components/Validators/DeferredValidatorLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,20 @@ export const DeferredValidatorLink: FC<{
address: string
validator: Validator | undefined
isError: boolean
}> = ({ network, address, validator, isError }) => {
highlightedPart?: string | undefined
}> = ({ network, address, validator, isError, highlightedPart }) => {
const scope: SearchScope = { network, layer: Layer.consensus }

if (isError) {
console.log('Warning: failed to look up validators!')
}

return <ValidatorLink address={address} network={scope.network} name={validator?.media?.name} />
return (
<ValidatorLink
address={address}
network={scope.network}
name={validator?.media?.name}
highlightedPart={highlightedPart}
/>
)
}
40 changes: 31 additions & 9 deletions src/app/components/Validators/ValidatorLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,37 @@ import { RouteUtils } from '../../utils/route-utils'
import Typography from '@mui/material/Typography'
import { COLORS } from '../../../styles/theme/colors'
import { Network } from '../../../types/network'
import { HighlightedText } from '../HighlightedText'

type ValidatorLinkProps = {
address: string
name?: string
network: Network
alwaysTrim?: boolean
highlightedPart?: string
}

export const ValidatorLink: FC<ValidatorLinkProps> = ({ address, name, network, alwaysTrim }) => {
export const ValidatorLink: FC<ValidatorLinkProps> = ({
address,
name,
network,
alwaysTrim,
highlightedPart,
}) => {
const { isTablet } = useScreenSize()
const to = RouteUtils.getValidatorRoute(network, address)
return (
<Typography variant="mono" component="span" sx={{ color: COLORS.brandDark, fontWeight: 700 }}>
{isTablet ? (
<TabletValidatorLink address={address} name={name} to={to} />
<TabletValidatorLink address={address} name={name} to={to} highlightedPart={highlightedPart} />
) : (
<DesktopValidatorLink address={address} alwaysTrim={alwaysTrim} name={name} to={to} />
<DesktopValidatorLink
address={address}
alwaysTrim={alwaysTrim}
name={name}
to={to}
highlightedPart={highlightedPart}
/>
)}
</Typography>
)
Expand All @@ -32,21 +46,23 @@ export const ValidatorLink: FC<ValidatorLinkProps> = ({ address, name, network,
type TrimValidatorEndLinkLabelProps = {
name: string
to: string
highlightedPart?: string
}

const TrimValidatorEndLinkLabel: FC<TrimValidatorEndLinkLabelProps> = ({ name, to }) => (
<TrimEndLinkLabel label={name} to={to} trimStart={14} />
const TrimValidatorEndLinkLabel: FC<TrimValidatorEndLinkLabelProps> = ({ name, to, highlightedPart }) => (
<TrimEndLinkLabel label={name} to={to} trimStart={14} highlightedPart={highlightedPart} />
)

type TabletValidatorLinkProps = {
address: string
name?: string
to: string
highlightedPart?: string
}

const TabletValidatorLink: FC<TabletValidatorLinkProps> = ({ address, name, to }) => {
const TabletValidatorLink: FC<TabletValidatorLinkProps> = ({ address, name, to, highlightedPart }) => {
if (name) {
return <TrimValidatorEndLinkLabel name={name} to={to} />
return <TrimValidatorEndLinkLabel name={name} to={to} highlightedPart={highlightedPart} />
}
return <TrimLinkLabel label={address} to={to} />
}
Expand All @@ -55,13 +71,19 @@ type DesktopValidatorLinkProps = TabletValidatorLinkProps & {
alwaysTrim?: boolean
}

const DesktopValidatorLink: FC<DesktopValidatorLinkProps> = ({ address, name, to, alwaysTrim }) => {
const DesktopValidatorLink: FC<DesktopValidatorLinkProps> = ({
address,
name,
to,
alwaysTrim,
highlightedPart,
}) => {
if (alwaysTrim) {
return <TrimLinkLabel label={address} to={to} />
}
return (
<Link component={RouterLink} to={to}>
{name ?? address}
{name ? <HighlightedText text={name} pattern={highlightedPart} /> : address}
</Link>
)
}
40 changes: 37 additions & 3 deletions src/app/pages/ProposalDetailsPage/ProposalVotesCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,24 @@ import { TablePaginationProps } from '../../components/Table/TablePagination'
import { useTranslation } from 'react-i18next'
import { Table, TableCellAlign, TableColProps } from '../../components/Table'
import { ExtendedVote, ProposalVoteValue } from '../../../types/vote'
import { PAGE_SIZE, useAllVotes, useDisplayedVotes, useWantedVoteType } from './hooks'
import {
PAGE_SIZE,
useAllVotes,
useDisplayedVotes,
useVoteFilters,
useVoterSearch,
useVoterSearchError,
useVoterSearchPattern,
useWantedVoteType,
} from './hooks'
import { ProposalVoteIndicator } from '../../components/Proposals/ProposalVoteIndicator'
import { DeferredValidatorLink } from '../../components/Validators/DeferredValidatorLink'
import { CardHeaderWithResponsiveActions } from '../../components/CardHeaderWithResponsiveActions'
import { VoteTypeFilter } from '../../components/Proposals/VoteTypeFilter'
import { AppErrors } from '../../../types/errors'
import { ErrorBoundary } from '../../components/ErrorBoundary'
import Box from '@mui/material/Box'
import { NoMatchingDataMaybeClearFilters, TableSearchBar } from '../../components/Search/TableSearchBar'

type ProposalVotesProps = {
isLoading: boolean
Expand All @@ -25,6 +36,8 @@ const ProposalVotes: FC<ProposalVotesProps> = ({ isLoading, votes, rowsNumber, p
const { t } = useTranslation()
const scope = useRequiredScopeParam()

const voterNameFragment = useVoterSearchPattern()

const tableColumns: TableColProps[] = [
{ key: 'index', content: <></>, width: '50px' },
{ key: 'voter', content: t('common.voter'), align: TableCellAlign.Left },
Expand All @@ -46,6 +59,7 @@ const ProposalVotes: FC<ProposalVotesProps> = ({ isLoading, votes, rowsNumber, p
address={vote.address}
isError={vote.haveValidatorsFailed}
validator={vote.validator}
highlightedPart={voterNameFragment}
/>
),
},
Expand Down Expand Up @@ -79,11 +93,19 @@ export const ProposalVotesView: FC = () => {

const { isLoading } = useAllVotes(network, proposalId)
const displayedVotes = useDisplayedVotes(network, proposalId)
const [hasFilters, clearFilters] = useVoteFilters()

const onFirstPage = displayedVotes.tablePaginationProps.selectedPage === 1
const hasData = !!displayedVotes.data?.length

if (!isLoading && displayedVotes.tablePaginationProps.selectedPage > 1 && !displayedVotes.data?.length) {
if (!isLoading && !onFirstPage && !hasData) {
throw AppErrors.PageDoesNotExist
}

if (!isLoading && onFirstPage && !hasData && hasFilters) {
return <NoMatchingDataMaybeClearFilters clearFilters={clearFilters} />
}

return (
<ProposalVotes
isLoading={isLoading}
Expand All @@ -98,11 +120,23 @@ export const ProposalVotesCard: FC = () => {
const { t } = useTranslation()

const [wantedVoteType, setWantedVoteType] = useWantedVoteType()
const [voterSearchInput, setVoterSearchPattern] = useVoterSearch()
const searchError = useVoterSearchError(t)

return (
<SubPageCard>
<CardHeaderWithResponsiveActions
action={<VoteTypeFilter onSelect={setWantedVoteType} value={wantedVoteType} />}
action={
<Box sx={{ display: 'flex-inline' }}>
<TableSearchBar
value={voterSearchInput}
onChange={setVoterSearchPattern}
placeholder={t('networkProposal.searchForVoters')}
warning={searchError}
/>
<VoteTypeFilter onSelect={setWantedVoteType} value={wantedVoteType} />
</Box>
}
disableTypography
component="h3"
title={t('common.votes')}
Expand Down
38 changes: 37 additions & 1 deletion src/app/pages/ProposalDetailsPage/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { getFilterForVoteType, getRandomVote } from '../../utils/vote'
import { useClientSidePagination } from '../../components/Table/useClientSidePagination'
import { NUMBER_OF_ITEMS_ON_SEPARATE_PAGE } from '../../config'
import { useTypedSearchParam } from '../../hooks/useTypedSearchParam'
import { TFunction } from 'i18next'

export type AllVotesData = List & {
isLoading: boolean
Expand Down Expand Up @@ -121,7 +122,42 @@ export const useWantedVoteType = () =>
deleteParams: ['page'],
})

const useWantedVoteFilter = (): VoteFilter => getFilterForVoteType(useWantedVoteType()[0])
export const useVoterSearch = () => useTypedSearchParam('voter', '', { deleteParams: ['page'] })

export const useVoterSearchPattern = () => {
const [voterSearchInput] = useVoterSearch()
return voterSearchInput.length < 3 ? undefined : voterSearchInput
}

export const useVoterSearchError = (t: TFunction) => {
const [input] = useVoterSearch()
const pattern = useVoterSearchPattern()
return !!input && !pattern ? t('tableSearch.error.tooShort') : undefined
}

const useWantedVoteFilter = (): VoteFilter => {
const typeFilter = getFilterForVoteType(useWantedVoteType()[0])
const voterSearchPattern = useVoterSearchPattern()

if (!voterSearchPattern) {
return typeFilter
} else {
return (vote: ExtendedVote) =>
typeFilter(vote) && !!vote.validator?.media?.name?.toLowerCase().includes(voterSearchPattern)
}
}

export const useVoteFilters = (): [boolean, () => void] => {
const [wantedType, setWantedType] = useWantedVoteType()
const searchPattern = useVoterSearchPattern()

return [
wantedType !== 'any' || !!searchPattern,
() => {
setWantedType('any', { deleteParams: ['voter'] })
},
]
}

export const PAGE_SIZE = NUMBER_OF_ITEMS_ON_SEPARATE_PAGE

Expand Down
1 change: 1 addition & 0 deletions src/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,7 @@
"passed": "Passed",
"rejected": "Rejected"
},
"searchForVoters": "Search for voters",
"type": {
"upgrade": "Upgrade",
"parameterUpgrade": "Parameter upgrade",
Expand Down

0 comments on commit 9b2a36a

Please sign in to comment.