Improve ui & performance

This commit is contained in:
Thomas Nordquist
2019-01-03 11:14:38 +01:00
parent 2b7e9a5ef7
commit 87dafc9c89
18 changed files with 676 additions and 364 deletions

View File

@@ -0,0 +1,41 @@
import * as React from 'react'
import * as q from '../../../../backend/src/Model'
// import Drawer from '@material-ui/core/Drawer'
import { Typography } from '@material-ui/core'
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
interface Props {
node: q.TreeNode,
classes: any,
theme: Theme
}
interface State {
node?: q.TreeNode | undefined
}
class NodeStats extends React.Component<Props, State> {
constructor(props: any) {
super(props)
}
public static styles: StyleRulesCallback<string> = (theme: Theme) => {
return {
}
}
public render() {
const leafes = this.props.node.leafes()
const leafMessages = leafes
.map(leaf => leaf.messages)
.reduce((a, b) => a + b)
return <Typography>
<p>Messages: #{this.props.node.messages}</p>
<p>Subtopics: {leafes.length}</p>
<p>Messages Subtopics: #{leafMessages}</p>
</Typography>
}
}
export default withStyles(NodeStats.styles, { withTheme: true })(NodeStats)

View File

@@ -0,0 +1,105 @@
import * as React from 'react'
import * as q from '../../../../backend/src/Model'
// import Drawer from '@material-ui/core/Drawer'
import ExpansionPanel from '@material-ui/core/ExpansionPanel'
import ExpansionPanelSummary from '@material-ui/core/ExpansionPanelSummary'
import ExpansionPanelDetails from '@material-ui/core/ExpansionPanelDetails'
import ExpandMore from '@material-ui/icons/ExpandMore'
import ValueRenderer from './ValueRenderer'
import NodeStats from './NodeStats'
import Topic from './Topic'
import { Typography } from '@material-ui/core'
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
interface Props {
node?: q.TreeNode | undefined,
classes: any,
theme: Theme
}
interface State {
node?: q.TreeNode | undefined
}
class Sidebar extends React.Component<Props, State> {
private updateNode: (node?: q.TreeNode | undefined) => void
constructor(props: any) {
super(props)
this.state = {}
this.updateNode = (node) => {
if (!node) {
this.setState(this.state)
} else {
this.setState({ node })
}
}
}
public static styles: StyleRulesCallback<string> = (theme: Theme) => {
return {
drawer: {
display: 'block',
height: '100%',
},
valuePaper: {
margin: `${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px ${theme.spacing.unit}px`,
},
heading: {
fontSize: theme.typography.pxToRem(15),
fontWeight: theme.typography.fontWeightRegular,
},
}
}
public componentWillReceiveProps(nextProps: Props) {
this.props.node && this.props.node.removeListener('update', this.updateNode)
nextProps.node && nextProps.node.on('update', this.updateNode)
nextProps.node && this.updateNode(nextProps.node)
}
private open(): boolean {
return true
}
public render() {
return <div className={this.props.classes.drawer}>
{this.renderNode()}
</div>
}
private renderNode() {
const { classes } = this.props
if (!this.state.node) {
return null
}
return <div>
<ExpansionPanel key="topic" defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<Typography className={classes.heading}>Topic</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<Topic node={this.state.node} />
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel key="value" defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<Typography className={classes.heading}>Value</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<ValueRenderer node={this.state.node} />
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel key="stats" defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<Typography className={classes.heading}>Stats</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<NodeStats node={this.state.node} />
</ExpansionPanelDetails>
</ExpansionPanel>
</div>
}
}
export default withStyles(Sidebar.styles, { withTheme: true })(Sidebar)

View File

@@ -0,0 +1,52 @@
import * as React from 'react'
import * as q from '../../../../backend/src/Model'
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
interface Props {
classes: any
theme: Theme
node: q.TreeNode
selected?: q.TreeNode
}
class Topic extends React.Component<Props, {}> {
public static styles: StyleRulesCallback<string> = (theme: Theme) => ({
button: {
textTransform: 'none',
padding: '3px 5px 3px 5px',
minWidth: '30px',
},
})
public render() {
const { node } = this.props
let i = 0
const breadCrumps = node.branch()
.map(node => node.sourceEdge)
.filter(edge => Boolean(edge))
.map(edge =>
[<Button
onClick={() => this.setState({ node: edge!.target })}
size="small"
color="secondary"
className={this.props.classes.button}
key={edge!.hash()}
>
{edge!.name}
</Button>],
)
if (breadCrumps.length === 0) {
return null
}
const joinedBreadCrumps = breadCrumps.reduce((prev, current) =>
prev.concat([<span key={i += 1}>/</span>]).concat(current),
)
return <span style={{ lineHeight: '2.2em' }}>{joinedBreadCrumps}</span>
}
}
export default withStyles(Topic.styles, { withTheme: true })(Topic)

View File

@@ -0,0 +1,82 @@
import * as React from 'react'
import * as q from '../../../../backend/src/Model'
import { default as ReactJson } from 'react-json-view'
import { withTheme, Theme } from '@material-ui/core/styles'
interface Props {
node?: q.TreeNode | undefined
theme: Theme
}
interface State {
node?: q.TreeNode | undefined
}
class ValueRenderer extends React.Component<Props, State> {
private updateNode: (node?: q.TreeNode | undefined) => void
constructor(props: any) {
super(props)
this.state = {}
this.updateNode = (node) => {
if (!node) {
this.setState(this.state)
} else {
this.setState({ node })
}
}
}
public componentWillReceiveProps(nextProps: Props) {
this.props.node && this.props.node.removeListener('update', this.updateNode)
nextProps.node && nextProps.node.on('update', this.updateNode)
nextProps.node && this.updateNode(nextProps.node)
}
private style = (theme: Theme) => {
}
public render() {
const node = this.props.node
if (!node || !node.message) {
return null
}
let json
try {
json = JSON.parse(node.message.value)
} catch (error) {
return this.renderRawValue(node.message.value)
}
if (typeof json === 'string') {
return this.renderRawValue(node.message.value)
} else if (typeof json === 'number') {
return this.renderRawValue(node.message.value)
} else {
const theme = this.props.theme.palette.type === 'dark' ? 'monokai' : 'bright:inverted'
return <ReactJson
style={{ width: '100%' }}
src={json}
theme={theme}
onEdit={(val) => {
console.log(val)
}} />
}
}
private renderRawValue(value: string) {
const style: React.CSSProperties = {
wordBreak: 'break-all',
width: '100%',
overflow: 'scroll',
display: 'block',
lineHeight: '1.2em',
padding: '12px 5px 12px 5px',
}
return <pre style={style}><code>{value}</code></pre>
}
}
export default withTheme()(ValueRenderer)

View File

@@ -0,0 +1,3 @@
import Sidebar from './Sidebar'
export { Sidebar }