Add pause feature

This commit is contained in:
Thomas Nordquist
2019-04-03 17:57:19 +02:00
parent 8266a87417
commit 094d795b39
6 changed files with 191 additions and 8 deletions

View File

@@ -57,3 +57,13 @@ export const showTree = (tree?: q.Tree<TopicViewModel>) => (dispatch: Dispatch<a
type: ActionTypes.TREE_SHOW_TREE,
})
}
export const togglePause = (tree?: q.Tree<TopicViewModel>) => (dispatch: Dispatch<any>, getState: () => AppState): AnyAction => {
const paused = getState().tree.paused
const tree = getState().tree.tree
// tree && tree.applyUnmergedChanges()
return dispatch({
type: paused ? ActionTypes.TREE_RESUME_UPDATES : ActionTypes.TREE_PAUSE_UPDATES,
})
}

View File

@@ -0,0 +1,108 @@
import * as React from 'react'
import * as q from '../../../backend/src/Model'
import CustomIconButton from './CustomIconButton'
import Pause from '@material-ui/icons/PauseCircleFilled'
import Resume from '@material-ui/icons/PlayCircleFilled'
import { AppState } from '../reducers'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { treeActions } from '../actions'
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
import { Tooltip } from '@material-ui/core';
const styles: StyleRulesCallback = theme => ({ })
interface Props {
classes: any
actions: {
tree: typeof treeActions,
}
paused: boolean
tree?: q.Tree<any>
}
class PauseButton extends React.Component<Props, {changes: number}> {
private timer?: any
constructor(props: Props) {
super(props)
this.state = { changes: 0 }
}
public componentDidMount() {
this.timer = setInterval(() => {
if (!this.props.paused || !this.props.tree) {
return
}
const changes = this.props.tree.unmergedChanges()
if (this.state.changes !== changes.length) {
this.setState({ changes: changes.length })
}
}, 300)
}
public componentWillUnmount() {
this.timer && clearInterval(this.timer)
}
public render() {
const { actions, classes } = this.props
return (
<div style={{ display: 'inline-flex' }}>
<span>
<CustomIconButton onClick={this.props.actions.tree.togglePause} >
{this.props.paused ? this.renderResume() : this.renderPause()}
</CustomIconButton>
</span>
{this.props.paused ? this.renderBufferStats() : null}
</div>
)
}
private renderResume() {
return (
<Tooltip title="Resumes updating the tree, after applying all recorded changes">
<Resume />
</Tooltip>
)
}
private renderPause() {
return (
<Tooltip title="Stops all updates, records changes until the buffer is full.">
<Pause />
</Tooltip>
)
}
private renderBufferStats() {
if (!this.props.tree) {
return
}
return (
<span>
{this.state.changes} changes<br />
buffer at {Math.round(this.props.tree.unmergedChanges().fillState() * 10000) / 100}%
</span>
)
}
}
const mapStateToProps = (state: AppState) => {
return {
paused: state.tree.paused,
tree: state.tree.tree,
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: {
tree: bindActionCreators(treeActions, dispatch),
},
}
}
export default connect(mapStateToProps, mapDispatchToProps)(withStyles(styles)(PauseButton))

View File

@@ -7,7 +7,7 @@ import Search from '@material-ui/icons/Search'
import { AppState } from '../reducers'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { connectionActions, settingsActions } from '../actions'
import { connectionActions, settingsActions, treeActions } from '../actions'
import { fade } from '@material-ui/core/styles/colorManipulator'
import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
import {
@@ -18,6 +18,7 @@ import {
Toolbar,
Typography,
} from '@material-ui/core'
import PauseButton from './PauseButton';
const styles: StyleRulesCallback = theme => ({
title: {
@@ -72,7 +73,7 @@ const styles: StyleRulesCallback = theme => ({
disconnect: {
margin: 'auto 8px auto auto',
color: theme.palette.primary.contrastText,
}
},
})
interface Props {
@@ -101,10 +102,11 @@ class TitleBar extends React.Component<Props, {}> {
</IconButton>
<Typography className={classes.title} variant="h6" color="inherit">MQTT Explorer</Typography>
{this.renderSearch()}
<PauseButton />
<Button className={classes.disconnect} onClick={actions.connection.disconnect}>
Disconnect <CloudOff style={{ marginRight: '8px', paddingLeft: '8px' }}/>
</Button>
<ConnectionHealthIndicator />
<ConnectionHealthIndicator withBackground={true} />
</Toolbar>
</AppBar>
)

View File

@@ -25,6 +25,7 @@ interface Props {
autoExpandLimit: number
highlightTopicUpdates: boolean
selectTopicWithMouseOver: boolean
paused: boolean
}
interface State {
@@ -78,7 +79,10 @@ class Tree extends React.PureComponent<Props, State> {
this.updateTimer && clearTimeout(this.updateTimer)
this.updateTimer = undefined
this.renderTime = performance.now()
this.props.tree && this.props.tree.applyUnmergedChanges()
if (!this.props.paused) {
this.props.tree && this.props.tree.applyUnmergedChanges()
}
window.requestIdleCallback(() => {
this.setState({ lastUpdate: this.renderTime })
}, { timeout: 100 })
@@ -126,6 +130,7 @@ class Tree extends React.PureComponent<Props, State> {
const mapStateToProps = (state: AppState) => {
return {
tree: state.tree.tree,
paused: state.tree.paused,
filter: state.tree.filter,
host: state.connection.host,
autoExpandLimit: state.settings.autoExpandLimit,

View File

@@ -7,6 +7,7 @@ export interface TreeState {
tree?: q.Tree<TopicViewModel>
selectedTopic?: q.TreeNode<TopicViewModel>
filter?: string
paused: boolean
}
export type Action = ShowTree | SelectTopic
@@ -14,6 +15,8 @@ export type Action = ShowTree | SelectTopic
export enum ActionTypes {
TREE_SHOW_TREE = 'TREE_SHOW_TREE',
TREE_SELECT_TOPIC = 'TREE_SELECT_TOPIC',
TREE_RESUME_UPDATES = 'TREE_RESUME_UPDATES',
TREE_PAUSE_UPDATES = 'TREE_PAUSE_UPDATES',
}
export interface ShowTree {
@@ -27,11 +30,26 @@ export interface SelectTopic {
selectedTopic?: q.TreeNode<TopicViewModel>
}
const initialState: TreeState = { }
export interface SetPause {
type: ActionTypes.TREE_PAUSE_UPDATES | ActionTypes.TREE_RESUME_UPDATES
}
const initialState: TreeState = {
paused: false,
}
const setPaused = (pause: boolean) => (state: TreeState, action: ShowTree) => {
return {
...state,
paused: pause,
}
}
export const treeReducer = createReducer(initialState, {
TREE_SHOW_TREE: showTree,
TREE_SELECT_TOPIC: selectTopic,
TREE_PAUSE_UPDATES: setPaused(true),
TREE_RESUME_UPDATES: setPaused(false),
})
function showTree(state: TreeState, action: ShowTree) {