Skip to content

Commit

Permalink
Merge pull request #795 from thomasnordquist/tnordquist/decode-data-i…
Browse files Browse the repository at this point in the history
…n-frontend

decode data in frontend
  • Loading branch information
thomasnordquist authored May 25, 2024
2 parents a2a7558 + 3bc23e6 commit 8b43e20
Show file tree
Hide file tree
Showing 49 changed files with 1,473 additions and 652 deletions.
4 changes: 2 additions & 2 deletions app/src/actions/Publish.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Action, ActionTypes } from '../reducers/Publish'
import { AppState } from '../reducers'
import { Base64Message } from '../../../backend/src/Model/Base64Message'
import { Dispatch } from 'redux'
import { makePublishEvent, rendererEvents } from '../../../events'
import { MqttMessage, makePublishEvent, rendererEvents } from '../../../events'

export const setTopic = (topic?: string): Action => {
return {
Expand Down Expand Up @@ -41,7 +41,7 @@ export const publish = (connectionId: string) => (dispatch: Dispatch<Action>, ge
}

const publishEvent = makePublishEvent(connectionId)
const mqttMessage = {
const mqttMessage: Partial<MqttMessage> = {
topic,
payload: state.publish.payload ? Base64Message.fromString(state.publish.payload) : null,
retain: state.publish.retain,
Expand Down
19 changes: 10 additions & 9 deletions app/src/actions/Settings.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as q from '../../../backend/src/Model'
import { ActionTypes, SettingsStateModel, TopicOrder } from '../reducers/Settings'
import { ActionTypes, SettingsStateModel, TopicOrder, ValueRendererDisplayMode } from '../reducers/Settings'
import { AppState } from '../reducers'
import { autoExpandLimitSet } from '../components/SettingsDrawer/Settings'
import { Base64Message } from '../../../backend/src/Model/Base64Message'
Expand Down Expand Up @@ -68,13 +68,14 @@ export const selectTopicWithMouseOver = (doSelect: boolean) => (dispatch: Dispat
dispatch(storeSettings())
}

export const setValueDisplayMode = (valueRendererDisplayMode: 'diff' | 'raw') => (dispatch: Dispatch<any>) => {
dispatch({
valueRendererDisplayMode,
type: ActionTypes.SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE,
})
dispatch(storeSettings())
}
export const setValueDisplayMode =
(valueRendererDisplayMode: ValueRendererDisplayMode) => (dispatch: Dispatch<any>) => {
dispatch({
valueRendererDisplayMode,
type: ActionTypes.SETTINGS_SET_VALUE_RENDERER_DISPLAY_MODE,
})
dispatch(storeSettings())
}

export const toggleHighlightTopicUpdates = () => (dispatch: Dispatch<any>) => {
dispatch({
Expand Down Expand Up @@ -117,7 +118,7 @@ export const filterTopics = (filterStr: string) => (dispatch: Dispatch<any>, get
const messageMatches =
node.message &&
node.message.payload &&
Base64Message.toUnicodeString(node.message.payload).toLowerCase().indexOf(filterStr) !== -1
node.message.payload.toUnicodeString().toLowerCase().indexOf(filterStr) !== -1

return Boolean(messageMatches)
}
Expand Down
9 changes: 2 additions & 7 deletions app/src/actions/Tree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,8 @@ const debouncedSelectTopic = debounce(
setTopicDispatch = setTopic(topic.path())
}

if (previouslySelectedTopic && previouslySelectedTopic.viewModel) {
previouslySelectedTopic.viewModel.setSelected(false)
}

if (topic.viewModel) {
topic.viewModel.setSelected(true)
}
previouslySelectedTopic?.viewModel?.setSelected(false)
topic.viewModel?.setSelected(true)

const selectTreeTopicDispatch = {
selectedTopic: topic,
Expand Down
1 change: 1 addition & 0 deletions app/src/components/ChartPanel/TopicChart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ function TopicChart(props: Props) {
</div>
</div>
<TopicPlot
node={props.treeNode ? props.treeNode : undefined}
color={props.parameters.color}
interpolation={props.parameters.interpolation}
timeInterval={props.parameters.timeRange ? props.parameters.timeRange.until : undefined}
Expand Down
2 changes: 1 addition & 1 deletion app/src/components/ConnectionSetup/ProfileList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { connect } from 'react-redux'
import { connectionManagerActions } from '../../../actions'
import { ConnectionOptions } from '../../../model/ConnectionOptions'
import { KeyCodes } from '../../../utils/KeyCodes'
import { List, ListSubheader } from '@material-ui/core'
import { List } from '@material-ui/core'
import { Theme, withStyles } from '@material-ui/core/styles'
import { useGlobalKeyEventHandler } from '../../../effects/useGlobalKeyEventHandler'

Expand Down
2 changes: 1 addition & 1 deletion app/src/components/SettingsDrawer/BrokerStatistics.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ function renderStat(tree: q.Tree<TopicViewModel>, stat: Stats) {
return null
}

const str = node.message.payload ? Base64Message.toUnicodeString(node.message.payload) : ''
const str = node.message.payload ? node.message.payload.toUnicodeString() : ''
let value = node.message && node.message.payload ? parseFloat(str) : NaN
value = !isNaN(value) ? abbreviate(value) : str

Expand Down
22 changes: 11 additions & 11 deletions app/src/components/Sidebar/CodeDiff/ChartPreview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -52,24 +52,24 @@ function ChartPreview(props: Props) {
/>
</Tooltip>
) : (
<Tooltip title="Add to chart panel, not enough data for preview">
<ShowChart
onClick={onClick}
className={props.classes.icon}
style={{ color: '#aaa' }}
data-test-type="ShowChart"
data-test={props.literal.path}
/>
</Tooltip>
)
<Tooltip title="Add to chart panel, not enough data for preview">
<ShowChart
onClick={onClick}
className={props.classes.icon}
style={{ color: '#aaa' }}
data-test-type="ShowChart"
data-test={props.literal.path}
/>
</Tooltip>
)

return (
<span>
{addChartToPanelButton}
<Popper open={open} anchorEl={chartIconRef.current} placement="left-end">
<Fade in={open} timeout={300}>
<Paper style={{ width: '300px' }}>
{open ? <TopicPlot history={props.treeNode.messageHistory} dotPath={props.literal.path} /> : <span />}
{open ? <TopicPlot node={props.treeNode} history={props.treeNode.messageHistory} dotPath={props.literal.path} /> : <span />}
</Paper>
</Fade>
</Popper>
Expand Down
6 changes: 2 additions & 4 deletions app/src/components/Sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as q from '../../../../backend/src/Model'
import React, { useState, useEffect, useCallback } from 'react'
import ExpandMore from '@material-ui/icons/ExpandMore'
import NodeStats from './NodeStats'
import ValuePanel from './ValueRenderer/ValuePanel'
import { AppState } from '../../reducers'
import { Badge, ExpansionPanel, ExpansionPanelDetails, ExpansionPanelSummary, Typography } from '@material-ui/core'
import { ExpansionPanelDetails } from '@material-ui/core'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { settingsActions, sidebarActions } from '../../actions'
Expand All @@ -28,7 +27,7 @@ interface Props {
}

function useUpdateNodeWhenNodeReceivesUpdates(node?: q.TreeNode<any>) {
const [lastUpdate, setLastUpdate] = useState(0)
const [, setLastUpdate] = useState(0)
const updateNode = useCallback(
throttle(() => {
setLastUpdate(node ? node.lastUpdate : 0)
Expand All @@ -52,7 +51,6 @@ function Sidebar(props: Props) {
const { classes, tree, nodePath } = props
const node = usePollingToFetchTreeNode(tree, nodePath || '')
useUpdateNodeWhenNodeReceivesUpdates(node)
// console.log(node && node.path(), tree, nodePath)

return (
<div id="Sidebar" className={classes.drawer}>
Expand Down
9 changes: 5 additions & 4 deletions app/src/components/Sidebar/TopicPanel/TopicPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import Topic from './Topic'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { RecursiveTopicDeleteButton } from './RecursiveTopicDeleteButton'
import { sidebarActions } from '../../../actions'
import { TopicDeleteButton } from './TopicDeleteButton'
import { TopicTypeButton } from './TopicTypeButton'
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

const deleteTopic = useCallback((topic?: q.TreeNode<any>, recursive: boolean = false) => {
if (!topic) {
return
}

props.actions.clearTopic(topic, recursive)
}, [])

Expand All @@ -29,11 +29,12 @@ const TopicPanel = (props: { node?: q.TreeNode<any>; actions: typeof sidebarActi
Topic {copyTopic}
<TopicDeleteButton node={node} deleteTopicAction={deleteTopic} />
<RecursiveTopicDeleteButton node={node} deleteTopicAction={deleteTopic} />
<TopicTypeButton node={node} />
</span>
<Topic node={node} />
</Panel>
),
[node, node && node.childTopicCount()]
[node, node?.childTopicCount()]
)
}

Expand Down
103 changes: 103 additions & 0 deletions app/src/components/Sidebar/TopicPanel/TopicTypeButton.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, { useCallback, useMemo } from 'react'
import * as q from '../../../../../backend/src/Model'
import ClickAwayListener from '@material-ui/core/ClickAwayListener'
import Grow from '@material-ui/core/Grow'
import Button from '@material-ui/core/Button'
import Paper from '@material-ui/core/Paper'
import Popper from '@material-ui/core/Popper'
import MenuItem from '@material-ui/core/MenuItem'
import MenuList from '@material-ui/core/MenuList'
import WarningRounded from '@material-ui/icons/WarningRounded'
import { MessageDecoder, decoders } from '../../../decoders'
import { Tooltip } from '@material-ui/core'

export const TopicTypeButton = (props: { node?: q.TreeNode<any> }) => {
const { node } = props
if (!node || !node.message || !node.message.payload) {
return null
}

const options = decoders.flatMap(decoder => decoder.formats.map(format => [decoder, format] as const))

const [anchorEl, setAnchorEl] = React.useState<null | HTMLElement>(null)
const [open, setOpen] = React.useState(false)

const selectOption = useCallback(
(decoder: MessageDecoder, format: string) => {
if (!node) {
return
}

node.viewModel.decoder = { decoder, format }
setOpen(false)
},
[node]
)

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?.viewModel.decoder?.format ?? props.node?.type}
<Popper open={open} anchorEl={anchorEl} role={undefined} transition>
{({ TransitionProps, placement }) => (
<Grow
{...TransitionProps}
style={{
transformOrigin: placement === 'bottom' ? 'center top' : 'center bottom',
}}
>
<Paper>
<ClickAwayListener onClickAway={handleClose}>
<MenuList id="topicTypeMode">
{options.map(([decoder, format], index) => (
<MenuItem
key={format}
selected={node && format === node.type}
onClick={() => selectOption(decoder, format)}
>
<DecoderStatus decoder={decoder} format={format} node={node} />
</MenuItem>
))}
</MenuList>
</ClickAwayListener>
</Paper>
</Grow>
)}
</Popper>
</Button>
)
}

function DecoderStatus({ node, decoder, format }: { node: q.TreeNode<any>; decoder: MessageDecoder; format: string }) {
const decoded = useMemo(() => {
return node.message?.payload && decoder.decode(node.message?.payload, format)
}, [node.message, decoder, format])

return decoded?.error ? (
<Tooltip title={decoded.error}>
<div>
{format} <WarningRounded />
</div>
</Tooltip>
) : (
<>{format}</>
)
}
Loading

0 comments on commit 8b43e20

Please sign in to comment.