Fix Sidebar & Mouse event target area
Fix clipboard Fix invalid state in sidebar due to missing event termination
This commit is contained in:
@@ -91,7 +91,7 @@ class App extends React.Component<Props, State> {
|
|||||||
}} />
|
}} />
|
||||||
</div>
|
</div>
|
||||||
<div style={this.getStyles().right}>
|
<div style={this.getStyles().right}>
|
||||||
<Sidebar node={this.state.selectedNode} />
|
<Sidebar />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
import * as settingsActions from './Settings'
|
import * as settingsActions from './Settings'
|
||||||
|
import * as treeActions from './Tree'
|
||||||
|
|
||||||
export { settingsActions }
|
export { settingsActions, treeActions }
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
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 Drawer from '@material-ui/core/Drawer'
|
|
||||||
import { Typography } from '@material-ui/core'
|
import { Typography } from '@material-ui/core'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -15,11 +14,13 @@ class NodeStats extends React.Component<Props, {}> {
|
|||||||
public render() {
|
public render() {
|
||||||
const { node } = this.props
|
const { node } = this.props
|
||||||
|
|
||||||
return <div>
|
return (
|
||||||
<Typography>Messages: #{node.messages}</Typography>
|
<div>
|
||||||
<Typography>Subtopics: {node.leafCount()}</Typography>
|
<Typography>Messages: #{node.messages}</Typography>
|
||||||
<Typography>Messages Subtopics: #{node.leafMessageCount()}</Typography>
|
<Typography>Subtopics: {node.leafCount()}</Typography>
|
||||||
</div>
|
<Typography>Messages Subtopics: #{node.leafMessageCount()}</Typography>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,6 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { AppState } from '../../reducers'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography } from '@material-ui/core'
|
import { ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography } from '@material-ui/core'
|
||||||
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
|
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
|
||||||
@@ -63,9 +65,11 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return <div className={this.props.classes.drawer}>
|
return (
|
||||||
{this.renderNode()}
|
<div className={this.props.classes.drawer}>
|
||||||
</div>
|
{this.renderNode()}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderNode() {
|
private renderNode() {
|
||||||
@@ -74,33 +78,41 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
const copyTopic = node ? <Copy value={node.path()} /> : null
|
const copyTopic = node ? <Copy value={node.path()} /> : null
|
||||||
const copyValue = node && node.message ? <Copy value={node.message.value} /> : null
|
const copyValue = node && node.message ? <Copy value={node.message.value} /> : null
|
||||||
|
|
||||||
return <div>
|
return (
|
||||||
<ExpansionPanel key="topic" defaultExpanded={true}>
|
<div>
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
<ExpansionPanel key="topic" defaultExpanded={true}>
|
||||||
<Typography className={classes.heading}>Topic {copyTopic}</Typography>
|
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
||||||
</ExpansionPanelSummary>
|
<Typography className={classes.heading}>Topic {copyTopic}</Typography>
|
||||||
<ExpansionPanelDetails>
|
</ExpansionPanelSummary>
|
||||||
<Topic node={this.props.node} didSelectNode={this.updateNode} />
|
<ExpansionPanelDetails>
|
||||||
</ExpansionPanelDetails>
|
<Topic node={this.props.node} didSelectNode={this.updateNode} />
|
||||||
</ExpansionPanel>
|
</ExpansionPanelDetails>
|
||||||
<ExpansionPanel key="value" defaultExpanded={true}>
|
</ExpansionPanel>
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
<ExpansionPanel key="value" defaultExpanded={true}>
|
||||||
<Typography className={classes.heading}>Value {copyValue}</Typography>
|
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
||||||
</ExpansionPanelSummary>
|
<Typography className={classes.heading}>Value {copyValue}</Typography>
|
||||||
<ExpansionPanelDetails>
|
</ExpansionPanelSummary>
|
||||||
<ValueRenderer node={this.state.node} />
|
<ExpansionPanelDetails>
|
||||||
</ExpansionPanelDetails>
|
<ValueRenderer node={this.props.node} />
|
||||||
</ExpansionPanel>
|
</ExpansionPanelDetails>
|
||||||
<ExpansionPanel defaultExpanded={true}>
|
</ExpansionPanel>
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
<ExpansionPanel defaultExpanded={true}>
|
||||||
<Typography className={classes.heading}>Stats</Typography>
|
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
|
||||||
</ExpansionPanelSummary>
|
<Typography className={classes.heading}>Stats</Typography>
|
||||||
<ExpansionPanelDetails>
|
</ExpansionPanelSummary>
|
||||||
<NodeStats node={this.state.node} />
|
<ExpansionPanelDetails>
|
||||||
</ExpansionPanelDetails>
|
{this.props.node ? <NodeStats node={this.props.node} /> : null}
|
||||||
</ExpansionPanel>
|
</ExpansionPanelDetails>
|
||||||
</div>
|
</ExpansionPanel>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(Sidebar.styles, { withTheme: true })(Sidebar)
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
node: state.selectedTopic,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(Sidebar.styles, { withTheme: true })(connect(mapStateToProps)(Sidebar))
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ class Topic extends React.Component<Props, {}> {
|
|||||||
.map(node => node.sourceEdge)
|
.map(node => node.sourceEdge)
|
||||||
.filter(edge => Boolean(edge))
|
.filter(edge => Boolean(edge))
|
||||||
.map(edge =>
|
.map(edge =>
|
||||||
[<Button
|
[(
|
||||||
|
<Button
|
||||||
onClick={() => this.setState({ node: edge!.target })}
|
onClick={() => this.setState({ node: edge!.target })}
|
||||||
size="small"
|
size="small"
|
||||||
color="secondary"
|
color="secondary"
|
||||||
@@ -39,7 +40,8 @@ class Topic extends React.Component<Props, {}> {
|
|||||||
key={edge!.hash()}
|
key={edge!.hash()}
|
||||||
>
|
>
|
||||||
{edge!.name}
|
{edge!.name}
|
||||||
</Button>],
|
</Button>
|
||||||
|
)],
|
||||||
)
|
)
|
||||||
|
|
||||||
if (breadCrumps.length === 0) {
|
if (breadCrumps.length === 0) {
|
||||||
|
|||||||
@@ -118,8 +118,7 @@ class Tree extends React.Component<Props, TreeState> {
|
|||||||
name="/"
|
name="/"
|
||||||
collapsed={false}
|
collapsed={false}
|
||||||
key="rootNode"
|
key="rootNode"
|
||||||
lastUpdate={0}
|
lastUpdate={this.state.tree.lastUpdate}
|
||||||
performanceCallback={this.performanceCallback}
|
|
||||||
/>
|
/>
|
||||||
</Typography>
|
</Typography>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { treeActions } from '../../actions'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { withStyles, Theme } from '@material-ui/core/styles'
|
import { withStyles, Theme } from '@material-ui/core/styles'
|
||||||
|
|
||||||
@@ -29,6 +32,7 @@ const styles = (theme: Theme) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
actions: any
|
||||||
lastUpdate: number
|
lastUpdate: number
|
||||||
animateChages: boolean
|
animateChages: boolean
|
||||||
isRoot?: boolean
|
isRoot?: boolean
|
||||||
@@ -39,6 +43,7 @@ interface Props {
|
|||||||
didSelectNode?: (node: q.TreeNode) => void
|
didSelectNode?: (node: q.TreeNode) => void
|
||||||
classes: any
|
classes: any
|
||||||
autoExpandLimit: number
|
autoExpandLimit: number
|
||||||
|
style?: React.CSSProperties
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -168,13 +173,13 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
key={this.props.treeNode.hash()}
|
key={this.props.treeNode.hash()}
|
||||||
className={`${classes.node} ${!this.props.isRoot ? classes.hover : ''}`}
|
className={`${classes.node} ${!this.props.isRoot ? classes.hover : ''}`}
|
||||||
onClick={this.didClickNode}
|
onClick={this.didClickNode}
|
||||||
|
style={this.props.style}
|
||||||
>
|
>
|
||||||
<span ref={this.titleRef} style={animation}>
|
<span ref={this.titleRef} style={animation}>
|
||||||
<TreeNodeTitle
|
<TreeNodeTitle
|
||||||
collapsed={this.collapsed()}
|
collapsed={this.collapsed()}
|
||||||
treeNode={this.props.treeNode}
|
treeNode={this.props.treeNode}
|
||||||
name={this.props.name}
|
name={this.props.name}
|
||||||
didSelectNode={this.props.didSelectNode}
|
|
||||||
/>
|
/>
|
||||||
</span>
|
</span>
|
||||||
{this.renderNodes()}
|
{this.renderNodes()}
|
||||||
@@ -185,7 +190,7 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
private didClickNode = (event: React.MouseEvent) => {
|
private didClickNode = (event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
this.toggle()
|
this.toggle()
|
||||||
this.props.didSelectNode && this.props.didSelectNode(this.props.treeNode)
|
this.props.actions.selectTopic(this.props.treeNode)
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderNodes() {
|
private renderNodes() {
|
||||||
@@ -202,4 +207,10 @@ class TreeNode extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withStyles(styles)(TreeNode)
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
|
return {
|
||||||
|
actions: bindActionCreators(treeActions, dispatch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles)(connect(null, mapDispatchToProps)(TreeNode))
|
||||||
|
|||||||
@@ -49,13 +49,14 @@ class TreeNodeSubnodes extends React.Component<Props, {}> {
|
|||||||
|
|
||||||
const nodes = this.sortedNodes()
|
const nodes = this.sortedNodes()
|
||||||
const listItems = nodes.map(node => (
|
const listItems = nodes.map(node => (
|
||||||
<div key={node.hash()} style={listItemStyle}>
|
<div key={node.hash()}>
|
||||||
<TreeNode
|
<TreeNode
|
||||||
animateChages={this.props.animateChanges}
|
animateChages={this.props.animateChanges}
|
||||||
treeNode={node}
|
treeNode={node}
|
||||||
didSelectNode={this.props.didSelectNode}
|
didSelectNode={this.props.didSelectNode}
|
||||||
autoExpandLimit={this.props.autoExpandLimit}
|
autoExpandLimit={this.props.autoExpandLimit}
|
||||||
lastUpdate={node.lastUpdate}
|
lastUpdate={node.lastUpdate}
|
||||||
|
style={listItemStyle}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { treeActions } from '../../actions'
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import { withTheme, Theme } from '@material-ui/core/styles'
|
import { withTheme, Theme } from '@material-ui/core/styles'
|
||||||
|
|
||||||
export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
|
export interface TreeNodeProps extends React.HTMLAttributes<HTMLElement> {
|
||||||
treeNode: q.TreeNode
|
treeNode: q.TreeNode
|
||||||
|
actions: any
|
||||||
name?: string | undefined
|
name?: string | undefined
|
||||||
collapsed?: boolean | undefined
|
collapsed?: boolean | undefined
|
||||||
didSelectNode?: (node: q.TreeNode) => void
|
|
||||||
theme: Theme
|
theme: Theme
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -23,9 +26,10 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private didSelectNode = () => {
|
private didSelectNode = (event: React.MouseEvent) => {
|
||||||
|
event.stopPropagation()
|
||||||
if (this.props.treeNode.message) {
|
if (this.props.treeNode.message) {
|
||||||
this.props.didSelectNode && this.props.didSelectNode(this.props.treeNode)
|
this.props.actions.selectTopic(this.props.treeNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +63,7 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
|||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
padding: '0',
|
padding: '0',
|
||||||
paddingLeft: '5px',
|
marginLeft: '5px',
|
||||||
display: 'inline-block',
|
display: 'inline-block',
|
||||||
}
|
}
|
||||||
return this.props.treeNode.message
|
return this.props.treeNode.message
|
||||||
@@ -85,4 +89,10 @@ class TreeNodeTitle extends React.Component<TreeNodeProps, {}> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default withTheme()(TreeNodeTitle)
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
|
return {
|
||||||
|
actions: bindActionCreators(treeActions, dispatch),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withTheme()(connect(null, mapDispatchToProps)(TreeNodeTitle))
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ const initialAppState = {
|
|||||||
nodeOrder: NodeOrder.none,
|
nodeOrder: NodeOrder.none,
|
||||||
visible: false,
|
visible: false,
|
||||||
},
|
},
|
||||||
|
selectedNode: undefined,
|
||||||
}
|
}
|
||||||
const store = createStore(reducers, initialAppState)
|
const store = createStore(reducers, initialAppState)
|
||||||
|
|
||||||
|
|||||||
@@ -1,19 +1,29 @@
|
|||||||
import { Reducer, Action } from 'redux'
|
import { Reducer, Action } from 'redux'
|
||||||
|
import * as q from '../../../backend/src/Model'
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
setAutoExpandLimit = 'SET_AUTO_EXPAND_LIMIT',
|
setAutoExpandLimit = 'SET_AUTO_EXPAND_LIMIT',
|
||||||
toggleSettingsVisibility = 'TOGGLE_SETTINGS_VISIBILITY',
|
toggleSettingsVisibility = 'TOGGLE_SETTINGS_VISIBILITY',
|
||||||
setNodeOrder = 'SET_NODE_ORDER',
|
setNodeOrder = 'SET_NODE_ORDER',
|
||||||
|
selectTopic = 'SELECT_TOPIC',
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SettingsAction extends Action {
|
interface CustomAction extends Action {
|
||||||
type: ActionTypes,
|
type: ActionTypes,
|
||||||
autoExpandLimit?: number
|
autoExpandLimit?: number
|
||||||
nodeOrder?: NodeOrder
|
nodeOrder?: NodeOrder
|
||||||
|
selectedTopic?: q.TreeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AppState {
|
export interface AppState {
|
||||||
settings: SettingsModel
|
settings: SettingsState,
|
||||||
|
selectedTopic?: q.TreeNode
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SettingsState {
|
||||||
|
autoExpandLimit: number
|
||||||
|
visible: boolean
|
||||||
|
nodeOrder: NodeOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum NodeOrder {
|
export enum NodeOrder {
|
||||||
@@ -23,13 +33,7 @@ export enum NodeOrder {
|
|||||||
topics = '#topics',
|
topics = '#topics',
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SettingsModel {
|
const reducer: Reducer<AppState | undefined, CustomAction> = (state, action) => {
|
||||||
autoExpandLimit: number
|
|
||||||
visible: boolean
|
|
||||||
nodeOrder: NodeOrder
|
|
||||||
}
|
|
||||||
|
|
||||||
const reducer: Reducer<AppState | undefined, SettingsAction> = (state, action) => {
|
|
||||||
if (!state) {
|
if (!state) {
|
||||||
throw Error('No initial state')
|
throw Error('No initial state')
|
||||||
}
|
}
|
||||||
@@ -57,6 +61,15 @@ const reducer: Reducer<AppState | undefined, SettingsAction> = (state, action) =
|
|||||||
nodeOrder: state.settings.nodeOrder,
|
nodeOrder: state.settings.nodeOrder,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
case ActionTypes.selectTopic:
|
||||||
|
if (!action.selectedTopic) {
|
||||||
|
return state
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
settings: state.settings,
|
||||||
|
selectedTopic: action.selectedTopic,
|
||||||
|
}
|
||||||
case ActionTypes.setNodeOrder:
|
case ActionTypes.setNodeOrder:
|
||||||
if (!action.nodeOrder) {
|
if (!action.nodeOrder) {
|
||||||
return state
|
return state
|
||||||
|
|||||||
Reference in New Issue
Block a user