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

Network proposal votes: add search by validator name #1357

Merged
merged 5 commits into from
May 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .changelog/1357.trivial.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Network proposal votes: add search by validator name
17 changes: 14 additions & 3 deletions src/app/components/CardEmptyState/index.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { FC } from 'react'
import { FC, ReactNode } from 'react'
import Box from '@mui/material/Box'
import Typography from '@mui/material/Typography'
import { styled } from '@mui/material/styles'
Expand All @@ -23,11 +23,22 @@ const StyledBox = styled(Box)(({ theme }) => ({

type CardEmptyStateProps = {
label: string
action?: ReactNode
}

export const CardEmptyState: FC<CardEmptyStateProps> = ({ label }) => (
export const CardEmptyState: FC<CardEmptyStateProps> = ({ label, action }) => (
<StyledBox>
<ReportProblemIcon sx={{ color: COLORS.warningColor, fontSize: '60px' }} />
<Typography sx={{ color: COLORS.grayDark }}>{label}</Typography>
<Typography
sx={{
color: COLORS.grayDark,
display: 'block',
alignItems: 'center',
verticalAlign: 'middle',
}}
>
{label}
{action}
</Typography>
</StyledBox>
)
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@ import CardHeader, { cardHeaderClasses } from '@mui/material/CardHeader'
import { styled } from '@mui/material/styles'

export const CardHeaderWithResponsiveActions = styled(CardHeader)(({ theme }) => ({
[theme.breakpoints.down('sm')]: {
[theme.breakpoints.down('md')]: {
display: 'inline',
alignItems: 'flex-start',
flexDirection: 'column',
[`.${cardHeaderClasses.content}`]: {
display: 'inline',
marginRight: theme.spacing(4),
},
[`.${cardHeaderClasses.action}`]: {
display: 'inline',
marginTop: theme.spacing(4),
marginBottom: theme.spacing(4),
},
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/HighlightedText/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ export interface HighlightOptions {

const defaultHighlightStyle: SxProps = {
background: '#FFFF5480',
padding: '4px',
margin: '-4px',
padding: '2px',
margin: '-2px',
}

const defaultHighlight: HighlightOptions = {
Expand Down
4 changes: 2 additions & 2 deletions src/app/components/Proposals/VoteTypeFilter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ export const VoteTypeFilter: FC<VoteTypeFilterProps> = ({ onSelect, value }) =>
]

return (
<>
<Box sx={{ display: 'inline-flex' }}>
{options.map(option => {
const selected = option.value === value
return (
Expand All @@ -59,6 +59,6 @@ export const VoteTypeFilter: FC<VoteTypeFilterProps> = ({ onSelect, value }) =>
/>
)
})}
</>
</Box>
)
}
133 changes: 133 additions & 0 deletions src/app/components/Search/TableSearchBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import { FC, useEffect, useState } from 'react'
import TextField from '@mui/material/TextField'
import SearchIcon from '@mui/icons-material/Search'
import HighlightOffIcon from '@mui/icons-material/HighlightOff'
import InputAdornment from '@mui/material/InputAdornment'
import { COLORS } from '../../../styles/theme/colors'
import IconButton from '@mui/material/IconButton'
import { useScreenSize } from '../../hooks/useScreensize'
import WarningIcon from '@mui/icons-material/WarningAmber'
import { typingDelay } from '../../../styles/theme'
import Typography from '@mui/material/Typography'
import { useTranslation } from 'react-i18next'
import Button from '@mui/material/Button'
import { CardEmptyState } from '../CardEmptyState'
import { inputBaseClasses } from '@mui/material/InputBase'

export interface TableSearchBarProps {
placeholder: string
warning?: string
value: string
onChange: (value: string) => void
}

export const TableSearchBar: FC<TableSearchBarProps> = ({ value, onChange, placeholder, warning }) => {
const { isTablet } = useScreenSize()

const [isWarningFresh, setIsWarningFresh] = useState(false)

useEffect(() => {
if (warning) {
const timeout = setTimeout(() => {
setIsWarningFresh(false)
}, typingDelay)
return () => clearTimeout(timeout)
} else {
setIsWarningFresh(true)
}
}, [warning])

const startAdornment = (
<InputAdornment
position="start"
disablePointerEvents // Pass clicks through, so it focuses the input
>
<SearchIcon sx={{ color: COLORS.grayDark, ml: -3 }} />
</InputAdornment>
)

const onClearValue = () => onChange('')

const endAdornment = (
<InputAdornment position="end">
{value ? (
<IconButton color="inherit" sx={{ mt: -3, mb: -3, mr: -1 }} onClick={onClearValue}>
csillag marked this conversation as resolved.
Show resolved Hide resolved
<HighlightOffIcon />
</IconButton>
) : (
<span style={{ width: '38px' }} />
lubej marked this conversation as resolved.
Show resolved Hide resolved
)}
</InputAdornment>
)

const helperText = isWarningFresh ? undefined : (
<Typography
component="span"
sx={{
display: 'inline-flex',
color: COLORS.warningColor,
fontSize: 12,
lineHeight: 2,
alignItems: 'center',
verticalAlign: 'middle',
mt: 3,
mb: 4,
width: isTablet ? '160px' : undefined,
}}
>
<WarningIcon sx={{ mr: 3 }} />
{warning}
</Typography>
)

return (
<TextField
sx={{
backgroundColor: COLORS.white,
marginLeft: 4,
marginRight: helperText ? '25px' : '25px',
'&:focus-within': {
boxShadow: '3px 3px 3px 3px rgb(0, 0, 98, 0.25) !important',
},
[`.${inputBaseClasses.root}`]: {
border: '1px solid',
borderColor: COLORS.inactiveStroke,
},
...(helperText
? {
border: '1px solid',
borderColor: COLORS.inactiveStroke,
marginBottom: isTablet ? '-99px' : '-50px',
csillag marked this conversation as resolved.
Show resolved Hide resolved
}
: {}),
zIndex: 10,
}}
variant={'outlined'}
value={value}
onChange={e => onChange(e.target.value)}
InputProps={{
inputProps: {
sx: {
p: 0,
width: isTablet ? 110 : 300,
margin: 2,
},
},
startAdornment,
endAdornment,
}}
placeholder={placeholder}
helperText={helperText}
/>
)
}

export const NoMatchingDataMaybeClearFilters: FC<{ clearFilters: () => void }> = ({ clearFilters }) => {
const { t } = useTranslation()
const clearButton = (
<Button variant={'text'} onClick={() => clearFilters()}>
{t('tableSearch.clearFilters')}
</Button>
)
return <CardEmptyState label={t('tableSearch.noMatchingResults')} action={clearButton} />
}
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>
)
}
Loading
Loading