Add clear button to topic search

This commit is contained in:
Thomas Nordquist
2019-01-22 16:43:25 +01:00
parent 28cc72a868
commit be8e05dbfa
7 changed files with 57 additions and 18 deletions

View File

@@ -5,16 +5,19 @@ import { rendererEvents, addMqttConnectionEvent, makeConnectionStateEvent, remov
import { AppState } from '../reducers' import { AppState } from '../reducers'
import * as q from '../../../backend/src/Model' import * as q from '../../../backend/src/Model'
import { showTree } from './Tree' import { showTree } from './Tree'
import * as url from 'url'
export const connect = (options: MqttOptions, connectionId: string) => (dispatch: Dispatch<any>, getState: () => AppState) => { export const connect = (options: MqttOptions, connectionId: string) => (dispatch: Dispatch<any>, getState: () => AppState) => {
dispatch(connecting(connectionId)) dispatch(connecting(connectionId))
rendererEvents.emit(addMqttConnectionEvent, { options, id: connectionId }) rendererEvents.emit(addMqttConnectionEvent, { options, id: connectionId })
const event = makeConnectionStateEvent(connectionId) const event = makeConnectionStateEvent(connectionId)
const host = url.parse(options.url).hostname
rendererEvents.subscribe(event, (dataSourceState) => { rendererEvents.subscribe(event, (dataSourceState) => {
if (dataSourceState.connected) { if (dataSourceState.connected) {
const tree = new q.Tree() const tree = new q.Tree()
tree.updateWithConnection(rendererEvents, connectionId) tree.updateWithConnection(rendererEvents, connectionId)
dispatch(connected(tree)) dispatch(connected(tree, host!))
dispatch(showTree(tree)) dispatch(showTree(tree))
} else if (dataSourceState.error) { } else if (dataSourceState.error) {
dispatch(showError(dataSourceState.error)) dispatch(showError(dataSourceState.error))
@@ -23,8 +26,9 @@ export const connect = (options: MqttOptions, connectionId: string) => (dispatch
}) })
} }
export const connected: (tree: q.Tree) => Action = (tree: q.Tree) => ({ export const connected: (tree: q.Tree, host: string) => Action = (tree: q.Tree, host: string) => ({
tree, tree,
host,
type: ActionTypes.CONNECTION_SET_CONNECTED, type: ActionTypes.CONNECTION_SET_CONNECTED,
}) })

View File

@@ -26,23 +26,20 @@ export const setTopicOrder = (topicOrder: TopicOrder = TopicOrder.none): Action
} }
export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, getState: () => AppState) => { export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, getState: () => AppState) => {
const topicFilter = filterStr.toLowerCase() const { tree } = getState().connection
dispatch({ dispatch({
topicFilter, topicFilter: filterStr,
type: ActionTypes.SETTINGS_FILTER_TOPICS, type: ActionTypes.SETTINGS_FILTER_TOPICS,
}) })
const { tree } = getState().connection if (!filterStr || !tree) {
if (!tree) {
return
}
if (!topicFilter) {
dispatch(showTree(tree)) dispatch(showTree(tree))
return return
} }
const topicFilter = filterStr.toLowerCase()
const nodeFilter = (node: q.TreeNode): boolean => { const nodeFilter = (node: q.TreeNode): boolean => {
const topicMatches = node.path().toLowerCase().indexOf(topicFilter) !== -1 const topicMatches = node.path().toLowerCase().indexOf(topicFilter) !== -1
if (topicMatches) { if (topicMatches) {

View File

@@ -32,6 +32,7 @@ import Clear from '@material-ui/icons/Clear'
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { publishActions } from '../../../actions' import { publishActions } from '../../../actions'
import ClearAdornment from '../../helper/ClearAdornment';
interface Props { interface Props {
node?: q.TreeNode node?: q.TreeNode
@@ -114,7 +115,7 @@ class Publish extends React.Component<Props, State> {
id="publish-topic" id="publish-topic"
value={topicStr} value={topicStr}
startAdornment={<span/>} startAdornment={<span/>}
endAdornment={<IconButton style={{ padding: '4px' }} onClick={this.clearTopic}><Clear style={{ fontSize: '14px' }} /></IconButton>} endAdornment={<ClearAdornment action={this.clearTopic} value={topicStr} />}
onBlur={this.onTopicBlur} onBlur={this.onTopicBlur}
onChange={this.updateTopic} onChange={this.updateTopic}
multiline={true} multiline={true}

View File

@@ -12,6 +12,7 @@ import { connect } from 'react-redux'
import { fade } from '@material-ui/core/styles/colorManipulator' import { fade } from '@material-ui/core/styles/colorManipulator'
import { settingsActions, connectionActions } from '../actions' import { settingsActions, connectionActions } from '../actions'
import { AppState } from '../reducers' import { AppState } from '../reducers'
import ClearAdornment from './helper/ClearAdornment';
const styles: StyleRulesCallback = theme => ({ const styles: StyleRulesCallback = theme => ({
title: { title: {
@@ -36,7 +37,7 @@ const styles: StyleRulesCallback = theme => ({
}, },
}, },
searchIcon: { searchIcon: {
width: theme.spacing.unit * 9, width: theme.spacing.unit * 8,
height: '100%', height: '100%',
position: 'absolute', position: 'absolute',
pointerEvents: 'none', pointerEvents: 'none',
@@ -100,7 +101,7 @@ class TitleBar extends React.Component<Props, {}> {
} }
private renderSearch() { private renderSearch() {
const { classes } = this.props const { classes, topicFilter } = this.props
return ( return (
<div className={classes.search}> <div className={classes.search}>
@@ -108,15 +109,20 @@ class TitleBar extends React.Component<Props, {}> {
<Search /> <Search />
</div> </div>
<InputBase <InputBase
value={this.props.topicFilter} value={topicFilter}
onChange={this.onFilterChange} onChange={this.onFilterChange}
placeholder="Search…" placeholder="Search…"
endAdornment={<div style={{ width: '24px', paddingRight: '8px' }}><ClearAdornment action={this.clearFilter} value={topicFilter} /></div>}
classes={{ root: classes.inputRoot, input: classes.inputInput }} classes={{ root: classes.inputRoot, input: classes.inputInput }}
/> />
</div> </div>
) )
} }
private clearFilter = () => {
this.props.actions.settings.filterTopics('')
}
private onFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => { private onFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.actions.settings.filterTopics(event.target.value) this.props.actions.settings.filterTopics(event.target.value)
} }

View File

@@ -18,6 +18,7 @@ interface Props {
connectionId?: string connectionId?: string
tree?: q.Tree tree?: q.Tree
filter: string filter: string
host?: string
} }
class Tree extends React.Component<Props, {}> { class Tree extends React.Component<Props, {}> {
@@ -90,7 +91,7 @@ class Tree extends React.Component<Props, {}> {
animateChages={true} animateChages={true}
isRoot={true} isRoot={true}
treeNode={tree} treeNode={tree}
name={'"root"'} name={this.props.host}
lastUpdate={tree.lastUpdate} lastUpdate={tree.lastUpdate}
collapsed={false} collapsed={false}
performanceCallback={this.performanceCallback} performanceCallback={this.performanceCallback}
@@ -109,6 +110,7 @@ const mapStateToProps = (state: AppState) => {
autoExpandLimit: state.settings.autoExpandLimit, autoExpandLimit: state.settings.autoExpandLimit,
tree: state.tree.tree, tree: state.tree.tree,
filter: state.tree.filter, filter: state.tree.filter,
host: state.connection.host,
} }
} }

View File

@@ -0,0 +1,25 @@
import * as React from 'react'
import { IconButton } from '@material-ui/core'
import Clear from '@material-ui/icons/Clear'
interface Props {
value?: string
action: any
style?: React.CSSProperties
}
class ClearAdornment extends React.Component<Props, {}> {
public render() {
if (this.props.value) {
return (
<IconButton style={{ ...this.props.style, padding: '1px' }} onClick={this.props.action}>
<Clear style={{ fontSize: '16px' }} />
</IconButton>
)
}
return null
}
}
export default ClearAdornment

View File

@@ -4,6 +4,7 @@ import * as q from '../../../backend/src/Model'
import { MqttOptions } from '../../../backend/src/DataSource' import { MqttOptions } from '../../../backend/src/DataSource'
export interface ConnectionState { export interface ConnectionState {
host?: string
tree?: q.Tree tree?: q.Tree
connectionOptions?: MqttOptions connectionOptions?: MqttOptions
connectionId?: string connectionId?: string
@@ -28,6 +29,7 @@ export interface SetConnecting {
export interface SetConnected { export interface SetConnected {
type: ActionTypes.CONNECTION_SET_CONNECTED type: ActionTypes.CONNECTION_SET_CONNECTED
host: string
tree: q.Tree tree: q.Tree
} }
@@ -52,7 +54,7 @@ export const connectionReducer = createReducer(initialState, {
CONNECTION_SET_SHOW_ERROR: showError, CONNECTION_SET_SHOW_ERROR: showError,
}) })
function setConnecting(state: ConnectionState, action: SetConnecting) { function setConnecting(state: ConnectionState, action: SetConnecting): ConnectionState {
return { return {
...state, ...state,
connecting: true, connecting: true,
@@ -61,18 +63,20 @@ function setConnecting(state: ConnectionState, action: SetConnecting) {
} }
} }
function setConnected(state: ConnectionState, action: SetConnected) { function setConnected(state: ConnectionState, action: SetConnected): ConnectionState {
return { return {
...state, ...state,
host: action.host,
connecting: false, connecting: false,
connected: true, connected: true,
tree: action.tree, tree: action.tree,
} }
} }
function setDisconnected(state: ConnectionState, action: SetDisconnected) { function setDisconnected(state: ConnectionState, action: SetDisconnected): ConnectionState {
return { return {
...state, ...state,
host: undefined,
connecting: false, connecting: false,
connected: false, connected: false,
connectionId: undefined, connectionId: undefined,