Refactor
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
15
app/src/actions/Sidebar.ts
Normal file
15
app/src/actions/Sidebar.ts
Normal 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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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,
|
||||||
|
|||||||
@@ -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 }
|
||||||
|
|||||||
@@ -66,8 +66,6 @@ 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">
|
||||||
@@ -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) => {
|
||||||
|
|||||||
39
app/src/components/Sidebar/Publish/HistoryEntry.tsx
Normal file
39
app/src/components/Sidebar/Publish/HistoryEntry.tsx
Normal 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)
|
||||||
7
app/src/components/Sidebar/Publish/Model/Message.ts
Normal file
7
app/src/components/Sidebar/Publish/Model/Message.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
interface Message {
|
||||||
|
topic: string
|
||||||
|
payload?: string
|
||||||
|
sent: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Message
|
||||||
@@ -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)
|
||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user