Add switch for diffs
This commit is contained in:
@@ -18,7 +18,6 @@ import { Theme, withStyles } from '@material-ui/core/styles'
|
|||||||
const Settings = React.lazy(() => import('./components/Settings'))
|
const Settings = React.lazy(() => import('./components/Settings'))
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
name: string
|
|
||||||
connectionId: string
|
connectionId: string
|
||||||
classes: any
|
classes: any
|
||||||
settingsVisible: boolean
|
settingsVisible: boolean
|
||||||
|
|||||||
@@ -51,6 +51,22 @@ export const setAutoExpandLimit = (autoExpandLimit: number = 0) => (dispatch: Di
|
|||||||
dispatch(storeSettings())
|
dispatch(storeSettings())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const selectTopicWithMouseOver = (selectTopicWithMouseOver: boolean) => (dispatch: Dispatch<any>, getState: () => AppState) => {
|
||||||
|
dispatch({
|
||||||
|
selectTopicWithMouseOver,
|
||||||
|
type: ActionTypes.SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER,
|
||||||
|
})
|
||||||
|
dispatch(storeSettings())
|
||||||
|
}
|
||||||
|
|
||||||
|
export const setValueDisplayMode = (valueRendererDisplayMode: 'diff' | 'raw') => (dispatch: Dispatch<any>, getState: () => AppState) => {
|
||||||
|
dispatch({
|
||||||
|
valueRendererDisplayMode,
|
||||||
|
type: ActionTypes.SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE,
|
||||||
|
})
|
||||||
|
dispatch(storeSettings())
|
||||||
|
}
|
||||||
|
|
||||||
export const toggleSettingsVisibility = () => (dispatch: Dispatch<any>, _getState: () => AppState) => {
|
export const toggleSettingsVisibility = () => (dispatch: Dispatch<any>, _getState: () => AppState) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: ActionTypes.SETTINGS_TOGGLE_VISIBILITY,
|
type: ActionTypes.SETTINGS_TOGGLE_VISIBILITY,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import Clear from '@material-ui/icons/Clear'
|
import Clear from '@material-ui/icons/Clear'
|
||||||
|
import Code from '@material-ui/icons/Code'
|
||||||
import Copy from '../Copy'
|
import Copy from '../Copy'
|
||||||
import CustomIconButton from '../CustomIconButton'
|
import CustomIconButton from '../CustomIconButton'
|
||||||
import DateFormatter from '../helper/DateFormatter'
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
@@ -9,23 +10,23 @@ import DeleteForever from '@material-ui/icons/DeleteForever'
|
|||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
import ExpandMore from '@material-ui/icons/ExpandMore'
|
||||||
import MessageHistory from './MessageHistory'
|
import MessageHistory from './MessageHistory'
|
||||||
import NodeStats from './NodeStats'
|
import NodeStats from './NodeStats'
|
||||||
|
import Reorder from '@material-ui/icons/Reorder'
|
||||||
|
import ToggleButton from '@material-ui/lab/ToggleButton'
|
||||||
|
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'
|
||||||
import Topic from './Topic'
|
import Topic from './Topic'
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { default as ReactResizeDetector } from 'react-resize-detector'
|
import { settingsActions, sidebarActons } from '../../actions'
|
||||||
import { sidebarActons } from '../../actions'
|
|
||||||
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
||||||
import { TopicViewModel } from '../../TopicViewModel'
|
import { TopicViewModel } from '../../TopicViewModel'
|
||||||
|
import { ValueRendererDisplayMode } from '../../reducers/Settings'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
ExpansionPanel,
|
ExpansionPanel,
|
||||||
ExpansionPanelDetails,
|
ExpansionPanelDetails,
|
||||||
ExpansionPanelSummary,
|
ExpansionPanelSummary,
|
||||||
Fade,
|
|
||||||
Paper,
|
|
||||||
Popper,
|
|
||||||
Typography,
|
Typography,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Badge,
|
Badge,
|
||||||
@@ -37,10 +38,12 @@ const Publish = React.lazy(() => import('./Publish/Publish'))
|
|||||||
const ValueRenderer = React.lazy(() => import('./ValueRenderer'))
|
const ValueRenderer = React.lazy(() => import('./ValueRenderer'))
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
node?: q.TreeNode<TopicViewModel>,
|
node?: q.TreeNode<TopicViewModel>
|
||||||
actions: typeof sidebarActons,
|
actions: typeof sidebarActons
|
||||||
classes: any,
|
settingsActions: typeof settingsActions
|
||||||
connectionId?: string,
|
valueRendererDisplayMode: ValueRendererDisplayMode
|
||||||
|
classes: any
|
||||||
|
connectionId?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -139,6 +142,27 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
this.props.actions.clearTopic(topic, recursive, maxCount)
|
this.props.actions.clearTopic(topic, recursive, maxCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderActionButtons() {
|
||||||
|
const handleValue = (_e: React.MouseEvent, value: any) => {
|
||||||
|
this.props.settingsActions.setValueDisplayMode(value)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToggleButtonGroup value={this.props.valueRendererDisplayMode} exclusive={true} onChange={handleValue}>
|
||||||
|
<ToggleButton value="diff">
|
||||||
|
<Tooltip title="Show difference between the current and the last message">
|
||||||
|
<Code />
|
||||||
|
</Tooltip>
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton value="raw">
|
||||||
|
<Tooltip title="Raw value">
|
||||||
|
<Reorder />
|
||||||
|
</Tooltip>
|
||||||
|
</ToggleButton>
|
||||||
|
</ToggleButtonGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private renderNode() {
|
private renderNode() {
|
||||||
const { classes, node } = this.props
|
const { classes, node } = this.props
|
||||||
|
|
||||||
@@ -165,7 +189,7 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
{this.messageMetaInfo()}
|
{this.messageMetaInfo()}
|
||||||
<div ref={this.valueRef}>
|
<div ref={this.valueRef}>
|
||||||
<React.Suspense fallback={<div>Loading...</div>}>
|
<React.Suspense fallback={<div>Loading...</div>}>
|
||||||
<ValueRenderer node={this.props.node} compareWith={this.state.compareMessage} />
|
{this.renderValue()}
|
||||||
</React.Suspense>
|
</React.Suspense>
|
||||||
</div>
|
</div>
|
||||||
<div><MessageHistory onSelect={this.handleMessageHistorySelect} selected={this.state.compareMessage} node={this.props.node} /></div>
|
<div><MessageHistory onSelect={this.handleMessageHistorySelect} selected={this.state.compareMessage} node={this.props.node} /></div>
|
||||||
@@ -191,6 +215,20 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private renderValue() {
|
||||||
|
const node = this.props.node
|
||||||
|
if (!node || !node.message) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ValueRenderer
|
||||||
|
message={node.message}
|
||||||
|
messageHistory={node.messageHistory}
|
||||||
|
compareWith={this.state.compareMessage} />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private messageMetaInfo() {
|
private messageMetaInfo() {
|
||||||
if (!this.props.node || !this.props.node.message || !this.props.node.mqttMessage) {
|
if (!this.props.node || !this.props.node.message || !this.props.node.mqttMessage) {
|
||||||
return null
|
return null
|
||||||
@@ -211,8 +249,9 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
)
|
)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%', display: 'flex' }}>
|
<div style={{ width: '100%', display: 'flex', paddingLeft: '8px' }}>
|
||||||
<div style={{ flex: 6 }}><Typography>QoS: {this.props.node.mqttMessage.qos}</Typography></div>
|
<div style={{ flex: 6 }}><Typography>QoS: {this.props.node.mqttMessage.qos}</Typography></div>
|
||||||
|
<span style={{ marginTop: '-8px' }}>{this.renderActionButtons()}</span>
|
||||||
<div style={{ flex: 8, textAlign: 'center' }}>
|
<div style={{ flex: 8, textAlign: 'center' }}>
|
||||||
{this.props.node.mqttMessage.retain ? retainedButton : null}
|
{this.props.node.mqttMessage.retain ? retainedButton : null}
|
||||||
</div>
|
</div>
|
||||||
@@ -245,12 +284,14 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
const mapStateToProps = (state: AppState) => {
|
const mapStateToProps = (state: AppState) => {
|
||||||
return {
|
return {
|
||||||
node: state.tree.selectedTopic,
|
node: state.tree.selectedTopic,
|
||||||
|
valueRendererDisplayMode: state.settings.valueRendererDisplayMode,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
actions: bindActionCreators(sidebarActons, dispatch),
|
actions: bindActionCreators(sidebarActons, dispatch),
|
||||||
|
settingsActions: bindActionCreators(settingsActions, dispatch),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,16 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import * as React from 'react'
|
||||||
import CodeDiff from '../CodeDiff'
|
import CodeDiff from '../CodeDiff'
|
||||||
|
import { AppState } from '../../reducers'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
import { default as ReactResizeDetector } from 'react-resize-detector'
|
import { default as ReactResizeDetector } from 'react-resize-detector'
|
||||||
|
import { ValueRendererDisplayMode } from '../../reducers/Settings'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
node?: q.TreeNode<any>,
|
message: q.Message
|
||||||
|
messageHistory: q.RingBuffer<q.Message>
|
||||||
compareWith?: q.Message
|
compareWith?: q.Message
|
||||||
|
renderMode: ValueRendererDisplayMode
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {
|
interface State {
|
||||||
@@ -19,10 +24,6 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
if (!this.props.node) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: '8px 0px 8px 8px' }}>
|
<div style={{ padding: '8px 0px 8px 8px' }}>
|
||||||
<ReactResizeDetector handleWidth={true} onResize={this.updateWidth} />
|
<ReactResizeDetector handleWidth={true} onResize={this.updateWidth} />
|
||||||
@@ -32,15 +33,14 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public renderValue() {
|
public renderValue() {
|
||||||
const { node } = this.props
|
const { message, messageHistory, compareWith, renderMode } = this.props
|
||||||
if (!node || !node.message) {
|
|
||||||
return <span key="empty" />
|
|
||||||
}
|
|
||||||
|
|
||||||
const message = node.message
|
const previousMessages = messageHistory.toArray()
|
||||||
const previousMessages = node.messageHistory.toArray()
|
|
||||||
const previousMessage = previousMessages[previousMessages.length - 2]
|
const previousMessage = previousMessages[previousMessages.length - 2]
|
||||||
const compareMessage = this.props.compareWith || previousMessage || message
|
let compareMessage = compareWith || previousMessage || message
|
||||||
|
if (renderMode === 'raw') {
|
||||||
|
compareMessage = message
|
||||||
|
}
|
||||||
|
|
||||||
let json
|
let json
|
||||||
try {
|
try {
|
||||||
@@ -98,4 +98,10 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ValueRenderer
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
renderMode: state.settings.valueRendererDisplayMode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(mapStateToProps)(ValueRenderer)
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ setTimeout(() => {
|
|||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<MuiThemeProvider theme={theme}>
|
<MuiThemeProvider theme={theme}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App name="" />
|
<App />
|
||||||
</Provider>
|
</Provider>
|
||||||
</MuiThemeProvider>,
|
</MuiThemeProvider>,
|
||||||
document.getElementById('app'),
|
document.getElementById('app'),
|
||||||
|
|||||||
@@ -8,14 +8,19 @@ export enum TopicOrder {
|
|||||||
topics = '#topics',
|
topics = '#topics',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type ValueRendererDisplayMode = 'diff' | 'raw'
|
||||||
|
|
||||||
export interface SettingsState {
|
export interface SettingsState {
|
||||||
autoExpandLimit: number
|
autoExpandLimit: number
|
||||||
visible: boolean
|
visible: boolean
|
||||||
topicOrder: TopicOrder
|
topicOrder: TopicOrder
|
||||||
topicFilter?: string
|
topicFilter?: string
|
||||||
highlightTopicUpdates: boolean
|
highlightTopicUpdates: boolean
|
||||||
|
valueRendererDisplayMode: ValueRendererDisplayMode
|
||||||
|
selectTopicWithMouseOver: boolean
|
||||||
}
|
}
|
||||||
export type Action = SetAutoExpandLimit | ToggleVisibility | SetTopicOrder | FilterTopics | TogglehighlightTopicUpdates
|
|
||||||
|
export type Action = SetAutoExpandLimit | ToggleVisibility | SetTopicOrder | FilterTopics | TogglehighlightTopicUpdates | SetValueRendererDisplayMode
|
||||||
|
|
||||||
export enum ActionTypes {
|
export enum ActionTypes {
|
||||||
SETTINGS_SET_AUTO_EXPAND_LIMIT = 'SETTINGS_SET_AUTO_EXPAND_LIMIT',
|
SETTINGS_SET_AUTO_EXPAND_LIMIT = 'SETTINGS_SET_AUTO_EXPAND_LIMIT',
|
||||||
@@ -24,6 +29,9 @@ export enum ActionTypes {
|
|||||||
SETTINGS_FILTER_TOPICS = 'SETTINGS_FILTER_TOPICS',
|
SETTINGS_FILTER_TOPICS = 'SETTINGS_FILTER_TOPICS',
|
||||||
SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY = 'SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY',
|
SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY = 'SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY',
|
||||||
SETTINGS_DID_LOAD_SETTINGS = 'SETTINGS_DID_LOAD_SETTINGS',
|
SETTINGS_DID_LOAD_SETTINGS = 'SETTINGS_DID_LOAD_SETTINGS',
|
||||||
|
SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE = 'SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE',
|
||||||
|
SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER = 'SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER',
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialState: SettingsState = {
|
const initialState: SettingsState = {
|
||||||
@@ -31,6 +39,8 @@ const initialState: SettingsState = {
|
|||||||
topicOrder: TopicOrder.none,
|
topicOrder: TopicOrder.none,
|
||||||
visible: false,
|
visible: false,
|
||||||
highlightTopicUpdates: true,
|
highlightTopicUpdates: true,
|
||||||
|
valueRendererDisplayMode: 'diff',
|
||||||
|
selectTopicWithMouseOver: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
export const settingsReducer = createReducer(initialState, {
|
export const settingsReducer = createReducer(initialState, {
|
||||||
@@ -40,6 +50,8 @@ export const settingsReducer = createReducer(initialState, {
|
|||||||
SETTINGS_FILTER_TOPICS: filterTopics,
|
SETTINGS_FILTER_TOPICS: filterTopics,
|
||||||
SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY: togglehighlightTopicUpdates,
|
SETTINGS_TOGGLE_HIGHLIGHT_ACTIVITY: togglehighlightTopicUpdates,
|
||||||
SETTINGS_DID_LOAD_SETTINGS: didLoadSettings,
|
SETTINGS_DID_LOAD_SETTINGS: didLoadSettings,
|
||||||
|
SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE: setValueRendererDisplayMode,
|
||||||
|
SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER: setSelectTopicWithMouseOver,
|
||||||
})
|
})
|
||||||
|
|
||||||
export interface DidLoadSettings {
|
export interface DidLoadSettings {
|
||||||
@@ -54,6 +66,30 @@ function didLoadSettings(state: SettingsState, action: DidLoadSettings) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface SetSelectTopicWithMouseOver {
|
||||||
|
type: ActionTypes.SETTINGS_SET_SELECT_TOPIC_WITH_MOUSE_OVER
|
||||||
|
selectTopicWithMouseOver: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setSelectTopicWithMouseOver(state: SettingsState, action: SetSelectTopicWithMouseOver) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
selectTopicWithMouseOver: action.selectTopicWithMouseOver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface SetValueRendererDisplayMode {
|
||||||
|
type: ActionTypes.SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE
|
||||||
|
valueRendererDisplayMode: ValueRendererDisplayMode
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setValueRendererDisplayMode(state: SettingsState, action: SetValueRendererDisplayMode) {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
valueRendererDisplayMode: action.valueRendererDisplayMode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export interface SetAutoExpandLimit {
|
export interface SetAutoExpandLimit {
|
||||||
type: ActionTypes.SETTINGS_SET_AUTO_EXPAND_LIMIT
|
type: ActionTypes.SETTINGS_SET_AUTO_EXPAND_LIMIT
|
||||||
autoExpandLimit: number
|
autoExpandLimit: number
|
||||||
|
|||||||
Reference in New Issue
Block a user