Add clear button to topic search
This commit is contained in:
@@ -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,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
25
app/src/components/helper/ClearAdornment.tsx
Normal file
25
app/src/components/helper/ClearAdornment.tsx
Normal 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
|
||||||
@@ -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,
|
||||||
|
|||||||
Reference in New Issue
Block a user