Add pane resizing

Refactor styles
Update autoExpand with filtered result count
Add redux batch reducer
This commit is contained in:
Thomas Nordquist
2019-01-23 11:54:12 +01:00
parent 37694d38b0
commit 6b0f2085e5
10 changed files with 230 additions and 91 deletions

View File

@@ -13,6 +13,7 @@ import Tree from './components/Tree/Tree'
import UpdateNotifier from './UpdateNotifier'
import { connect } from 'react-redux'
import ErrorBoundary from './ErrorBoundary'
import { default as SplitPane } from 'react-split-pane'
interface Props {
name: string
@@ -29,22 +30,33 @@ class App extends React.Component<Props, {}> {
public render() {
const { settingsVisible } = this.props
const { content, contentShift, centerContent, left, right } = this.props.classes
const { content, contentShift, centerContent, paneDefaults, heightProperty } = this.props.classes
return (
<div className={centerContent}>
<CssBaseline />
<ErrorBoundary>
<Settings />
<div className={settingsVisible ? contentShift : content}>
<div className={`${settingsVisible ? contentShift : content} ${heightProperty}`}>
<TitleBar />
<div className={centerContent}>
<div className={this.props.classes.left}>
<SplitPane
step={48}
primary="second"
className={heightProperty}
split="vertical"
minSize={250}
defaultSize={500}
allowResize={true}
pane1Style={{ overflow: 'hidden' }}
>
<div className={paneDefaults}>
<Tree />
</div>
<div className={right}>
<div className={paneDefaults}>
<Sidebar connectionId={this.props.connectionId} />
</div>
</SplitPane>
</div>
</div>
<UpdateNotifier />
@@ -65,24 +77,16 @@ const mapStateToProps = (state: AppState) => {
const styles = (theme: Theme) => {
const drawerWidth = 300
return {
left: {
heightProperty: {
height: 'calc(100vh - 64px) !important',
},
paneDefaults: {
backgroundColor: theme.palette.background.default,
color: theme.palette.text.primary,
height: 'calc(100vh - 64px)',
float: 'left' as 'left',
overflowY: 'scroll' as 'scroll',
overflowX: 'hidden' as 'hidden',
display: 'block' as 'block',
width: '60vw',
},
right: {
height: 'calc(100vh - 64px)',
color: theme.palette.text.primary,
float: 'left' as 'left',
width: '40vw',
overflowY: 'scroll' as 'scroll',
overflowX: 'hidden' as 'hidden',
display: 'block' as 'block',
},
centerContent: {
width: '100vw',

View File

@@ -4,6 +4,8 @@ import { Dispatch } from 'redux'
import { showTree } from './Tree'
import { AppState } from '../reducers'
import * as q from '../../../backend/src/Model'
import { batchActions, enableBatching, batchDispatchMiddleware } from 'redux-batched-actions';
import { autoExpandLimitSet } from '../components/Settings';
export const setAutoExpandLimit = (autoExpandLimit: number = 0): Action => {
return {
@@ -34,7 +36,7 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, get
})
if (!filterStr || !tree) {
dispatch(showTree(tree))
dispatch(batchActions([setAutoExpandLimit(0), showTree(tree)]))
return
}
@@ -67,5 +69,21 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, get
nextTree.updateWithConnection(tree.updateSource, tree.connectionId, nodeFilter)
}
dispatch(showTree(nextTree))
dispatch(batchActions([setAutoExpandLimit(autoExpandLimitForTree(nextTree)), showTree(nextTree)]))
}
function autoExpandLimitForTree(tree: q.Tree) {
if (!tree) {
return 0
}
function closestExistingLimit(i: number): number {
const sorted = autoExpandLimitSet.sort((a, b) => Math.abs(a.limit - i) - Math.abs(b.limit - i))
console.log('sorted', i, sorted)
return sorted[0]!.limit
}
const count = tree.childTopicCount()
const calculatedLimit = Math.max(7 - Math.log(count), 0) * 2
return closestExistingLimit(calculatedLimit)
}

View File

@@ -20,6 +20,23 @@ import { settingsActions, treeActions } from '../actions'
import { TopicOrder } from '../reducers/Settings'
import BrokerStatistics from './BrokerStatistics'
export const autoExpandLimitSet = [{
limit: 0,
name: 'Collapsed',
}, {
limit: 2,
name: 'Few',
}, {
limit: 3,
name: 'Some',
}, {
limit: 10,
name: 'Most',
}, {
limit: 1E6,
name: 'All',
}]
const styles: StyleRulesCallback = theme => ({
drawer: {
backgroundColor: theme.palette.background.default,
@@ -87,6 +104,8 @@ class Settings extends React.Component<Props, {}> {
private renderAutoExpand() {
const { classes, autoExpandLimit } = this.props
const limits = autoExpandLimitSet.map(limit => <MenuItem key={limit.limit} value={limit.limit}>{limit.name}</MenuItem>)
return (
<div style={{ padding: '8px', display: 'flex' }}>
<InputLabel htmlFor="auto-expand" style={{ flex: '1', marginTop: '8px' }}>Auto Expand</InputLabel>
@@ -98,11 +117,7 @@ class Settings extends React.Component<Props, {}> {
className={classes.input}
style={{ flex: '1' }}
>
<MenuItem value={0}><em>Collapsed</em></MenuItem>
<MenuItem value={2}>Few</MenuItem>
<MenuItem value={3}>Some</MenuItem>
<MenuItem value={10}>Most</MenuItem>
<MenuItem value={1E6}>All</MenuItem>
{limits}
</Select>
</div>
)

View File

@@ -26,11 +26,11 @@ const styles = (theme: Theme) => {
display: 'block',
marginLeft: '10px',
},
hover: {
'&:hover': {
backgroundColor: 'rgba(80, 80, 80, 0.35)',
},
},
// hover: {
// '&:hover': {
// backgroundColor: 'rgba(80, 80, 80, 0.35)',
// },
// },
topicSelect: {
float: 'right' as 'right',
opacity: 0,
@@ -51,7 +51,7 @@ interface Props {
performanceCallback?: ((ms: number) => void) | undefined
autoExpandLimit: number
classes: any
style?: React.CSSProperties
className?: string
}
interface State {
@@ -68,6 +68,7 @@ class TreeNode extends React.Component<Props, State> {
private willUpdateTime: number = performance.now()
private titleRef?: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>()
private nodeRef?: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>()
private topicSelectRef?: React.RefObject<HTMLDivElement> = React.createRef<HTMLDivElement>()
private subnodesDidchange = () => {
@@ -119,6 +120,7 @@ class TreeNode extends React.Component<Props, State> {
this.removeSubscriber(treeNode)
this.topicSelectRef = undefined
this.titleRef = undefined
this.nodeRef = undefined
}
private stateHasChanged(newState: State) {
@@ -177,11 +179,11 @@ class TreeNode extends React.Component<Props, State> {
return (
<div
key={this.props.treeNode.hash()}
className={`${classes.node} ${!this.props.isRoot ? classes.hover : ''}`}
className={`${classes.node} ${this.props.className}`}
onClick={this.didClickNode}
style={this.props.style}
onMouseOver={this.mouseOver}
onMouseOut={this.mouseOut}
ref={this.nodeRef}
>
<span ref={this.titleRef} style={animation}>
<TreeNodeTitle
@@ -191,14 +193,6 @@ class TreeNode extends React.Component<Props, State> {
lastUpdate={this.props.treeNode.lastUpdate}
/>
</span>
<div
className={this.props.classes.topicSelect}
ref={this.topicSelectRef}
onClick={this.didSelectNode}
title="Select topic"
>
<LabelImportant style={{ fontSize: '14px' }} />
</div>
{this.renderNodes()}
</div>
)
@@ -206,12 +200,18 @@ class TreeNode extends React.Component<Props, State> {
private mouseOver = (event: React.MouseEvent) => {
event.stopPropagation()
if (this.nodeRef && this.nodeRef.current) {
this.nodeRef.current.style.backgroundColor = 'rgba(100, 100, 100, 0.55)'
}
if (this.topicSelectRef && this.topicSelectRef.current) {
this.topicSelectRef.current.style.opacity = '1'
}
}
private mouseOut = (event: React.MouseEvent) => {
event.stopPropagation()
if (this.nodeRef && this.nodeRef.current) {
this.nodeRef.current.style.backgroundColor = 'inherit'
}
if (this.topicSelectRef && this.topicSelectRef.current) {
this.topicSelectRef.current.style.opacity = '0'
}

View File

@@ -6,6 +6,7 @@ import { AppState } from '../../reducers'
import TreeNode from './TreeNode'
import { connect } from 'react-redux'
import { TopicOrder } from '../../reducers/Settings'
import { Theme, withStyles } from '@material-ui/core'
export interface Props {
lastUpdate: number
@@ -16,6 +17,7 @@ export interface Props {
filter?: string
collapsed?: boolean | undefined
didSelectNode?: (node: q.TreeNode) => void
classes: any
}
interface State {
@@ -69,24 +71,19 @@ class TreeNodeSubnodes extends React.Component<Props, State> {
this.renderMore()
}
const listItemStyle = {
padding: '3px 0px 0px 8px',
}
const nodes = this.sortedNodes().slice(0, this.state.alreadyAdded)
const listItems = nodes.map(node => (
<div key={`${node.hash()}-${this.props.filter}`}>
<TreeNode
animateChages={this.props.animateChanges}
treeNode={node}
lastUpdate={node.lastUpdate}
style={listItemStyle}
/>
</div>
<TreeNode
key={`${node.hash()}-${this.props.filter}`}
animateChages={this.props.animateChanges}
treeNode={node}
lastUpdate={node.lastUpdate}
className={this.props.classes.listItem}
/>
))
return (
<span style={{ display: 'block', clear: 'both' }} >
<span className={this.props.classes.list}>
{listItems}
</span>
)
@@ -100,4 +97,14 @@ const mapStateToProps = (state: AppState) => {
}
}
export default connect(mapStateToProps)(TreeNodeSubnodes)
const styles = (theme: Theme) => ({
list: {
display: 'block' as 'block',
clear: 'both' as 'both',
},
listItem: {
padding: '3px 0px 0px 8px',
},
})
export default withStyles(styles)(connect(mapStateToProps)(TreeNodeSubnodes))

View File

@@ -3,6 +3,7 @@ import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { treeActions } from '../../actions'
import * as q from '../../../../backend/src/Model'
import { withStyles, Theme } from '@material-ui/core'
export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
treeNode: q.TreeNode
@@ -10,62 +11,33 @@ export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
name?: string | undefined
collapsed?: boolean | undefined
lastUpdate: number
classes: any
}
class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
private getStyles() {
return {
collapsedSubnodes: {
color: 'white', // theme.palette.text.secondary,
},
container: {
display: 'block',
},
}
}
private didSelectNode = (event: React.MouseEvent) => {
event.stopPropagation()
private mouseOver = (event: React.MouseEvent) => {
if (this.props.treeNode.message) {
this.props.actions.selectTopic(this.props.treeNode)
}
}
public render() {
const style: React.CSSProperties = {
lineHeight: '1em',
whiteSpace: 'nowrap',
}
return (
<span style={style} onMouseOver={this.didSelectNode}>
<span className={this.props.classes.title} onMouseOver={this.mouseOver}>
{this.renderExpander()} {this.renderSourceEdge()} {this.renderCollapsedSubnodes()} {this.renderValue()}
</span>
)
}
private renderSourceEdge() {
const style: React.CSSProperties = {
fontWeight: 'bold',
overflow: 'hidden',
display: 'inline-block',
}
const name = this.props.name || (this.props.treeNode.sourceEdge && this.props.treeNode.sourceEdge.name)
return <span style={style}>{name}</span>
return <span className={this.props.classes.sourceEdge}>{name}</span>
}
private renderValue() {
const style: React.CSSProperties = {
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
padding: '0',
marginLeft: '5px',
display: 'inline-block',
}
return this.props.treeNode.message && this.props.treeNode.message.length > 0
? <span style={style}> = {this.props.treeNode.message.value.toString()}</span>
? <span className={this.props.classes.value}> = {this.props.treeNode.message.value.toString().slice(0, 120)}</span>
: null
}
@@ -83,7 +55,7 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
}
const messages = this.props.treeNode.leafMessageCount()
return <span style={this.getStyles().collapsedSubnodes}>({this.props.treeNode.childTopicCount()} topics, {messages} messages)</span>
return <span className={this.props.classes.collapsedSubnodes}>({this.props.treeNode.childTopicCount()} topics, {messages} messages)</span>
}
}
@@ -93,4 +65,27 @@ const mapDispatchToProps = (dispatch: any) => {
}
}
export default connect(null, mapDispatchToProps)(TreeNodeTitle)
const styles = (theme: Theme) => ({
value: {
whiteSpace: 'nowrap' as 'nowrap',
overflow: 'hidden' as 'hidden',
textOverflow: 'ellipsis' as 'ellipsis',
padding: '0',
marginLeft: '5px',
display: 'inline-block' as 'inline-block',
},
sourceEdge: {
fontWeight: 'bold' as 'bold',
overflow: 'hidden' as 'hidden',
display: 'inline-block' as 'inline-block',
},
title: {
lineHeight: '1em',
whiteSpace: 'nowrap' as 'nowrap',
},
collapsedSubnodes: {
color: theme.palette.text.secondary,
},
})
export default withStyles(styles)(connect(null, mapDispatchToProps)(TreeNodeTitle))

View File

@@ -3,6 +3,7 @@ import './tracking'
import * as React from 'react'
import * as ReactDOM from 'react-dom'
import reduxThunk from 'redux-thunk'
import { batchDispatchMiddleware } from 'redux-batched-actions';
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import reducers from './reducers'
@@ -17,6 +18,7 @@ const store = createStore(
composeEnhancers(
applyMiddleware(
reduxThunk,
batchDispatchMiddleware,
),
),
)