Extract settings reducer

This commit is contained in:
Thomas Nordquist
2019-01-21 09:40:04 +01:00
parent 61737fa97b
commit 4d21c63da9
10 changed files with 70 additions and 107 deletions

View File

@@ -104,7 +104,7 @@ class App extends React.Component<Props, {}> {
const mapStateToProps = (state: AppState) => { const mapStateToProps = (state: AppState) => {
return { return {
settingsVisible: state.tooBigReducer.settings.visible, settingsVisible: state.settings.visible,
connectionId: state.connection.connectionId, connectionId: state.connection.connectionId,
} }
} }

View File

@@ -1,21 +1,28 @@
import { ActionTypes, NodeOrder, CustomAction } from '../reducers' import { Action, ActionTypes, TopicOrder } from '../reducers/Settings'
export const setAutoExpandLimit = (autoExpandLimit: number = 0): CustomAction => { export const setAutoExpandLimit = (autoExpandLimit: number = 0): Action => {
return { return {
autoExpandLimit, autoExpandLimit,
type: ActionTypes.setAutoExpandLimit, type: ActionTypes.SETTINGS_SET_AUTO_EXPAND_LIMIT,
} }
} }
export const toggleSettingsVisibility = (): CustomAction => { export const toggleSettingsVisibility = (): Action => {
return { return {
type: ActionTypes.toggleSettingsVisibility, type: ActionTypes.SETTINGS_TOGGLE_VISIBILITY,
} }
} }
export const setNodeOrder = (nodeOrder: NodeOrder = NodeOrder.none): CustomAction => { export const setTopicOrder = (topicOrder: TopicOrder = TopicOrder.none): Action => {
return { return {
nodeOrder, topicOrder,
type: ActionTypes.setNodeOrder, type: ActionTypes.SETTINGS_SET_TOPIC_ORDER,
}
}
export const filterTopics = (topicFilter: string): Action => {
return {
topicFilter,
type: ActionTypes.SETTINGS_FILTER_TOPICS,
} }
} }

View File

@@ -1,7 +1,7 @@
import * as React from 'react' import * as React from 'react'
import * as q from '../../../backend/src/Model' import * as q from '../../../backend/src/Model'
import { AppState, NodeOrder } from '../reducers' import { AppState } from '../reducers'
import { import {
Divider, Divider,
Drawer, Drawer,
@@ -18,6 +18,7 @@ import ChevronRight from '@material-ui/icons/ChevronRight'
import { bindActionCreators } from 'redux' import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { settingsActions } from '../actions' import { settingsActions } from '../actions'
import { TopicOrder } from '../reducers/Settings'
const styles: StyleRulesCallback = theme => ({ const styles: StyleRulesCallback = theme => ({
drawer: { drawer: {
@@ -44,7 +45,7 @@ interface Props {
visible: boolean visible: boolean
store?: any store?: any
classes: any classes: any
nodeOrder: NodeOrder topicOrder: TopicOrder
} }
class Settings extends React.Component<Props, {}> { class Settings extends React.Component<Props, {}> {
@@ -110,23 +111,23 @@ class Settings extends React.Component<Props, {}> {
} }
private renderNodeOrder() { private renderNodeOrder() {
const { classes, nodeOrder } = this.props const { classes, topicOrder } = this.props
return ( return (
<div style={{ padding: '8px' }}> <div style={{ padding: '8px' }}>
<InputLabel htmlFor="auto-expand">Topic order</InputLabel> <InputLabel htmlFor="auto-expand">Topic order</InputLabel>
<Select <Select
value={nodeOrder} value={topicOrder}
onChange={this.onChangeSorting} onChange={this.onChangeSorting}
input={<Input name="node-order" id="node-order-label-placeholder" />} input={<Input name="node-order" id="node-order-label-placeholder" />}
displayEmpty={true} displayEmpty={true}
name="node-order" name="node-order"
className={classes.input} className={classes.input}
> >
<MenuItem value={NodeOrder.none}><em>default</em></MenuItem> <MenuItem value={TopicOrder.none}><em>default</em></MenuItem>
<MenuItem value={NodeOrder.abc}>a-z</MenuItem> <MenuItem value={TopicOrder.abc}>a-z</MenuItem>
<MenuItem value={NodeOrder.messages}>{NodeOrder.messages}</MenuItem> <MenuItem value={TopicOrder.messages}>{TopicOrder.messages}</MenuItem>
<MenuItem value={NodeOrder.topics}>{NodeOrder.topics}</MenuItem> <MenuItem value={TopicOrder.topics}>{TopicOrder.topics}</MenuItem>
</Select> </Select>
</div>) </div>)
} }
@@ -138,9 +139,9 @@ class Settings extends React.Component<Props, {}> {
const mapStateToProps = (state: AppState) => { const mapStateToProps = (state: AppState) => {
return { return {
autoExpandLimit: state.tooBigReducer.settings.autoExpandLimit, autoExpandLimit: state.settings.autoExpandLimit,
nodeOrder: state.tooBigReducer.settings.nodeOrder, topicOrder: state.settings.topicOrder,
visible: state.tooBigReducer.settings.visible, visible: state.settings.visible,
} }
} }

View File

@@ -54,6 +54,7 @@ class MessageHistory extends React.Component<Props, State> {
return ( return (
<div style={{ backgroundColor: 'rgba(60, 60, 60, 0.6)', marginTop: '16px' }}> <div style={{ backgroundColor: 'rgba(60, 60, 60, 0.6)', marginTop: '16px' }}>
<Typography <Typography
component={'span'}
onClick={this.toggle} onClick={this.toggle}
style={{ cursor: 'pointer' }} style={{ cursor: 'pointer' }}
> >

View File

@@ -11,6 +11,7 @@ import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' 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'
const styles: StyleRulesCallback = theme => ({ const styles: StyleRulesCallback = theme => ({
title: { title: {
@@ -70,22 +71,13 @@ interface Props {
settings: typeof settingsActions, settings: typeof settingsActions,
connection: typeof connectionActions, connection: typeof connectionActions,
} }
topicFilter?: string
} }
interface State { class TitleBar extends React.Component<Props, {}> {
selectedNode?: q.TreeNode
settingsVisible: boolean
autoExpandLimit: number
}
class TitleBar extends React.Component<Props, State> {
constructor(props: any) { constructor(props: any) {
super(props) super(props)
this.state = { this.state = { }
selectedNode: undefined,
settingsVisible: false,
autoExpandLimit: 0,
}
} }
public render() { public render() {
@@ -98,6 +90,7 @@ class TitleBar extends React.Component<Props, State> {
<Menu /> <Menu />
</IconButton> </IconButton>
<Typography className={classes.title} variant="h6" color="inherit">MQTT-Explorer</Typography> <Typography className={classes.title} variant="h6" color="inherit">MQTT-Explorer</Typography>
{this.renderSearch()}
<Button style={{ margin: 'auto 8px auto auto' }} onClick={actions.connection.disconnect}> <Button style={{ margin: 'auto 8px auto auto' }} onClick={actions.connection.disconnect}>
Disconnect <CloudOff style={{ marginRight: '8px', paddingLeft: '8px' }}/> Disconnect <CloudOff style={{ marginRight: '8px', paddingLeft: '8px' }}/>
</Button> </Button>
@@ -115,12 +108,24 @@ class TitleBar extends React.Component<Props, State> {
<Search /> <Search />
</div> </div>
<InputBase <InputBase
value={this.props.topicFilter}
onChange={this.onFilterChange}
placeholder="Search…" placeholder="Search…"
classes={{ root: classes.inputRoot, input: classes.inputInput }} classes={{ root: classes.inputRoot, input: classes.inputInput }}
/> />
</div> </div>
) )
} }
private onFilterChange = (event: React.ChangeEvent<HTMLInputElement>) => {
this.props.actions.settings.filterTopics(event.target.value)
}
}
const mapStateToProps = (state: AppState) => {
return {
topicFilter: state.settings.topicFilter,
}
} }
const mapDispatchToProps = (dispatch: any) => { const mapDispatchToProps = (dispatch: any) => {
@@ -132,4 +137,4 @@ const mapDispatchToProps = (dispatch: any) => {
} }
} }
export default connect(undefined, mapDispatchToProps)(withStyles(styles)(TitleBar)) export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(TitleBar))

View File

@@ -89,9 +89,7 @@ class Tree extends React.Component<Props, {}> {
<div style={style}> <div style={style}>
<TreeNode <TreeNode
animateChages={true} animateChages={true}
autoExpandLimit={this.props.autoExpandLimit}
isRoot={true} isRoot={true}
didSelectNode={this.props.didSelectNode}
treeNode={this.props.tree} treeNode={this.props.tree}
name="/" name="/"
collapsed={false} collapsed={false}
@@ -110,7 +108,7 @@ class Tree extends React.Component<Props, {}> {
const mapStateToProps = (state: AppState) => { const mapStateToProps = (state: AppState) => {
return { return {
autoExpandLimit: state.tooBigReducer.settings.autoExpandLimit, autoExpandLimit: state.settings.autoExpandLimit,
tree: state.connection.tree, tree: state.connection.tree,
} }
} }

View File

@@ -10,6 +10,7 @@ import { bindActionCreators } from 'redux'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { isElementInViewport } from '../helper/isElementInViewport' import { isElementInViewport } from '../helper/isElementInViewport'
import { treeActions } from '../../actions' import { treeActions } from '../../actions'
import { AppState } from '../../reducers'
declare var performance: any declare var performance: any
@@ -40,7 +41,7 @@ const styles = (theme: Theme) => {
} }
interface Props { interface Props {
actions: any actions: typeof treeActions
lastUpdate: number lastUpdate: number
animateChages: boolean animateChages: boolean
isRoot?: boolean isRoot?: boolean
@@ -48,9 +49,8 @@ interface Props {
name?: string | undefined name?: string | undefined
collapsed?: boolean | undefined collapsed?: boolean | undefined
performanceCallback?: ((ms: number) => void) | undefined performanceCallback?: ((ms: number) => void) | undefined
didSelectNode?: (node: q.TreeNode) => void
classes: any
autoExpandLimit: number autoExpandLimit: number
classes: any
style?: React.CSSProperties style?: React.CSSProperties
} }
@@ -220,7 +220,6 @@ class TreeNode extends React.Component<Props, State> {
animateChanges={this.props.animateChages} animateChanges={this.props.animateChages}
collapsed={this.collapsed()} collapsed={this.collapsed()}
autoExpandLimit={this.props.autoExpandLimit} autoExpandLimit={this.props.autoExpandLimit}
didSelectNode={this.props.didSelectNode}
treeNode={this.props.treeNode} treeNode={this.props.treeNode}
lastUpdate={this.props.treeNode.lastUpdate} lastUpdate={this.props.treeNode.lastUpdate}
/> />
@@ -234,4 +233,10 @@ const mapDispatchToProps = (dispatch: any) => {
} }
} }
export default withStyles(styles)(connect(null, mapDispatchToProps)(TreeNode)) const mapStateToProps = (state: AppState) => {
return {
autoExpandLimit: state.settings.autoExpandLimit,
}
}
export default withStyles(styles)(connect(mapStateToProps, mapDispatchToProps)(TreeNode))

View File

@@ -1,15 +1,16 @@
import * as React from 'react' import * as React from 'react'
import * as q from '../../../../backend/src/Model' import * as q from '../../../../backend/src/Model'
import { AppState, NodeOrder } from '../../reducers' import { AppState } from '../../reducers'
import { Theme, withTheme } from '@material-ui/core/styles' import { Theme, withTheme } from '@material-ui/core/styles'
import TreeNode from './TreeNode' import TreeNode from './TreeNode'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import { TopicOrder } from '../../reducers/Settings'
export interface Props { export interface Props {
lastUpdate: number lastUpdate: number
nodeOrder?: NodeOrder topicOrder?: TopicOrder
animateChanges: boolean animateChanges: boolean
treeNode: q.TreeNode treeNode: q.TreeNode
autoExpandLimit: number autoExpandLimit: number
@@ -20,18 +21,18 @@ export interface Props {
class TreeNodeSubnodes extends React.Component<Props, {}> { class TreeNodeSubnodes extends React.Component<Props, {}> {
private sortedNodes(): q.TreeNode[] { private sortedNodes(): q.TreeNode[] {
const { nodeOrder, treeNode } = this.props const { topicOrder, treeNode } = this.props
let edges = Object.values(treeNode.edges) let edges = Object.values(treeNode.edges)
if (nodeOrder === NodeOrder.abc) { if (topicOrder === TopicOrder.abc) {
edges = edges.sort((a, b) => a.name.localeCompare(b.name)) edges = edges.sort((a, b) => a.name.localeCompare(b.name))
} }
let nodes = edges.map(edge => edge.target) let nodes = edges.map(edge => edge.target)
if (nodeOrder === NodeOrder.messages) { if (topicOrder === TopicOrder.messages) {
nodes = nodes.sort((a, b) => b.leafMessageCount() - a.leafMessageCount()) nodes = nodes.sort((a, b) => b.leafMessageCount() - a.leafMessageCount())
} }
if (nodeOrder === NodeOrder.topics) { if (topicOrder === TopicOrder.topics) {
nodes = nodes.sort((a, b) => b.leafCount() - a.leafCount()) nodes = nodes.sort((a, b) => b.leafCount() - a.leafCount())
} }
@@ -54,8 +55,6 @@ class TreeNodeSubnodes extends React.Component<Props, {}> {
<TreeNode <TreeNode
animateChages={this.props.animateChanges} animateChages={this.props.animateChanges}
treeNode={node} treeNode={node}
didSelectNode={this.props.didSelectNode}
autoExpandLimit={this.props.autoExpandLimit}
lastUpdate={node.lastUpdate} lastUpdate={node.lastUpdate}
style={listItemStyle} style={listItemStyle}
/> />
@@ -72,7 +71,7 @@ class TreeNodeSubnodes extends React.Component<Props, {}> {
const mapStateToProps = (state: AppState) => { const mapStateToProps = (state: AppState) => {
return { return {
nodeOrder: state.tooBigReducer.settings.nodeOrder, topicOrder: state.settings.topicOrder,
} }
} }

View File

@@ -5,7 +5,7 @@ import * as ReactDOM from 'react-dom'
import reduxThunk from 'redux-thunk' import reduxThunk from 'redux-thunk'
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles' import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import reducers, { AppState, NodeOrder } from './reducers' import reducers from './reducers'
import App from './App' import App from './App'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'

View File

@@ -5,22 +5,16 @@ import { Action, Reducer, combineReducers } from 'redux'
import { trackEvent } from '../tracking' import { trackEvent } from '../tracking'
import { PublishState, publishReducer } from './Publish' import { PublishState, publishReducer } from './Publish'
import { ConnectionState, connectionReducer } from './Connection' import { ConnectionState, connectionReducer } from './Connection'
import { SettingsState, settingsReducer } from './Settings'
export enum ActionTypes { export enum ActionTypes {
setAutoExpandLimit = 'SET_AUTO_EXPAND_LIMIT',
toggleSettingsVisibility = 'TOGGLE_SETTINGS_VISIBILITY',
setNodeOrder = 'SET_NODE_ORDER',
selectTopic = 'SELECT_TOPIC', selectTopic = 'SELECT_TOPIC',
showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION', showUpdateNotification = 'SHOW_UPDATE_NOTIFICATION',
showUpdateDetails = 'SHOW_UPDATE_DETAILS', showUpdateDetails = 'SHOW_UPDATE_DETAILS',
} }
export interface CustomAction extends Action { export interface CustomAction extends Action {
type: ActionTypes, type: ActionTypes,
autoExpandLimit?: number
nodeOrder?: NodeOrder
selectedTopic?: q.TreeNode selectedTopic?: q.TreeNode
showUpdateNotification?: boolean showUpdateNotification?: boolean
showUpdateDetails?: boolean showUpdateDetails?: boolean
@@ -28,36 +22,18 @@ export interface CustomAction extends Action {
export interface AppState { export interface AppState {
tooBigReducer: TooBigOfState tooBigReducer: TooBigOfState
settings: SettingsState,
publish: PublishState publish: PublishState
connection: ConnectionState connection: ConnectionState
} }
export interface TooBigOfState { export interface TooBigOfState {
settings: SettingsState,
selectedTopic?: q.TreeNode selectedTopic?: q.TreeNode
showUpdateNotification?: boolean showUpdateNotification?: boolean
showUpdateDetails: boolean showUpdateDetails: boolean
} }
export interface SettingsState {
autoExpandLimit: number
visible: boolean
nodeOrder: NodeOrder
}
export enum NodeOrder {
none = 'none',
messages = '#messages',
abc = 'abc',
topics = '#topics',
}
const initialBigState: TooBigOfState = { const initialBigState: TooBigOfState = {
settings: {
autoExpandLimit: 0,
nodeOrder: NodeOrder.none,
visible: false,
},
selectedTopic: undefined, selectedTopic: undefined,
showUpdateDetails: false, showUpdateDetails: false,
} }
@@ -69,27 +45,6 @@ const tooBigReducer: Reducer<TooBigOfState | undefined, CustomAction> = (state =
trackEvent(action.type) trackEvent(action.type)
console.log(action, state) console.log(action, state)
switch (action.type) { switch (action.type) {
case ActionTypes.setAutoExpandLimit:
if (action.autoExpandLimit === undefined) {
return state
}
return {
...state,
settings: {
...state.settings,
autoExpandLimit: action.autoExpandLimit,
},
}
case ActionTypes.toggleSettingsVisibility:
return {
...state,
settings: {
...state.settings,
visible: !state.settings.visible,
},
}
case ActionTypes.selectTopic: case ActionTypes.selectTopic:
if (!action.selectedTopic) { if (!action.selectedTopic) {
return state return state
@@ -99,15 +54,6 @@ const tooBigReducer: Reducer<TooBigOfState | undefined, CustomAction> = (state =
selectedTopic: action.selectedTopic, selectedTopic: action.selectedTopic,
} }
case ActionTypes.setNodeOrder:
if (!action.nodeOrder) {
return state
}
return {
...state,
settings: { ...state.settings, nodeOrder: action.nodeOrder },
}
case ActionTypes.showUpdateNotification: case ActionTypes.showUpdateNotification:
return { return {
...state, ...state,
@@ -132,6 +78,7 @@ const reducer = combineReducers({
tooBigReducer, tooBigReducer,
publish: publishReducer, publish: publishReducer,
connection: connectionReducer, connection: connectionReducer,
settings: settingsReducer,
}) })
export default reducer export default reducer