chore: refactor
This commit is contained in:
@@ -12,7 +12,6 @@ import { sidebarActions } from '../../../actions'
|
||||
|
||||
const TopicPanel = (props: { node?: q.TreeNode<any>; actions: typeof sidebarActions }) => {
|
||||
const { node } = props
|
||||
console.log(node && node.path())
|
||||
|
||||
const copyTopic = node ? <Copy value={node.path()} /> : null
|
||||
|
||||
@@ -35,7 +34,7 @@ const TopicPanel = (props: { node?: q.TreeNode<any>; actions: typeof sidebarActi
|
||||
<Topic node={node} />
|
||||
</Panel>
|
||||
),
|
||||
[node, node && node.childTopicCount()]
|
||||
[node, node?.childTopicCount()]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,23 +11,6 @@ import WarningRounded from '@material-ui/icons/WarningRounded'
|
||||
import { IDecoder, decoders } from '../../../../../backend/src/Model/sparkplugb'
|
||||
import { Tooltip } from '@material-ui/core'
|
||||
|
||||
// const options: q.TopicDataType[] = ['json', 'string', 'hex', 'integer', 'unsigned int', 'floating point']
|
||||
const options: q.TopicDataType[] = [
|
||||
'json',
|
||||
'string',
|
||||
'hex',
|
||||
'uint8',
|
||||
'uint16',
|
||||
'uint32',
|
||||
'uint64',
|
||||
'int8',
|
||||
'int16',
|
||||
'int32',
|
||||
'int64',
|
||||
'float',
|
||||
'double',
|
||||
]
|
||||
|
||||
export const TopicTypeButton = (props: { node?: q.TreeNode<any> }) => {
|
||||
const { node } = props
|
||||
if (!node || !node.message || !node.message.payload) {
|
||||
@@ -39,34 +22,40 @@ export const TopicTypeButton = (props: { node?: q.TreeNode<any> }) => {
|
||||
const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
|
||||
const [open, setOpen] = React.useState(false)
|
||||
|
||||
const selectOption = useCallback((decoder: IDecoder, format: string) => {
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
node.decoder = decoder
|
||||
node.decoderFormat = format
|
||||
setOpen(false)
|
||||
}, [])
|
||||
const selectOption = useCallback(
|
||||
(decoder: IDecoder, format: string) => {
|
||||
if (!node) {
|
||||
return
|
||||
}
|
||||
|
||||
const handleToggle = (event: React.MouseEvent<HTMLElement>) => {
|
||||
event.stopPropagation()
|
||||
if (open === true) {
|
||||
return
|
||||
}
|
||||
setAnchorEl(event.currentTarget)
|
||||
setOpen(prevOpen => !prevOpen)
|
||||
}
|
||||
node.viewModel.decoder = { decoder, format }
|
||||
setOpen(false)
|
||||
},
|
||||
[node]
|
||||
)
|
||||
|
||||
const handleClose = (event: React.MouseEvent<Document, MouseEvent>) => {
|
||||
const handleToggle = useCallback(
|
||||
(event: React.MouseEvent<HTMLElement>) => {
|
||||
event.stopPropagation()
|
||||
if (open === true) {
|
||||
return
|
||||
}
|
||||
setAnchorEl(event.currentTarget)
|
||||
setOpen(prevOpen => !prevOpen)
|
||||
},
|
||||
[open]
|
||||
)
|
||||
|
||||
const handleClose = useCallback((event: React.MouseEvent<Document, MouseEvent>) => {
|
||||
if (anchorEl && anchorEl.contains(event.target as HTMLElement)) {
|
||||
return
|
||||
}
|
||||
setOpen(false)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<Button onClick={handleToggle}>
|
||||
{props.node?.decoderFormat ?? props.node?.type}
|
||||
{props.node?.viewModel.decoder?.format ?? props.node?.type}
|
||||
<Popper open={open} anchorEl={anchorEl} role={undefined} transition>
|
||||
{({ TransitionProps, placement }) => (
|
||||
<Grow
|
||||
|
||||
@@ -5,7 +5,6 @@ import Copy from '../../helper/Copy'
|
||||
import DateFormatter from '../../helper/DateFormatter'
|
||||
import History from '../HistoryDrawer'
|
||||
import TopicPlot from '../../TopicPlot'
|
||||
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
||||
import { isPlottable } from '../CodeDiff/util'
|
||||
import { TopicViewModel } from '../../../model/TopicViewModel'
|
||||
import { bindActionCreators } from 'redux'
|
||||
@@ -13,6 +12,8 @@ import { chartActions } from '../../../actions'
|
||||
import { connect } from 'react-redux'
|
||||
import CustomIconButton from '../../helper/CustomIconButton'
|
||||
import { MessageId } from '../MessageId'
|
||||
import { useSubscription } from '../../hooks/useSubscription'
|
||||
import { useDecoder } from '../../hooks/useDecoder'
|
||||
|
||||
const throttle = require('lodash.throttle')
|
||||
|
||||
@@ -25,119 +26,100 @@ interface Props {
|
||||
}
|
||||
}
|
||||
|
||||
interface State {
|
||||
displayMessage?: q.Message
|
||||
anchorEl?: HTMLElement
|
||||
lastUpdate: number
|
||||
}
|
||||
export const MessageHistory: React.FC<Props> = props => {
|
||||
const [, setLastUpdate] = React.useState(Date.now())
|
||||
const updateNodeThrottled = React.useCallback(
|
||||
throttle(() => {
|
||||
setLastUpdate
|
||||
}, 300),
|
||||
[]
|
||||
)
|
||||
|
||||
class MessageHistory extends React.PureComponent<Props, State> {
|
||||
private updateNode = throttle(() => {
|
||||
this.setState({ lastUpdate: Date.now() })
|
||||
}, 300)
|
||||
useSubscription(props.node?.onMessage, updateNodeThrottled)
|
||||
const decodeMessage = useDecoder(props.node)
|
||||
|
||||
constructor(props: any) {
|
||||
super(props)
|
||||
this.state = { lastUpdate: 0 }
|
||||
}
|
||||
|
||||
private addNodeToCharts = (event: React.MouseEvent) => {
|
||||
function addNodeToCharts(event: React.MouseEvent) {
|
||||
event.preventDefault()
|
||||
event.stopPropagation()
|
||||
|
||||
const { node } = this.props
|
||||
const { node } = props
|
||||
if (!node) {
|
||||
return null
|
||||
}
|
||||
|
||||
this.props.actions.charts.addChart({ topic: node.path() })
|
||||
props.actions.charts.addChart({ topic: node.path() })
|
||||
}
|
||||
|
||||
private displayMessage = (index: number, eventTarget: EventTarget) => {
|
||||
const message = this.props.node && this.props.node.messageHistory.toArray().reverse()[index]
|
||||
function displayMessage(index: number, eventTarget: EventTarget) {
|
||||
const message = props.node && props.node.messageHistory.toArray().reverse()[index]
|
||||
if (message) {
|
||||
this.props.onSelect(message)
|
||||
props.onSelect(message)
|
||||
}
|
||||
}
|
||||
|
||||
public componentWillReceiveProps(nextProps: Props) {
|
||||
this.props.node && this.props.node.onMessage.unsubscribe(this.updateNode)
|
||||
nextProps.node && nextProps.node.onMessage.subscribe(this.updateNode)
|
||||
const { node } = props
|
||||
if (!node) {
|
||||
return null
|
||||
}
|
||||
|
||||
public componentDidMount() {
|
||||
this.props.node && this.props.node.onMessage.subscribe(this.updateNode)
|
||||
}
|
||||
const history = node.messageHistory.toArray()
|
||||
let previousMessage: q.Message | undefined = node.message
|
||||
const historyElements = [...history].reverse().map((message, idx) => {
|
||||
const value = node.message ? decodeMessage(node.message)?.format()[0] ?? null : null
|
||||
|
||||
public componentWillUnMount() {
|
||||
this.props.node && this.props.node.onMessage.unsubscribe(this.updateNode)
|
||||
}
|
||||
|
||||
public render() {
|
||||
const { node } = this.props
|
||||
if (!node) {
|
||||
return null
|
||||
}
|
||||
|
||||
const history = node.messageHistory.toArray()
|
||||
let previousMessage: q.Message | undefined = node.message
|
||||
const historyElements = [...history].reverse().map((message, idx) => {
|
||||
const value = node.message ? node.decodeMessage(node.message)?.format()[0] ?? null : null
|
||||
|
||||
const element = {
|
||||
value: value ?? '',
|
||||
key: `${message.messageNumber}-${message.received}`,
|
||||
title: (
|
||||
const element = {
|
||||
value: value ?? '',
|
||||
key: `${message.messageNumber}-${message.received}`,
|
||||
title: (
|
||||
<span>
|
||||
<div style={{ float: 'left' }}>
|
||||
<DateFormatter date={message.received} />
|
||||
{previousMessage && previousMessage !== message ? (
|
||||
<i>
|
||||
(-
|
||||
<DateFormatter date={message.received} intervalSince={previousMessage.received} />)
|
||||
</i>
|
||||
) : null}
|
||||
</div>
|
||||
<span>
|
||||
<div style={{ float: 'left' }}>
|
||||
<DateFormatter date={message.received} />
|
||||
{previousMessage && previousMessage !== message ? (
|
||||
<i>
|
||||
(-
|
||||
<DateFormatter date={message.received} intervalSince={previousMessage.received} />)
|
||||
</i>
|
||||
) : null}
|
||||
</div>
|
||||
<span>
|
||||
|
||||
<MessageId message={message} />
|
||||
</span>
|
||||
<div style={{ float: 'right' }}>
|
||||
<Copy value={value ?? ''} />
|
||||
</div>
|
||||
|
||||
<MessageId message={message} />
|
||||
</span>
|
||||
),
|
||||
selected: message && message === this.props.selected,
|
||||
}
|
||||
previousMessage = message
|
||||
return element
|
||||
})
|
||||
<div style={{ float: 'right' }}>
|
||||
<Copy value={value ?? ''} />
|
||||
</div>
|
||||
</span>
|
||||
),
|
||||
selected: message && message === props.selected,
|
||||
}
|
||||
previousMessage = message
|
||||
return element
|
||||
})
|
||||
|
||||
const value = node.message ? node.decodeMessage(node.message)?.format()[0] ?? null : null
|
||||
const value = node.message ? decodeMessage(node.message)?.format()[0] ?? null : null
|
||||
|
||||
const isMessagePlottable = isPlottable(value)
|
||||
return (
|
||||
<div>
|
||||
<History
|
||||
items={historyElements}
|
||||
contentTypeIndicator={
|
||||
isMessagePlottable ? (
|
||||
<CustomIconButton
|
||||
style={{ height: '22px', width: '22px' }}
|
||||
onClick={this.addNodeToCharts}
|
||||
tooltip="Add to chart panel"
|
||||
>
|
||||
<ShowChart style={{ marginTop: '-5px' }} />
|
||||
</CustomIconButton>
|
||||
) : undefined
|
||||
}
|
||||
onClick={this.displayMessage}
|
||||
>
|
||||
{isMessagePlottable ? <TopicPlot node={node} history={node.messageHistory} /> : null}
|
||||
</History>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
const isMessagePlottable = isPlottable(value)
|
||||
return (
|
||||
<div>
|
||||
<History
|
||||
items={historyElements}
|
||||
contentTypeIndicator={
|
||||
isMessagePlottable ? (
|
||||
<CustomIconButton
|
||||
style={{ height: '22px', width: '22px' }}
|
||||
onClick={addNodeToCharts}
|
||||
tooltip="Add to chart panel"
|
||||
>
|
||||
<ShowChart style={{ marginTop: '-5px' }} />
|
||||
</CustomIconButton>
|
||||
) : undefined
|
||||
}
|
||||
onClick={displayMessage}
|
||||
>
|
||||
{isMessagePlottable ? <TopicPlot node={node} history={node.messageHistory} /> : null}
|
||||
</History>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mapDispatchToProps = (dispatch: any) => {
|
||||
@@ -146,4 +128,4 @@ const mapDispatchToProps = (dispatch: any) => {
|
||||
}
|
||||
}
|
||||
|
||||
export default connect(null, mapDispatchToProps)(MessageHistory)
|
||||
export default connect(null, mapDispatchToProps)(React.memo(MessageHistory))
|
||||
|
||||
@@ -7,13 +7,13 @@ import Panel from '../Panel'
|
||||
import React, { useCallback } from 'react'
|
||||
import ValueRenderer from './ValueRenderer'
|
||||
import { AppState } from '../../../reducers'
|
||||
import { Base64Message } from '../../../../../backend/src/Model/Base64Message'
|
||||
import { bindActionCreators } from 'redux'
|
||||
import { Theme, Typography, withStyles } from '@material-ui/core'
|
||||
import { connect } from 'react-redux'
|
||||
import { sidebarActions } from '../../../actions'
|
||||
import DeleteSelectedTopicButton from './DeleteSelectedTopicButton'
|
||||
import { MessageId } from '../MessageId'
|
||||
import { useDecoder } from '../../hooks/useDecoder'
|
||||
|
||||
interface Props {
|
||||
node?: q.TreeNode<any>
|
||||
@@ -35,6 +35,7 @@ function RenderedValue(props: { node?: q.TreeNode<any>; compareMessage?: q.Messa
|
||||
|
||||
function ValuePanel(props: Props) {
|
||||
const { node, compareMessage } = props
|
||||
const decodeMessage = useDecoder(node)
|
||||
|
||||
function renderViewOptions() {
|
||||
if (!props.node || !props.node.message) {
|
||||
@@ -54,6 +55,10 @@ function ValuePanel(props: Props) {
|
||||
)
|
||||
}
|
||||
|
||||
const getDecodedValue = useCallback(() => {
|
||||
return node?.message && decodeMessage(node.message)?.toUnicodeString()
|
||||
}, [node, decodeMessage])
|
||||
|
||||
function messageMetaInfo() {
|
||||
if (!props.node || !props.node.message) {
|
||||
return null
|
||||
@@ -87,7 +92,7 @@ function ValuePanel(props: Props) {
|
||||
|
||||
const [value] =
|
||||
node && node.message && node.message.payload ? node.message.payload?.format(node.type) : [null, undefined]
|
||||
const copyValue = value ? <Copy value={value} /> : null
|
||||
const copyValue = value ? <Copy getValue={getDecodedValue} /> : null
|
||||
|
||||
return (
|
||||
<Panel>
|
||||
|
||||
@@ -6,6 +6,7 @@ import { connect } from 'react-redux'
|
||||
import { ValueRendererDisplayMode } from '../../../reducers/Settings'
|
||||
import { Fade } from '@material-ui/core'
|
||||
import { Decoder } from '../../../../../backend/src/Model/Decoder'
|
||||
import { DecoderFunction, useDecoder } from '../../hooks/useDecoder'
|
||||
|
||||
interface Props {
|
||||
message: q.Message
|
||||
@@ -14,30 +15,28 @@ interface Props {
|
||||
renderMode: ValueRendererDisplayMode
|
||||
}
|
||||
|
||||
interface State {
|
||||
width: number
|
||||
}
|
||||
export const ValueRenderer: React.FC<Props> = props => {
|
||||
const decodeMessage = useDecoder(props.treeNode)
|
||||
|
||||
class ValueRenderer extends React.Component<Props, State> {
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = { width: 0 }
|
||||
}
|
||||
|
||||
private renderDiff(current: string = '', previous: string = '', title?: string, language?: 'json') {
|
||||
function renderDiff(current: string = '', previous: string = '', title?: string, language?: 'json') {
|
||||
return (
|
||||
<CodeDiff
|
||||
treeNode={this.props.treeNode}
|
||||
treeNode={props.treeNode}
|
||||
previous={previous}
|
||||
current={current}
|
||||
title={title}
|
||||
language={language}
|
||||
nameOfCompareMessage={this.props.compareWith ? 'selected' : 'previous'}
|
||||
nameOfCompareMessage={props.compareWith ? 'selected' : 'previous'}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
private renderDiffMode(message: q.Message, treeNode: q.TreeNode<any>, compare?: q.Message) {
|
||||
function renderDiffMode(
|
||||
decodeMessage: DecoderFunction,
|
||||
message: q.Message,
|
||||
treeNode: q.TreeNode<any>,
|
||||
compare?: q.Message
|
||||
) {
|
||||
if (!message.payload) {
|
||||
return
|
||||
}
|
||||
@@ -46,55 +45,58 @@ class ValueRenderer extends React.Component<Props, State> {
|
||||
const previousMessage = previousMessages[previousMessages.length - 2]
|
||||
const compareMessage = compare || previousMessage || message
|
||||
|
||||
const [currentStr, currentType] = treeNode.decodeMessage(message)?.format(treeNode.type) ?? []
|
||||
const [compareStr, compareType] = treeNode.decodeMessage(compareMessage)?.format(treeNode.type) ?? []
|
||||
const [currentStr, currentType] = decodeMessage(message)?.format(treeNode.type) ?? []
|
||||
const [compareStr, compareType] = decodeMessage(compareMessage)?.format(treeNode.type) ?? []
|
||||
|
||||
const language = currentType === compareType && compareType === 'json' ? 'json' : undefined
|
||||
|
||||
return <div>{this.renderDiff(currentStr, compareStr, undefined, language)}</div>
|
||||
return <div>{renderDiff(currentStr, compareStr, undefined, language)}</div>
|
||||
}
|
||||
|
||||
private renderRawMode(message: q.Message, treeNode: q.TreeNode<any>, compare?: q.Message) {
|
||||
function renderRawMode(
|
||||
decodeMessage: DecoderFunction,
|
||||
message: q.Message,
|
||||
treeNode: q.TreeNode<any>,
|
||||
compare?: q.Message
|
||||
) {
|
||||
if (!message.payload) {
|
||||
return
|
||||
}
|
||||
|
||||
const [currentStr, currentType] = treeNode.decodeMessage(message)?.format(treeNode.type) ?? []
|
||||
const [currentStr, currentType] = decodeMessage(message)?.format(treeNode.type) ?? []
|
||||
const [compareStr, compareType] =
|
||||
compare && compare.payload ? treeNode.decodeMessage(compare)?.format(treeNode.type) ?? [] : []
|
||||
compare && compare.payload ? decodeMessage(compare)?.format(treeNode.type) ?? [] : []
|
||||
|
||||
return (
|
||||
<div>
|
||||
{this.renderDiff(currentStr, currentStr, undefined, currentType)}
|
||||
{renderDiff(currentStr, currentStr, undefined, currentType)}
|
||||
<Fade in={Boolean(compareStr)} timeout={400}>
|
||||
<div>{Boolean(compareStr) ? this.renderDiff(compareStr, compareStr, 'selected', compareType) : null}</div>
|
||||
<div>{Boolean(compareStr) ? renderDiff(compareStr, compareStr, 'selected', compareType) : null}</div>
|
||||
</Fade>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public render() {
|
||||
return (
|
||||
<div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
|
||||
{this.props.message?.payload?.decoder === Decoder.SPARKPLUG && 'Decoded SparkplugB'}
|
||||
{this.renderValue()}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
public renderValue() {
|
||||
const { message, treeNode, compareWith, renderMode } = this.props
|
||||
function renderValue(decodeMessage: DecoderFunction) {
|
||||
const { message, treeNode, compareWith, renderMode } = props
|
||||
if (!message.payload) {
|
||||
return null
|
||||
}
|
||||
|
||||
switch (renderMode) {
|
||||
case 'diff':
|
||||
return this.renderDiffMode(message, treeNode, compareWith)
|
||||
return renderDiffMode(decodeMessage, message, treeNode, compareWith)
|
||||
default:
|
||||
return this.renderRawMode(message, treeNode, compareWith)
|
||||
return renderRawMode(decodeMessage, message, treeNode, compareWith)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div style={{ padding: '0px 0px 8px 0px', width: '100%' }}>
|
||||
{props.message?.payload?.decoder === Decoder.SPARKPLUG && 'Decoded SparkplugB'}
|
||||
{renderValue(decodeMessage)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
const mapStateToProps = (state: AppState) => {
|
||||
|
||||
Reference in New Issue
Block a user