Refactor
This commit is contained in:
@@ -3,7 +3,8 @@ import FormatAlignLeft from '@material-ui/icons/FormatAlignLeft'
|
|||||||
import Message from './Model/Message'
|
import Message from './Model/Message'
|
||||||
import Navigation from '@material-ui/icons/Navigation'
|
import Navigation from '@material-ui/icons/Navigation'
|
||||||
import PublishHistory from './PublishHistory'
|
import PublishHistory from './PublishHistory'
|
||||||
import React, { useCallback, useState, useMemo } from 'react'
|
import React, { useCallback, useMemo, useState } from 'react'
|
||||||
|
import RetainSwitch from './RetainSwitch'
|
||||||
import TopicInput from './TopicInput'
|
import TopicInput from './TopicInput'
|
||||||
import { AppState } from '../../../reducers'
|
import { AppState } from '../../../reducers'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
@@ -12,7 +13,6 @@ import { connect } from 'react-redux'
|
|||||||
import { EditorModeSelect } from './EditorModeSelect'
|
import { EditorModeSelect } from './EditorModeSelect'
|
||||||
import { globalActions, publishActions } from '../../../actions'
|
import { globalActions, publishActions } from '../../../actions'
|
||||||
import { KeyCodes } from '../../../utils/KeyCodes'
|
import { KeyCodes } from '../../../utils/KeyCodes'
|
||||||
import RetainSwitch from './RetainSwitch'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
connectionId?: string
|
connectionId?: string
|
||||||
@@ -41,14 +41,8 @@ function useHistory(): [Array<Message>, (topic: string, payload?: string) => voi
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Publish(props: Props) {
|
function Publish(props: Props) {
|
||||||
console.log(props.connectionId)
|
|
||||||
const updatePayload = props.actions.setPayload
|
|
||||||
const [history, amendToHistory] = useHistory()
|
const [history, amendToHistory] = useHistory()
|
||||||
|
|
||||||
const updateMode = useCallback((e: React.ChangeEvent<{}>, value: string) => {
|
|
||||||
props.actions.setEditorMode(value)
|
|
||||||
}, [])
|
|
||||||
|
|
||||||
const publish = useCallback(() => {
|
const publish = useCallback(() => {
|
||||||
if (!props.connectionId) {
|
if (!props.connectionId) {
|
||||||
return
|
return
|
||||||
@@ -63,65 +57,6 @@ function Publish(props: Props) {
|
|||||||
}
|
}
|
||||||
}, [props, props.connectionId, props.topic, props.payload, amendToHistory])
|
}, [props, props.connectionId, props.topic, props.payload, amendToHistory])
|
||||||
|
|
||||||
const handleClickPublish = useCallback(
|
|
||||||
(e: React.MouseEvent) => {
|
|
||||||
e.stopPropagation()
|
|
||||||
publish()
|
|
||||||
},
|
|
||||||
[publish]
|
|
||||||
)
|
|
||||||
|
|
||||||
const PublishButton = () => {
|
|
||||||
return (
|
|
||||||
<Button variant="contained" size="small" color="primary" onClick={handleClickPublish} id="publish-button">
|
|
||||||
<Navigation style={{ marginRight: '8px' }} /> Publish
|
|
||||||
</Button>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const formatJson = () => {
|
|
||||||
if (props.payload) {
|
|
||||||
try {
|
|
||||||
const str = JSON.stringify(JSON.parse(props.payload), undefined, ' ')
|
|
||||||
updatePayload(str)
|
|
||||||
} catch (error) {
|
|
||||||
props.globalActions.showError(`Format error: ${error.message}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const renderFormatJson = () => {
|
|
||||||
if (props.editorMode !== 'json') {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Tooltip title="Format JSON">
|
|
||||||
<Fab
|
|
||||||
style={{ width: '36px', height: '36px', marginLeft: '8px' }}
|
|
||||||
onClick={formatJson}
|
|
||||||
id="sidebar-publish-format-json"
|
|
||||||
>
|
|
||||||
<FormatAlignLeft style={{ fontSize: '20px' }} />
|
|
||||||
</Fab>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function EditorMode() {
|
|
||||||
return (
|
|
||||||
<div style={{ marginTop: '16px' }}>
|
|
||||||
<div style={{ width: '100%', lineHeight: '64px' }}>
|
|
||||||
<EditorModeSelect value={props.editorMode} onChange={updateMode} />
|
|
||||||
{renderFormatJson()}
|
|
||||||
<div style={{ float: 'right', marginRight: '16px' }}>
|
|
||||||
<PublishButton />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleSubmit = useCallback(
|
const handleSubmit = useCallback(
|
||||||
(e: React.KeyboardEvent) => {
|
(e: React.KeyboardEvent) => {
|
||||||
if (e.keyCode === KeyCodes.enter && (e.metaKey || e.ctrlKey)) {
|
if (e.keyCode === KeyCodes.enter && (e.metaKey || e.ctrlKey)) {
|
||||||
@@ -138,14 +73,97 @@ function Publish(props: Props) {
|
|||||||
<div style={{ flexGrow: 1, marginLeft: '8px' }} onKeyDown={handleSubmit}>
|
<div style={{ flexGrow: 1, marginLeft: '8px' }} onKeyDown={handleSubmit}>
|
||||||
<TopicInput />
|
<TopicInput />
|
||||||
<div style={{ width: '100%', display: 'block' }}>
|
<div style={{ width: '100%', display: 'block' }}>
|
||||||
<EditorMode />
|
<EditorMode
|
||||||
<Editor value={props.payload} editorMode={props.editorMode} onChange={updatePayload} />
|
actions={props.actions}
|
||||||
|
globalActions={props.globalActions}
|
||||||
|
payload={props.payload}
|
||||||
|
editorMode={props.editorMode}
|
||||||
|
publish={publish}
|
||||||
|
/>
|
||||||
|
<Editor value={props.payload} editorMode={props.editorMode} onChange={props.actions.setPayload} />
|
||||||
<RetainSwitch />
|
<RetainSwitch />
|
||||||
</div>
|
</div>
|
||||||
<PublishHistory history={history} />
|
<PublishHistory history={history} />
|
||||||
</div>
|
</div>
|
||||||
),
|
),
|
||||||
[props.payload, props.editorMode, history, handleSubmit, updatePayload]
|
[props.payload, props.editorMode, history, handleSubmit, publish]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function EditorMode(props: {
|
||||||
|
payload?: string
|
||||||
|
editorMode: string
|
||||||
|
actions: typeof publishActions
|
||||||
|
globalActions: typeof globalActions
|
||||||
|
publish: () => void
|
||||||
|
}) {
|
||||||
|
const updatePayload = props.actions.setPayload
|
||||||
|
|
||||||
|
const updateMode = useCallback((e: React.ChangeEvent<{}>, value: string) => {
|
||||||
|
props.actions.setEditorMode(value)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
const formatJson = useCallback(() => {
|
||||||
|
if (props.payload) {
|
||||||
|
try {
|
||||||
|
const str = JSON.stringify(JSON.parse(props.payload), undefined, ' ')
|
||||||
|
updatePayload(str)
|
||||||
|
} catch (error) {
|
||||||
|
props.globalActions.showError(`Format error: ${error.message}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, [props.payload])
|
||||||
|
|
||||||
|
const renderFormatJson = useCallback(() => {
|
||||||
|
if (props.editorMode !== 'json') {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tooltip title="Format JSON">
|
||||||
|
<Fab
|
||||||
|
style={{ width: '36px', height: '36px', marginLeft: '8px' }}
|
||||||
|
onClick={formatJson}
|
||||||
|
id="sidebar-publish-format-json"
|
||||||
|
>
|
||||||
|
<FormatAlignLeft style={{ fontSize: '20px' }} />
|
||||||
|
</Fab>
|
||||||
|
</Tooltip>
|
||||||
|
)
|
||||||
|
}, [formatJson, props.editorMode, props.publish])
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => (
|
||||||
|
<div style={{ marginTop: '16px' }}>
|
||||||
|
<div style={{ width: '100%', lineHeight: '64px' }}>
|
||||||
|
<EditorModeSelect value={props.editorMode} onChange={updateMode} />
|
||||||
|
{renderFormatJson()}
|
||||||
|
<div style={{ float: 'right', marginRight: '16px' }}>
|
||||||
|
<PublishButton publish={props.publish} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[props.editorMode, renderFormatJson]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const PublishButton = (props: { publish: () => void }) => {
|
||||||
|
const handleClickPublish = useCallback(
|
||||||
|
(e: React.MouseEvent) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
props.publish()
|
||||||
|
},
|
||||||
|
[props.publish]
|
||||||
|
)
|
||||||
|
|
||||||
|
return useMemo(
|
||||||
|
() => (
|
||||||
|
<Button variant="contained" size="small" color="primary" onClick={handleClickPublish} id="publish-button">
|
||||||
|
<Navigation style={{ marginRight: '8px' }} /> Publish
|
||||||
|
</Button>
|
||||||
|
),
|
||||||
|
[handleClickPublish]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import ClearAdornment from '../../helper/ClearAdornment'
|
import ClearAdornment from '../../helper/ClearAdornment'
|
||||||
import React, { useCallback } from 'react'
|
import React, { useCallback, useMemo } from 'react'
|
||||||
import { FormControl, Input, InputLabel } from '@material-ui/core'
|
import { FormControl, Input, InputLabel } from '@material-ui/core'
|
||||||
import { publishActions } from '../../../actions'
|
import { publishActions } from '../../../actions'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
@@ -7,7 +7,6 @@ import { AppState } from '../../../reducers'
|
|||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
|
||||||
function TopicInput(props: { actions: typeof publishActions; topic?: string }) {
|
function TopicInput(props: { actions: typeof publishActions; topic?: string }) {
|
||||||
console.log(props.topic)
|
|
||||||
const updateTopic = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
const updateTopic = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
props.actions.setTopic(e.target.value)
|
props.actions.setTopic(e.target.value)
|
||||||
}, [])
|
}, [])
|
||||||
@@ -23,22 +22,26 @@ function TopicInput(props: { actions: typeof publishActions; topic?: string }) {
|
|||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const topicStr = props.topic || ''
|
const topicStr = props.topic || ''
|
||||||
return (
|
|
||||||
<div>
|
return useMemo(
|
||||||
<FormControl style={{ width: '100%' }}>
|
() => (
|
||||||
<InputLabel htmlFor="publish-topic">Topic</InputLabel>
|
<div>
|
||||||
<Input
|
<FormControl style={{ width: '100%' }}>
|
||||||
id="publish-topic"
|
<InputLabel htmlFor="publish-topic">Topic</InputLabel>
|
||||||
value={topicStr}
|
<Input
|
||||||
startAdornment={<span />}
|
id="publish-topic"
|
||||||
endAdornment={<ClearAdornment action={clearTopic} value={topicStr} />}
|
value={topicStr}
|
||||||
onBlur={onTopicBlur}
|
startAdornment={<span />}
|
||||||
onChange={updateTopic}
|
endAdornment={<ClearAdornment action={clearTopic} value={topicStr} />}
|
||||||
multiline={true}
|
onBlur={onTopicBlur}
|
||||||
placeholder="example/topic"
|
onChange={updateTopic}
|
||||||
/>
|
multiline={false}
|
||||||
</FormControl>
|
placeholder="example/topic"
|
||||||
</div>
|
/>
|
||||||
|
</FormControl>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
[topicStr]
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -54,9 +54,7 @@ function Sidebar(props: Props) {
|
|||||||
<ValuePanel lastUpdate={node ? node.lastUpdate : 0} />
|
<ValuePanel lastUpdate={node ? node.lastUpdate : 0} />
|
||||||
<Panel>
|
<Panel>
|
||||||
<span>Publish</span>
|
<span>Publish</span>
|
||||||
<React.Suspense fallback={<div>Loading...</div>}>
|
<Publish connectionId={props.connectionId} />
|
||||||
<Publish connectionId={props.connectionId} />
|
|
||||||
</React.Suspense>
|
|
||||||
</Panel>
|
</Panel>
|
||||||
<Panel detailsHidden={!node}>
|
<Panel detailsHidden={!node}>
|
||||||
<span>Stats</span>
|
<span>Stats</span>
|
||||||
|
|||||||
79
app/src/components/Sidebar/ValueRenderer/ActionButtons.tsx
Normal file
79
app/src/components/Sidebar/ValueRenderer/ActionButtons.tsx
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
import React, { useCallback } from 'react'
|
||||||
|
import Code from '@material-ui/icons/Code'
|
||||||
|
import Reorder from '@material-ui/icons/Reorder'
|
||||||
|
import ToggleButton from '@material-ui/lab/ToggleButton'
|
||||||
|
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'
|
||||||
|
import { settingsActions } from '../../../actions'
|
||||||
|
import { Tooltip, withStyles, Theme } from '@material-ui/core'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { AppState } from '../../../reducers'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
|
||||||
|
|
||||||
|
function ActionButtons(props: {
|
||||||
|
actions: { settings: typeof settingsActions }
|
||||||
|
valueRendererDisplayMode: ValueRendererDisplayMode
|
||||||
|
classes: any
|
||||||
|
}) {
|
||||||
|
const handleValue = useCallback(
|
||||||
|
(mouseEvent: React.MouseEvent, value: any) => {
|
||||||
|
if (value === null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
props.actions.settings.setValueDisplayMode(value)
|
||||||
|
},
|
||||||
|
[props.actions.settings.setValueDisplayMode]
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<ToggleButtonGroup
|
||||||
|
id="valueRendererDisplayMode"
|
||||||
|
value={props.valueRendererDisplayMode}
|
||||||
|
exclusive={true}
|
||||||
|
onChange={handleValue}
|
||||||
|
>
|
||||||
|
<ToggleButton className={props.classes.toggleButton} value="diff" id="valueRendererDisplayMode-diff">
|
||||||
|
<Tooltip title="Show difference between the current and the last message">
|
||||||
|
<span>
|
||||||
|
<Code className={props.classes.toggleButtonIcon} />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</ToggleButton>
|
||||||
|
<ToggleButton className={props.classes.toggleButton} value="raw" id="valueRendererDisplayMode-raw">
|
||||||
|
<Tooltip title="Raw value">
|
||||||
|
<span>
|
||||||
|
<Reorder className={props.classes.toggleButtonIcon} />
|
||||||
|
</span>
|
||||||
|
</Tooltip>
|
||||||
|
</ToggleButton>
|
||||||
|
</ToggleButtonGroup>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => ({
|
||||||
|
toggleButton: {
|
||||||
|
height: '36px',
|
||||||
|
},
|
||||||
|
toggleButtonIcon: {
|
||||||
|
verticalAlign: 'middle',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
|
return {
|
||||||
|
actions: {
|
||||||
|
settings: bindActionCreators(settingsActions, dispatch),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
valueRendererDisplayMode: state.settings.get('valueRendererDisplayMode'),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
mapStateToProps,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(withStyles(styles)(ActionButtons))
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import Clear from '@material-ui/icons/Clear'
|
||||||
|
import React, { useMemo } from 'react'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { Button, Tooltip } from '@material-ui/core'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { sidebarActions } from '../../../actions'
|
||||||
|
|
||||||
|
const DeleteSelectedTopicButton = (props: {
|
||||||
|
actions: {
|
||||||
|
sidebar: typeof sidebarActions
|
||||||
|
}
|
||||||
|
}) =>
|
||||||
|
useMemo(
|
||||||
|
() => (
|
||||||
|
<Tooltip title="Delete retained topic" placement="top">
|
||||||
|
<Button
|
||||||
|
size="small"
|
||||||
|
color="secondary"
|
||||||
|
variant="contained"
|
||||||
|
style={{ marginTop: '11px', padding: '0px 4px', minHeight: '24px' }}
|
||||||
|
onClick={props.actions.sidebar.clearRetainedTopic}
|
||||||
|
>
|
||||||
|
retained <Clear style={{ fontSize: '16px', marginLeft: '2px' }} />
|
||||||
|
</Button>
|
||||||
|
</Tooltip>
|
||||||
|
),
|
||||||
|
[props.actions.sidebar.clearRetainedTopic]
|
||||||
|
)
|
||||||
|
|
||||||
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
|
return {
|
||||||
|
actions: { sidebar: bindActionCreators(sidebarActions, dispatch) },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default connect(
|
||||||
|
undefined,
|
||||||
|
mapDispatchToProps
|
||||||
|
)(DeleteSelectedTopicButton)
|
||||||
@@ -27,16 +27,17 @@ interface Props {
|
|||||||
interface State {
|
interface State {
|
||||||
displayMessage?: q.Message
|
displayMessage?: q.Message
|
||||||
anchorEl?: HTMLElement
|
anchorEl?: HTMLElement
|
||||||
|
lastUpdate: number
|
||||||
}
|
}
|
||||||
|
|
||||||
class MessageHistory extends React.Component<Props, State> {
|
class MessageHistory extends React.PureComponent<Props, State> {
|
||||||
private updateNode = throttle(() => {
|
private updateNode = throttle(() => {
|
||||||
this.setState(this.state)
|
this.setState({ lastUpdate: Date.now() })
|
||||||
}, 300)
|
}, 300)
|
||||||
|
|
||||||
constructor(props: any) {
|
constructor(props: any) {
|
||||||
super(props)
|
super(props)
|
||||||
this.state = {}
|
this.state = { lastUpdate: 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
private addNodeToCharts = (event: React.MouseEvent) => {
|
private addNodeToCharts = (event: React.MouseEvent) => {
|
||||||
|
|||||||
@@ -1,196 +1,117 @@
|
|||||||
import * as q from '../../../../../backend/src/Model'
|
import * as q from '../../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import ActionButtons from './ActionButtons'
|
||||||
import Clear from '@material-ui/icons/Clear'
|
|
||||||
import Code from '@material-ui/icons/Code'
|
|
||||||
import Copy from '../../helper/Copy'
|
import Copy from '../../helper/Copy'
|
||||||
import DateFormatter from '../../helper/DateFormatter'
|
import DateFormatter from '../../helper/DateFormatter'
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
|
||||||
import MessageHistory from './MessageHistory'
|
import MessageHistory from './MessageHistory'
|
||||||
import Reorder from '@material-ui/icons/Reorder'
|
import Panel from '../Panel'
|
||||||
import ToggleButton from '@material-ui/lab/ToggleButton'
|
import React, { useCallback } from 'react'
|
||||||
import ToggleButtonGroup from '@material-ui/lab/ToggleButtonGroup'
|
|
||||||
import ValueRenderer from './ValueRenderer'
|
import ValueRenderer from './ValueRenderer'
|
||||||
import { AppState } from '../../../reducers'
|
import { AppState } from '../../../reducers'
|
||||||
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { Theme, Typography, withStyles } from '@material-ui/core'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { settingsActions, sidebarActions } from '../../../actions'
|
import { sidebarActions } from '../../../actions'
|
||||||
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
|
import DeleteSelectedTopicButton from './DeleteSelectedTopicButton'
|
||||||
|
|
||||||
import {
|
|
||||||
Button,
|
|
||||||
ExpansionPanel,
|
|
||||||
ExpansionPanelDetails,
|
|
||||||
ExpansionPanelSummary,
|
|
||||||
Tooltip,
|
|
||||||
Typography,
|
|
||||||
StyleRulesCallback,
|
|
||||||
withStyles,
|
|
||||||
Theme,
|
|
||||||
} from '@material-ui/core'
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
node?: q.TreeNode<any>
|
node?: q.TreeNode<any>
|
||||||
valueRendererDisplayMode: ValueRendererDisplayMode
|
|
||||||
sidebarActions: typeof sidebarActions
|
sidebarActions: typeof sidebarActions
|
||||||
settingsActions: typeof settingsActions
|
|
||||||
classes: any
|
classes: any
|
||||||
lastUpdate: number
|
lastUpdate: number
|
||||||
compareMessage?: q.Message
|
compareMessage?: q.Message
|
||||||
}
|
}
|
||||||
|
|
||||||
interface State {}
|
function RenderedValue(props: { node?: q.TreeNode<any>; compareMessage?: q.Message }) {
|
||||||
|
const { node, compareMessage } = props
|
||||||
|
|
||||||
class ValuePanel extends React.PureComponent<Props, State> {
|
if (!node || !node.message) {
|
||||||
constructor(props: Props) {
|
return null
|
||||||
super(props)
|
|
||||||
this.state = {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderValue() {
|
return <ValueRenderer treeNode={node} message={node.message} compareWith={compareMessage} />
|
||||||
const node = this.props.node
|
}
|
||||||
if (!node || !node.message) {
|
|
||||||
|
function ValuePanel(props: Props) {
|
||||||
|
const { node, compareMessage } = props
|
||||||
|
|
||||||
|
function renderViewOptions() {
|
||||||
|
if (!props.node || !props.node.message || !props.node.mqttMessage) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return <ValueRenderer treeNode={node} message={node.message} compareWith={this.props.compareMessage} />
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderViewOptions() {
|
|
||||||
if (!this.props.node || !this.props.node.message || !this.props.node.mqttMessage) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
const retainedButton = (
|
|
||||||
<Tooltip title="Delete retained topic" placement="top">
|
|
||||||
<Button
|
|
||||||
size="small"
|
|
||||||
color="secondary"
|
|
||||||
variant="contained"
|
|
||||||
style={{ marginTop: '11px', padding: '0px 4px', minHeight: '24px' }}
|
|
||||||
onClick={this.props.sidebarActions.clearRetainedTopic}
|
|
||||||
>
|
|
||||||
retained <Clear style={{ fontSize: '16px', marginLeft: '2px' }} />
|
|
||||||
</Button>
|
|
||||||
</Tooltip>
|
|
||||||
)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%', display: 'flex', paddingLeft: '8px' }}>
|
<div style={{ width: '100%', display: 'flex', paddingLeft: '8px' }}>
|
||||||
<span style={{ marginTop: '2px', flexGrow: 1 }}>{this.renderActionButtons()}</span>
|
<span style={{ marginTop: '2px', flexGrow: 1 }}>
|
||||||
<div style={{ flex: 6, textAlign: 'right' }}>{this.props.node.mqttMessage.retain ? retainedButton : null}</div>
|
<ActionButtons />
|
||||||
{this.messageMetaInfo()}
|
</span>
|
||||||
|
<div style={{ flex: 6, textAlign: 'right' }}>
|
||||||
|
{props.node.mqttMessage.retain ? <DeleteSelectedTopicButton /> : null}
|
||||||
|
</div>
|
||||||
|
{messageMetaInfo()}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private messageMetaInfo() {
|
function messageMetaInfo() {
|
||||||
if (!this.props.node || !this.props.node.message || !this.props.node.mqttMessage) {
|
if (!props.node || !props.node.message || !props.node.mqttMessage) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span style={{ width: '100%', paddingLeft: '8px', flex: 6 }}>
|
<span style={{ width: '100%', paddingLeft: '8px', flex: 6 }}>
|
||||||
<Typography style={{ textAlign: 'right' }}>QoS: {this.props.node.mqttMessage.qos}</Typography>
|
<Typography style={{ textAlign: 'right' }}>QoS: {props.node.mqttMessage.qos}</Typography>
|
||||||
<Typography style={{ textAlign: 'right' }}>
|
<Typography style={{ textAlign: 'right' }}>
|
||||||
<i>
|
<i>
|
||||||
<DateFormatter date={this.props.node.message.received} />
|
<DateFormatter date={props.node.message.received} />
|
||||||
</i>
|
</i>
|
||||||
</Typography>
|
</Typography>
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private renderActionButtons() {
|
const handleMessageHistorySelect = useCallback(
|
||||||
const handleValue = (mouseEvent: React.MouseEvent, value: any) => {
|
(message: q.Message) => {
|
||||||
if (value === null) {
|
if (message !== compareMessage) {
|
||||||
return
|
props.sidebarActions.setCompareMessage(message)
|
||||||
|
} else {
|
||||||
|
props.sidebarActions.setCompareMessage(undefined)
|
||||||
}
|
}
|
||||||
this.props.settingsActions.setValueDisplayMode(value)
|
},
|
||||||
}
|
[compareMessage]
|
||||||
|
)
|
||||||
|
|
||||||
return (
|
const copyValue =
|
||||||
<ToggleButtonGroup
|
node && node.message && node.message.value ? (
|
||||||
id="valueRendererDisplayMode"
|
<Copy value={Base64Message.toUnicodeString(node.message.value)} />
|
||||||
value={this.props.valueRendererDisplayMode}
|
) : null
|
||||||
exclusive={true}
|
|
||||||
onChange={handleValue}
|
|
||||||
>
|
|
||||||
<ToggleButton className={this.props.classes.toggleButton} value="diff" id="valueRendererDisplayMode-diff">
|
|
||||||
<Tooltip title="Show difference between the current and the last message">
|
|
||||||
<span>
|
|
||||||
<Code className={this.props.classes.toggleButtonIcon} />
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</ToggleButton>
|
|
||||||
<ToggleButton className={this.props.classes.toggleButton} value="raw" id="valueRendererDisplayMode-raw">
|
|
||||||
<Tooltip title="Raw value">
|
|
||||||
<span>
|
|
||||||
<Reorder className={this.props.classes.toggleButtonIcon} />
|
|
||||||
</span>
|
|
||||||
</Tooltip>
|
|
||||||
</ToggleButton>
|
|
||||||
</ToggleButtonGroup>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private panelStyle() {
|
return (
|
||||||
return {
|
<Panel>
|
||||||
detailsStyle: { padding: '0px 16px 8px 8px', display: 'block' },
|
<span>Value {copyValue}</span>
|
||||||
summaryStyle: { minHeight: '0' },
|
<span style={{ width: '100%' }}>
|
||||||
}
|
{renderViewOptions()}
|
||||||
}
|
<div style={{ marginBottom: '-8px' }}>
|
||||||
|
<React.Suspense fallback={<div>Loading...</div>}>
|
||||||
private handleMessageHistorySelect = (message: q.Message) => {
|
<RenderedValue node={node} compareMessage={compareMessage} />
|
||||||
if (message !== this.props.compareMessage) {
|
</React.Suspense>
|
||||||
this.props.sidebarActions.setCompareMessage(message)
|
</div>
|
||||||
} else {
|
<div>
|
||||||
this.props.sidebarActions.setCompareMessage(undefined)
|
<MessageHistory onSelect={handleMessageHistorySelect} selected={props.compareMessage} node={props.node} />
|
||||||
}
|
</div>
|
||||||
}
|
</span>
|
||||||
|
</Panel>
|
||||||
public render() {
|
)
|
||||||
const { node, classes } = this.props
|
|
||||||
const { detailsStyle, summaryStyle } = this.panelStyle()
|
|
||||||
|
|
||||||
const copyValue =
|
|
||||||
node && node.message && node.message.value ? (
|
|
||||||
<Copy value={Base64Message.toUnicodeString(node.message.value)} />
|
|
||||||
) : null
|
|
||||||
|
|
||||||
return (
|
|
||||||
<ExpansionPanel key="value" defaultExpanded={true}>
|
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summaryStyle}>
|
|
||||||
<Typography className={classes.heading}>Value {copyValue}</Typography>
|
|
||||||
</ExpansionPanelSummary>
|
|
||||||
<ExpansionPanelDetails style={detailsStyle}>
|
|
||||||
{this.renderViewOptions()}
|
|
||||||
<div style={{ marginBottom: '-8px' }}>
|
|
||||||
<React.Suspense fallback={<div>Loading...</div>}>{this.renderValue()}</React.Suspense>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<MessageHistory
|
|
||||||
onSelect={this.handleMessageHistorySelect}
|
|
||||||
selected={this.props.compareMessage}
|
|
||||||
node={this.props.node}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</ExpansionPanelDetails>
|
|
||||||
</ExpansionPanel>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = (dispatch: any) => {
|
const mapDispatchToProps = (dispatch: any) => {
|
||||||
return {
|
return {
|
||||||
sidebarActions: bindActionCreators(sidebarActions, dispatch),
|
sidebarActions: bindActionCreators(sidebarActions, dispatch),
|
||||||
settingsActions: bindActionCreators(settingsActions, dispatch),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapStateToProps = (state: AppState) => {
|
const mapStateToProps = (state: AppState) => {
|
||||||
return {
|
return {
|
||||||
valueRendererDisplayMode: state.settings.get('valueRendererDisplayMode'),
|
|
||||||
node: state.tree.get('selectedTopic'),
|
node: state.tree.get('selectedTopic'),
|
||||||
compareMessage: state.sidebar.get('compareMessage'),
|
compareMessage: state.sidebar.get('compareMessage'),
|
||||||
}
|
}
|
||||||
@@ -201,12 +122,6 @@ const styles = (theme: Theme) => ({
|
|||||||
fontSize: theme.typography.pxToRem(15),
|
fontSize: theme.typography.pxToRem(15),
|
||||||
fontWeight: theme.typography.fontWeightRegular,
|
fontWeight: theme.typography.fontWeightRegular,
|
||||||
},
|
},
|
||||||
toggleButton: {
|
|
||||||
height: '36px',
|
|
||||||
},
|
|
||||||
toggleButtonIcon: {
|
|
||||||
verticalAlign: 'middle',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
export default connect(
|
export default connect(
|
||||||
|
|||||||
@@ -56,12 +56,7 @@ class ValueRenderer extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
return (
|
return <div style={{ padding: '0px 0px 8px 8px', width: '100%' }}>{this.renderValue()}</div>
|
||||||
<div style={{ padding: '0px 0px 8px 8px' }}>
|
|
||||||
<ReactResizeDetector handleWidth={true} onResize={this.updateWidth} />
|
|
||||||
{this.renderValue()}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderValue() {
|
public renderValue() {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { Browser, Element } from 'webdriverio'
|
import { Browser } from 'webdriverio'
|
||||||
import { clickOn, expandTopic, sleep, writeText } from '../util'
|
import { clickOn } from '../util'
|
||||||
|
|
||||||
export async function copyValueToClipboard(browser: Browser) {
|
export async function copyValueToClipboard(browser: Browser) {
|
||||||
const copyButton = await browser.$('//p[contains(text(), "Value")]//button')
|
const copyButton = await browser.$('//span[contains(text(), "Value")]//button')
|
||||||
await clickOn(copyButton, browser, 1)
|
await clickOn(copyButton, browser, 1)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user