Add topic publishing sidebar

This commit is contained in:
Thomas Nordquist
2019-01-11 00:40:05 +01:00
parent eb375073f9
commit c3ef9335c0
13 changed files with 292 additions and 15 deletions

32
app/package-lock.json generated
View File

@@ -748,6 +748,11 @@
"multicast-dns-service-types": "^1.1.0"
}
},
"brace": {
"version": "0.11.1",
"resolved": "https://registry.npmjs.org/brace/-/brace-0.11.1.tgz",
"integrity": "sha1-SJb8ydVE7vRfS7dmDbMg07N5/lg="
},
"brace-expansion": {
"version": "1.1.11",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
@@ -1451,6 +1456,11 @@
"resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.0.4.tgz",
"integrity": "sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw=="
},
"diff-match-patch": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.4.tgz",
"integrity": "sha512-Uv3SW8bmH9nAtHKaKSanOQmj2DnlH65fUpcrMdfdaOxUG02QQ4YGZ8AE7kKOMisF7UqvOlGKVYWRvezdncW9lg=="
},
"diffie-hellman": {
"version": "5.0.3",
"resolved": "http://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
@@ -3300,6 +3310,16 @@
"resolved": "https://registry.npmjs.org/lodash.flow/-/lodash.flow-3.5.0.tgz",
"integrity": "sha1-h79AKSuM+D5OjOGjrkIJ4gBxZ1o="
},
"lodash.get": {
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
"integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
},
"lodash.isequal": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.isequal/-/lodash.isequal-4.5.0.tgz",
"integrity": "sha1-QVxEePK8wwEgwizhDtMib30+GOA="
},
"lodash.throttle": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz",
@@ -4183,6 +4203,18 @@
"scheduler": "^0.12.0"
}
},
"react-ace": {
"version": "6.3.2",
"resolved": "https://registry.npmjs.org/react-ace/-/react-ace-6.3.2.tgz",
"integrity": "sha512-eSk0fWvrBe2oqYIYX0njLddLG5H0hemWv5VVoQi5yDSPTjGlSSnzFwdgPyfuwRe8mSARZuRdprPQa5p61hKirw==",
"requires": {
"brace": "^0.11.1",
"diff-match-patch": "^1.0.4",
"lodash.get": "^4.4.2",
"lodash.isequal": "^4.5.0",
"prop-types": "^15.6.2"
}
},
"react-base16-styling": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/react-base16-styling/-/react-base16-styling-0.6.0.tgz",

View File

@@ -32,6 +32,7 @@
"jquery": "^3.3.1",
"lodash.throttle": "^4.1.1",
"moving-average": "^1.0.0",
"react-ace": "^6.3.2",
"react-json-view": "^1.19.1",
"sha1": "^1.1.1",
"socket.io-client": "^2.2.0",

View File

@@ -91,7 +91,7 @@ class App extends React.Component<Props, State> {
}} />
</div>
<div style={this.getStyles().right}>
<Sidebar />
<Sidebar connectionId={this.state.connectionId} />
</div>
</div>
</div>

9
app/src/actions/Tree.ts Normal file
View File

@@ -0,0 +1,9 @@
import { ActionTypes } from '../reducers'
import * as q from '../../../backend/src/Model'
export const selectTopic = (topic: q.TreeNode) => {
return {
selectedTopic: topic,
type: ActionTypes.selectTopic,
}
}

View File

