This commit is contained in:
Thomas Nordquist
2019-01-11 18:52:12 +01:00
parent 1586d0121c
commit b52b2d7696
11 changed files with 143 additions and 64 deletions

View File

@@ -1,19 +1,19 @@
import { ActionTypes, NodeOrder } from '../reducers' import { ActionTypes, NodeOrder, CustomAction } from '../reducers'
export const setAutoExpandLimit = (autoExpandLimit: number = 0) => { export const setAutoExpandLimit = (autoExpandLimit: number = 0): CustomAction => {
return { return {
autoExpandLimit, autoExpandLimit,
type: ActionTypes.setAutoExpandLimit, type: ActionTypes.setAutoExpandLimit,
} }
} }
export const toggleSettingsVisibility = () => { export const toggleSettingsVisibility = (): CustomAction => {
return { return {
type: ActionTypes.toggleSettingsVisibility, type: ActionTypes.toggleSettingsVisibility,
} }
} }
export const setNodeOrder = (nodeOrder: NodeOrder = NodeOrder.none) => { export const setNodeOrder = (nodeOrder: NodeOrder = NodeOrder.none): CustomAction => {
return { return {
nodeOrder, nodeOrder,
type: ActionTypes.setNodeOrder, type: ActionTypes.setNodeOrder,

View File

@@ -0,0 +1,15 @@
import { ActionTypes, CustomAction } from '../reducers'
export const setPublishTopic = (topic: string): CustomAction => {
return {
publishTopic: topic,
type: ActionTypes.setPublishTopic,
}
}
export const setPublishPayload = (payload: string): CustomAction => {
return {
publishPayload: payload,
type: ActionTypes.setPublishPayload,
}
}

View File

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

View File

@@ -1,4 +1,5 @@
import * as settingsActions from './Settings' import * as settingsActions from './Settings'
import * as treeActions from './Tree' import * as treeActions from './Tree'
import * as sidebarActions from './Sidebar'
export { settingsActions, treeActions } export { settingsActions, treeActions, sidebarActions }

View File

@@ -66,11 +66,9 @@ class Settings extends React.Component<Props, {}> {
className={classes.paper} className={classes.paper}
tabIndex={0} tabIndex={0}
role="button" role="button"
onClick={(e: React.MouseEvent) => e.stopPropagation()}
onKeyDown={(e: React.KeyboardEvent) => e.stopPropagation()}
> >
<Typography className={ classes.title } variant="h6" color="inherit"> <Typography className={classes.title} variant="h6" color="inherit">
<IconButton onClick={actions.toggleSettingsVisibility}> <IconButton onClick={actions.toggleSettingsVisibility}>
<ChevronRight /> <ChevronRight />
</IconButton> </IconButton>
@@ -93,7 +91,7 @@ class Settings extends React.Component<Props, {}> {
<InputLabel htmlFor="auto-expand">Auto Expand</InputLabel> <InputLabel htmlFor="auto-expand">Auto Expand</InputLabel>
<Select <Select
value={autoExpandLimit} value={autoExpandLimit}
onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => actions.setAutoExpandLimit(e.target.value) } onChange={(e: React.ChangeEvent<HTMLSelectElement>) => actions.setAutoExpandLimit(e.target.value)}
input={<Input name="auto-expand" id="auto-expand-label-placeholder" />} input={<Input name="auto-expand" id="auto-expand-label-placeholder" />}
displayEmpty={true} displayEmpty={true}
name="auto-expand" name="auto-expand"
@@ -110,16 +108,14 @@ class Settings extends React.Component<Props, {}> {
} }
private renderNodeOrder() { private renderNodeOrder() {
const { classes, actions, nodeOrder } = this.props const { classes, nodeOrder } = this.props
return ( return (
<div style={{ padding: '8px' }}> <div style={{ padding: '8px' }}>
<InputLabel htmlFor="auto-expand">Topic order</InputLabel> <InputLabel htmlFor="auto-expand">Topic order</InputLabel>
<Select <Select
value={nodeOrder} value={nodeOrder}
onChange={ (e: React.ChangeEvent<HTMLSelectElement>) => { onChange={this.onChangeSorting}
actions.setNodeOrder(e.target.value)
}}
input={<Input name="node-order" id="node-order-label-placeholder" />} input={<Input name="node-order" id="node-order-label-placeholder" />}
displayEmpty={true} displayEmpty={true}
name="node-order" name="node-order"
@@ -132,6 +128,10 @@ class Settings extends React.Component<Props, {}> {
</Select> </Select>
</div>) </div>)
} }
private onChangeSorting = (e: React.ChangeEvent<HTMLSelectElement>) => {
this.props.actions.setNodeOrder(e.target.value)
}
} }
const mapStateToProps = (state: AppState) => { const mapStateToProps = (state: AppState) => {

View File

@@ -0,0 +1,39 @@
import * as React from 'react'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { sidebarActions } from '../../../actions'
import { Typography } from '@material-ui/core'
import Message from './Model/Message'
interface Props {
message: Message
actions: any
}
class HystoryEntry extends React.Component<Props, {}> {
public render() {
const { message } = this.props
return (
<Typography onClick={this.setPublishPreset}>
<div style={{ width: '100%', cursor: 'pointer', marginTop: '8px' }}>
<div><b>{message.topic}</b></div>
<div><i>{message.payload}</i></div>
</div>
</Typography>
)
}
private setPublishPreset = (e: React.MouseEvent) => {
e.stopPropagation()
this.props.actions.setPublishTopic(this.props.message.topic)
this.props.actions.setPublishPayload(this.props.message.payload)
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: bindActionCreators(sidebarActions, dispatch),
}
}
export default connect(null, mapDispatchToProps)(HystoryEntry)

View File

@@ -0,0 +1,7 @@
interface Message {
topic: string
payload?: string
sent: Date
}
export default Message

View File

@@ -1,11 +1,17 @@
import * as React from 'react' import * as React from 'react'
import * as q from '../../../../backend/src/Model' import { connect } from 'react-redux'
import { makePublishEvent, rendererEvents } from '../../../../events' import { bindActionCreators } from 'redux'
import * as q from '../../../../../backend/src/Model'
import { AppState } from '../../../reducers'
import { rendererEvents, makePublishEvent } from '../../../../../events'
import { sidebarActions } from '../../../actions'
import Navigation from '@material-ui/icons/Navigation' import Navigation from '@material-ui/icons/Navigation'
import { import {
Button, Fab, InputAdornment, FormControlLabel, Radio, Button, Fab, InputAdornment, FormControlLabel, Radio,
RadioGroup, TextField, Typography, RadioGroup, TextField, Typography,
} from '@material-ui/core' } from '@material-ui/core'
import Message from './Model/Message'
import HistoryEntry from './HistoryEntry'
import * as brace from 'brace' import * as brace from 'brace'
import { default as AceEditor } from 'react-ace' import { default as AceEditor } from 'react-ace'
@@ -19,17 +25,12 @@ import 'brace/theme/monokai'
interface Props { interface Props {
node?: q.TreeNode node?: q.TreeNode
connectionId?: string connectionId?: string
} topic?: string
interface Message {
topic: string
payload?: string payload?: string
sent: Date actions: any
} }
interface State { interface State {
customTopic?: string
payload?: string
mode: string mode: string
history: Message[] history: Message[]
} }
@@ -41,11 +42,12 @@ class Publisher extends React.Component<Props, State> {
} }
private updatePayload = (value: string, event?: any) => { private updatePayload = (value: string, event?: any) => {
this.setState({ payload: value }) this.props.actions.setPublishPayload(value)
} }
private updateTopic = (e: React.ChangeEvent<HTMLInputElement>) => { private updateTopic = (e: React.ChangeEvent<HTMLInputElement>) => {
this.setState({ customTopic: e.target.value }) console.log(e.target.value)
this.props.actions.setPublishTopic(e.target.value)
} }
private updateMode = (e: React.ChangeEvent<{}>, value: string) => { private updateMode = (e: React.ChangeEvent<{}>, value: string) => {
@@ -55,7 +57,7 @@ class Publisher extends React.Component<Props, State> {
private publish = (e: React.MouseEvent) => { private publish = (e: React.MouseEvent) => {
e.stopPropagation() e.stopPropagation()
const topic = this.currentTopic() || '' const topic = this.currentTopic() || ''
const payload = this.state.payload const payload = this.props.payload
if (this.props.connectionId && topic) { if (this.props.connectionId && topic) {
rendererEvents.emit(makePublishEvent(this.props.connectionId), { topic, payload }) rendererEvents.emit(makePublishEvent(this.props.connectionId), { topic, payload })
@@ -82,8 +84,10 @@ class Publisher extends React.Component<Props, State> {
} }
private currentTopic(): string | undefined { private currentTopic(): string | undefined {
const { node } = this.props const { node, topic } = this.props
return (this.state.customTopic !== undefined) ? this.state.customTopic : (node ? node.path() : undefined) const selectedNodePath = (node ? node.path() : undefined)
return (topic !== undefined) ? topic : selectedNodePath
} }
private topic() { private topic() {
@@ -107,7 +111,7 @@ class Publisher extends React.Component<Props, State> {
private onTopicBlur = (e: React.FocusEvent<HTMLInputElement>) => { private onTopicBlur = (e: React.FocusEvent<HTMLInputElement>) => {
if (!e.target.value) { if (!e.target.value) {
this.setState({ customTopic: undefined }) this.props.actions.setPublishTopic(undefined)
} }
} }
@@ -173,21 +177,9 @@ class Publisher extends React.Component<Props, State> {
) )
} }
private loadHistoryEntry(entry: Message) {
this.setState({
customTopic: entry.topic,
payload: entry.payload,
})
}
private history() { private history() {
const entries = this.state.history.map(message => ( const entries = this.state.history.map(message => (
<Typography onClick={() => this.loadHistoryEntry(message)}> <HistoryEntry message={message} />
<div style={{ width: '100%', cursor: 'pointer', marginTop: '8px' }}>
<div><b>{message.topic}</b></div>
<div><i>{message.payload}</i></div>
</div>
</Typography>
)) ))
return ( return (
@@ -209,7 +201,7 @@ class Publisher extends React.Component<Props, State> {
width="100%" width="100%"
height="200px" height="200px"
showGutter={true} showGutter={true}
value={this.state.payload} value={this.props.payload}
onChange={this.updatePayload} onChange={this.updatePayload}
setOptions={this.editorOptions} setOptions={this.editorOptions}
editorProps={{ $blockScrolling: true }} editorProps={{ $blockScrolling: true }}
@@ -219,4 +211,17 @@ class Publisher extends React.Component<Props, State> {
} }
} }
export default Publisher const mapDispatchToProps = (dispatch: any) => {
return {
actions: bindActionCreators(sidebarActions, dispatch),
}
}
const mapStateToProps = (state: AppState) => {
return {
topic: state.sidebar.publishTopic,
payload: state.sidebar.publishPayload,
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Publisher)

View File

@@ -5,7 +5,7 @@ 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'
import ExpandMore from '@material-ui/icons/ExpandMore' import ExpandMore from '@material-ui/icons/ExpandMore'
import Publisher from './Publisher' import Publish from './Publish/Publish'
import Copy from '../Copy' import Copy from '../Copy'
import ValueRenderer from './ValueRenderer' import ValueRenderer from './ValueRenderer'
@@ -104,7 +104,7 @@ class Sidebar extends React.Component<Props, State> {
<Typography className={classes.heading}>Publish</Typography> <Typography className={classes.heading}>Publish</Typography>
</ExpansionPanelSummary> </ExpansionPanelSummary>
<ExpansionPanelDetails style={detailsStyle}> <ExpansionPanelDetails style={detailsStyle}>
<Publisher node={this.props.node} connectionId={this.props.connectionId} /> <Publish node={this.props.node} connectionId={this.props.connectionId} />
</ExpansionPanelDetails> </ExpansionPanelDetails>
</ExpansionPanel> </ExpansionPanel>
<ExpansionPanel defaultExpanded={true}> <ExpansionPanel defaultExpanded={true}>

View File

@@ -3,19 +3,17 @@ import * as ReactDOM from 'react-dom'
import { Provider } from 'react-redux' import { Provider } from 'react-redux'
import { createStore } from 'redux' import { createStore } from 'redux'
import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles' import { MuiThemeProvider, createMuiTheme } from '@material-ui/core/styles'
import reducers, { NodeOrder, AppState } from './reducers'
import reducers, { NodeOrder } from './reducers'
import App from './App' import App from './App'
declare var document: any const initialAppState: AppState = {
const initialAppState = {
settings: { settings: {
autoExpandLimit: 0, autoExpandLimit: 0,
nodeOrder: NodeOrder.none, nodeOrder: NodeOrder.none,
visible: false, visible: false,
}, },
selectedNode: undefined, sidebar: {},
selectedTopic: undefined,
} }
const store = createStore(reducers, initialAppState) const store = createStore(reducers, initialAppState)

View File

@@ -6,18 +6,28 @@ export enum ActionTypes {
toggleSettingsVisibility = 'TOGGLE_SETTINGS_VISIBILITY', toggleSettingsVisibility = 'TOGGLE_SETTINGS_VISIBILITY',
setNodeOrder = 'SET_NODE_ORDER', setNodeOrder = 'SET_NODE_ORDER',
selectTopic = 'SELECT_TOPIC', selectTopic = 'SELECT_TOPIC',
setPublishTopic = 'SET_PUBLISH_TOPIC',
setPublishPayload = 'SET_PUBLISH_PAYLOAD',
} }
interface CustomAction extends Action { export interface CustomAction extends Action {
type: ActionTypes, type: ActionTypes,
autoExpandLimit?: number autoExpandLimit?: number
nodeOrder?: NodeOrder nodeOrder?: NodeOrder
selectedTopic?: q.TreeNode selectedTopic?: q.TreeNode
publishTopic?: string
publishPayload?: string
}
export interface SidebarState {
publishTopic?: string
publishPayload?: string
} }
export interface AppState { export interface AppState {
settings: SettingsState, settings: SettingsState,
selectedTopic?: q.TreeNode selectedTopic?: q.TreeNode
sidebar: SidebarState
} }
export interface SettingsState { export interface SettingsState {
@@ -47,18 +57,27 @@ const reducer: Reducer<AppState | undefined, CustomAction> = (state, action) =>
return { return {
...state, ...state,
settings: { settings: {
visible: state.settings.visible, ...state.settings,
autoExpandLimit: action.autoExpandLimit, autoExpandLimit: action.autoExpandLimit,
nodeOrder: state.settings.nodeOrder,
}, },
} }
case ActionTypes.setPublishTopic:
console.log(state)
return {
...state,
sidebar: { ...state.sidebar, publishTopic: action.publishTopic },
}
case ActionTypes.setPublishPayload:
return {
...state,
sidebar: { ...state.sidebar, publishPayload: action.publishPayload },
}
case ActionTypes.toggleSettingsVisibility: case ActionTypes.toggleSettingsVisibility:
return { return {
...state, ...state,
settings: { settings: {
...state.settings,
visible: !state.settings.visible, visible: !state.settings.visible,
autoExpandLimit: state.settings.autoExpandLimit,
nodeOrder: state.settings.nodeOrder,
}, },
} }
case ActionTypes.selectTopic: case ActionTypes.selectTopic:
@@ -67,7 +86,6 @@ const reducer: Reducer<AppState | undefined, CustomAction> = (state, action) =>
} }
return { return {
...state, ...state,
settings: state.settings,
selectedTopic: action.selectedTopic, selectedTopic: action.selectedTopic,
} }
case ActionTypes.setNodeOrder: case ActionTypes.setNodeOrder:
@@ -76,11 +94,7 @@ const reducer: Reducer<AppState | undefined, CustomAction> = (state, action) =>
} }
return { return {
...state, ...state,
settings: { settings: { ...state.settings, autoExpandLimit: state.settings.autoExpandLimit },
visible: state.settings.visible,
autoExpandLimit: state.settings.autoExpandLimit,
nodeOrder: action.nodeOrder,
},
} }
default: default:
return state return state