Skip to content

Commit

Permalink
feat: add menu to telemetry page and keyboard shortcut for representa…
Browse files Browse the repository at this point in the history
…tive filter input (fixes #94)
  • Loading branch information
mistakia committed Mar 6, 2024
1 parent 673dda6 commit 0557232
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 42 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@
"eslint-plugin-react": "7.33.0",
"file-loader": "^6.2.0",
"highlight.js": "^11.8.0",
"hotkeys-js": "^3.13.7",
"html-inline-script-webpack-plugin": "^2.0.3",
"html-loader": "^2.1.2",
"html-webpack-plugin": "^5.5.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,57 +1,83 @@
import React from 'react'
import React, { useState, useEffect, useRef } from 'react'
import PropTypes from 'prop-types'
import ClearIcon from '@mui/icons-material/Clear'
import KeyboardCommandKeyIcon from '@mui/icons-material/KeyboardCommandKey'
import hotkeys from 'hotkeys-js'

import { debounce } from '@core/utils'

import './representatives-search.styl'

export default class RepresentativesSearch extends React.Component {
constructor(props) {
super(props)
const RepresentativesSearch = ({
value: initialValue,
search,
align = 'center'
}) => {
const [value, setValue] = useState(initialValue || '')
const inputRef = useRef(null)

this.state = {
value: this.props.value || ''
const debouncedSearch = debounce((value) => {
search(value)
}, 300)

useEffect(() => {
const handleHotkeys = (event, handler) => {
event.preventDefault()
inputRef.current.focus()
}

this.search = debounce((value) => {
this.props.search(value)
}, 300)
}
hotkeys('command+k,ctrl+k', handleHotkeys)

handleClick = () => {
const value = ''
this.setState({ value })
this.props.search(value)
return () => {
hotkeys.unbind('command+k,ctrl+k')
}
}, [])

const handleClick = () => {
setValue('')
search('')
}

handleChange = (event) => {
const handleChange = (event) => {
const { value } = event.target
this.setState({ value })
this.search(value)
setValue(value)
debouncedSearch(value)
}

render = () => {
return (
<div className='representatives__search'>
<input
className='search__input'
type='text'
placeholder='Filter by account, alias, ip'
value={this.state.value}
onChange={this.handleChange}
/>
{this.state.value && (
<div className='search__input-clear' onClick={this.handleClick}>
<ClearIcon />
</div>
)}
</div>
)
const classNames = ['representatives__search']

if (align === 'left') {
classNames.push('left')
} else {
classNames.push('center')
}

return (
<div className={classNames.join(' ')}>
<input
ref={inputRef}
className='search__input'
type='text'
placeholder='Filter by account, alias, ip'
value={value}
onChange={handleChange}
/>
<div className='search__shortcut-icon'>
<KeyboardCommandKeyIcon fontSize='small' />K
</div>
{value && (
<div className='search__input-clear' onClick={handleClick}>
<ClearIcon />
</div>
)}
</div>
)
}

RepresentativesSearch.propTypes = {
value: PropTypes.string,
search: PropTypes.func
search: PropTypes.func,
align: PropTypes.oneOf(['left', 'center'])
}

export default RepresentativesSearch
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,31 @@
width 380px
min-width 160px
max-width 400px
margin 8px
margin-right 8px
border-radius 99em
border-radius 6px
overflow hidden
position relative
display flex
align-items center
background white

&.center
margin 8px auto

&.left
margin 8px

.search__shortcut-icon
display flex
align-items center
justify-content center
padding 4px
cursor pointer
margin-right 4px

border 1px solid #e0e0e0
border-radius 6px

.MuiSvgIcon-root
width 14px
height 14px

6 changes: 4 additions & 2 deletions src/views/pages/representatives/representatives.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,10 @@ export default class RepresentativesPage extends React.Component {
<RepresentativesCountryByWeight />
</div>
<div className='representatives__body'>
<RepresentativesSearch />
<RepresentativesFilters />
<div className='representatives__body-header'>
<RepresentativesSearch align='left' />
<RepresentativesFilters />
</div>
<Representatives />
<div className='representatives__metrics'>
<Tabs
Expand Down
4 changes: 4 additions & 0 deletions src/views/pages/representatives/representatives.styl
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
margin 0 auto
max-width 1300px

.representatives__body-header
flex 1
display flex

.representatives__metrics
width 100%
max-width 1100px
Expand Down
6 changes: 4 additions & 2 deletions src/views/pages/telemetry/telemetry.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ export default function TelemetryPage() {
]}
/>
<div className='representatives__body'>
<RepresentativesSearch />
<div className='representatives__body-header'>
<RepresentativesSearch />
</div>
<Representatives table_height={table_height} />
</div>
<div className='representatives__footer'>
<Menu hide_speed_dial={true} />
<Menu />
</div>
</>
)
Expand Down
8 changes: 8 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -9841,6 +9841,13 @@ __metadata:
languageName: node
linkType: hard

"hotkeys-js@npm:^3.13.7":
version: 3.13.7
resolution: "hotkeys-js@npm:3.13.7"
checksum: 8c1da52704c1c2a97810d0d2c9d0917b87a7edd250aae79cd4b185b9374b2ddc7ba24eeec8491018ba51726b72faecf89042fede2b3a05d0599f334355bb968c
languageName: node
linkType: hard

"hpack.js@npm:^2.1.6":
version: 2.1.6
resolution: "hpack.js@npm:2.1.6"
Expand Down Expand Up @@ -15711,6 +15718,7 @@ __metadata:
front-matter: ^4.0.2
fs-extra: ^11.1.1
highlight.js: ^11.8.0
hotkeys-js: ^3.13.7
html-inline-script-webpack-plugin: ^2.0.3
html-loader: ^2.1.2
html-webpack-plugin: ^5.5.3
Expand Down

0 comments on commit 0557232

Please sign in to comment.