@@ -0,0 +1,165 @@
import * as React from 'react'
import * as q from '../../../../backend/src/Model'
import { makePublishEvent, rendererEvents } from '../../../../events'
import Navigation from '@material-ui/icons/Navigation'
import {
Button, Fab, InputAdornment, FormControlLabel, Radio,
RadioGroup, TextField, Typography,
} from '@material-ui/core'
import * as brace from 'brace'
import { default as AceEditor } from 'react-ace'
// tslint:disable-next-line
import 'react-ace'
import 'brace/mode/java'
import 'brace/mode/text'
import 'brace/mode/xml'
import 'brace/theme/monokai'
interface Props {
node?: q.TreeNode
connectionId?: string
}
interface State {
customTopic?: string
payload?: string
mode: string
}
class Publisher extends React.Component<Props, State> {
constructor(props: any) {
super(props)
this.state = { mode: 'json' }
}
private updatePayload = (value: string, event?: any) => {
this.setState({ payload: value })
}
private updateTopic = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ customTopic: e.target.value })
}
private updateMode = (e: React.ChangeEvent<{}>, value: string) => {
this.setState({ mode: value })
}
private publish = (e: React.MouseEvent) => {
e.stopPropagation()
if (!this.props.connectionId || !this.state.customTopic) {
return
}
rendererEvents.emit(makePublishEvent(this.props.connectionId), {
topic: this.state.customTopic,
payload: this.state.payload,
})
}
public render() {
return (
<div style={{ flexGrow: 1, marginLeft: '8px' }}>
{this.topic()}
{this.editor()}
</div>
)
}
private topic() {
const { node } = this.props
const topicStr = this.state.customTopic || (node ? node.path() : '')
return (
<div>
<Typography>Topic</Typography>
<TextField
placeholder="example/topic"
style={{ width: '100%' }}
margin="normal"
value={topicStr}
multiline={true}
onChange={this.updateTopic}
/>
</div>
)
}
private editorOptions = {
enableBasicAutocompletion: true,
enableLiveAutocompletion: true,
enableSnippets: true,
showLineNumbers: false,
tabSize: 2,
}
private publishButton() {
return (
<Button variant="contained" size="small" color="primary">
<Navigation style={{ marginRight: '8px' }} /> Publish
</Button>
)
}
private editorMode() {
const labelStyle = { margin: '0 8px 0 8px' }
return (
<div style={{ marginTop: '16px' }}>
<Typography style={{ width: '100%', lineHeight: '64px' }}>
<RadioGroup
style={{ display: 'inline-block', float: 'left' }}
value={this.state.mode}
onChange={this.updateMode}
row={true}
>
<FormControlLabel
value="text"
style={labelStyle}
control={<Radio color="primary" />}
label="raw"
labelPlacement="top"
/>
<FormControlLabel
value="xml"
style={labelStyle}
control={<Radio color="primary" />}
label="xml"
labelPlacement="top"
/>
<FormControlLabel
value="json"
style={labelStyle}
control={<Radio color="primary" />}
label="json"
labelPlacement="top"
/>
</RadioGroup>
<div style={{ float: 'right', marginRight: '16px' }}>
{this.publishButton()}
</div>
</Typography>
</div>
)
}
private editor() {
return (
<div style={{ width: '100%', display: 'block' }}>
{this.editorMode()}
<AceEditor
mode={this.state.mode}
theme="monokai"
name="UNIQUE_ID_OF_DIV"
width="100%"
height="200px"
showGutter={true}
value={this.state.payload}
onChange={this.updatePayload}
setOptions={this.editorOptions}
editorProps={{ $blockScrolling: true }}
/>
</div>
)
}
}
export default Publisher

View File

@@ -5,6 +5,7 @@ import * as q from '../../../../backend/src/Model'
import { ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography } from '@material-ui/core'
import { withStyles, Theme, StyleRulesCallback } from '@material-ui/core/styles'
import ExpandMore from '@material-ui/icons/ExpandMore'
import Publisher from './Publisher'
import Copy from '../Copy'
import ValueRenderer from './ValueRenderer'
@@ -15,10 +16,11 @@ interface Props {
node?: q.TreeNode,
classes: any,
theme: Theme,
connectionId?: string,
}
interface State {
node: q.TreeNode
node: q.TreeNode,
}
class Sidebar extends React.Component<Props, State> {
@@ -77,30 +79,39 @@ class Sidebar extends React.Component<Props, State> {
const copyTopic = node ? <Copy value={node.path()} /> : null
const copyValue = node && node.message ? <Copy value={node.message.value} /> : null
const summeryStyle = { minHeight: '0' }
const detailsStyle = { padding: '0px 8px 8px' }
return (
<div>
<ExpansionPanel key="topic" defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
<Typography className={classes.heading}>Topic {copyTopic}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<ExpansionPanelDetails style={detailsStyle}>
<Topic node={this.props.node} didSelectNode={this.updateNode} />
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel key="value" defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
<Typography className={classes.heading}>Value {copyValue}</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<ExpansionPanelDetails style={detailsStyle}>
<ValueRenderer node={this.props.node} />
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />}>
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
<Typography className={classes.heading}>Publish</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails style={detailsStyle}>
<Publisher node={this.props.node} connectionId={this.props.connectionId} />
</ExpansionPanelDetails>
</ExpansionPanel>
<ExpansionPanel defaultExpanded={true}>
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
<Typography className={classes.heading}>Stats</Typography>
</ExpansionPanelSummary>
<ExpansionPanelDetails>
<ExpansionPanelDetails style={detailsStyle}>
{this.props.node ? <NodeStats node={this.props.node} /> : null}
</ExpansionPanelDetails>
</ExpansionPanel>