WiP
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer/releases)
|
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer/releases)
|
||||||
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer/releases)
|
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer/releases)
|
||||||
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer)
|
[](https://travis-ci.org/thomasnordquist/MQTT-Explorer)
|
||||||
|

|
||||||
|
|
||||||
### Version {{ version }}
|
### Version {{ version }}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,6 @@ class RemoteStorage implements PersistantStorage {
|
|||||||
const ack = makeStorageAcknoledgementEvent(transactionId)
|
const ack = makeStorageAcknoledgementEvent(transactionId)
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const callback = (msg: any) => {
|
const callback = (msg: any) => {
|
||||||
console.log(msg)
|
|
||||||
if (msg && msg.error) {
|
if (msg && msg.error) {
|
||||||
reject(msg.error)
|
reject(msg.error)
|
||||||
} else {
|
} else {
|
||||||
@@ -57,8 +56,6 @@ class RemoteStorage implements PersistantStorage {
|
|||||||
|
|
||||||
const promise = new Promise<Model>((resolve, reject) => {
|
const promise = new Promise<Model>((resolve, reject) => {
|
||||||
const callback = (msg: any) => {
|
const callback = (msg: any) => {
|
||||||
console.log(msg)
|
|
||||||
|
|
||||||
if (msg.error) {
|
if (msg.error) {
|
||||||
reject(msg.error)
|
reject(msg.error)
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -1,21 +1,43 @@
|
|||||||
import { Dispatch, Action } from 'redux'
|
import { Dispatch, Action } from 'redux'
|
||||||
import { AppState } from '../reducers'
|
import { AppState } from '../reducers'
|
||||||
import { makePublishEvent, rendererEvents } from '../../../events'
|
import { makePublishEvent, rendererEvents } from '../../../events'
|
||||||
|
import * as q from '../../../backend/src/Model'
|
||||||
|
|
||||||
export const clearRetainedTopic = () => (dispatch: Dispatch<Action>, getState: () => AppState) => {
|
export const clearRetainedTopic = () => (dispatch: Dispatch<any>, getState: () => AppState) => {
|
||||||
const { selectedTopic } = getState().tree
|
const { selectedTopic } = getState().tree
|
||||||
const { connectionId } = getState().connection
|
if (!selectedTopic) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (!selectedTopic || !connectionId) {
|
dispatch(clearTopic(selectedTopic, false))
|
||||||
|
}
|
||||||
|
|
||||||
|
export const clearTopic = (topic: q.TreeNode<any>, recursive: boolean) => (dispatch: Dispatch<any>, getState: () => AppState) => {
|
||||||
|
const { connectionId } = getState().connection
|
||||||
|
if (!connectionId) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
const publishEvent = makePublishEvent(connectionId)
|
const publishEvent = makePublishEvent(connectionId)
|
||||||
const mqttMessage = {
|
const mqttMessage = {
|
||||||
topic: selectedTopic.path(),
|
topic: topic.path(),
|
||||||
|
payload: null,
|
||||||
|
retain: true,
|
||||||
|
qos: 0 as 0,
|
||||||
|
}
|
||||||
|
console.log('deleting', topic.path())
|
||||||
|
rendererEvents.emit(publishEvent, mqttMessage)
|
||||||
|
|
||||||
|
if (recursive) {
|
||||||
|
topic.childTopics().forEach((topic) => {
|
||||||
|
console.log('deleting', topic.path())
|
||||||
|
const mqttMessage = {
|
||||||
|
topic: topic.path(),
|
||||||
payload: null,
|
payload: null,
|
||||||
retain: true,
|
retain: true,
|
||||||
qos: 0 as 0,
|
qos: 0 as 0,
|
||||||
}
|
}
|
||||||
rendererEvents.emit(publishEvent, mqttMessage)
|
rendererEvents.emit(publishEvent, mqttMessage)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import FileCopy from '@material-ui/icons/FileCopy'
|
|||||||
import Check from '@material-ui/icons/Check'
|
import Check from '@material-ui/icons/Check'
|
||||||
import green from '@material-ui/core/colors/green'
|
import green from '@material-ui/core/colors/green'
|
||||||
import { withStyles, Theme } from '@material-ui/core/styles'
|
import { withStyles, Theme } from '@material-ui/core/styles'
|
||||||
|
import CustomIconButton from './CustomIconButton';
|
||||||
|
|
||||||
const copy = require('copy-text-to-clipboard')
|
const copy = require('copy-text-to-clipboard')
|
||||||
|
|
||||||
@@ -32,13 +33,17 @@ class Copy extends React.Component<Props, State> {
|
|||||||
|
|
||||||
public render() {
|
public render() {
|
||||||
const icon = !this.state.didCopy
|
const icon = !this.state.didCopy
|
||||||
? <FileCopy fontSize="inherit" style={{ cursor: 'pointer' }} onClick={this.handleClick} />
|
? <FileCopy fontSize="inherit" />
|
||||||
: <Check fontSize="inherit" style={{ cursor: 'default' }} />
|
: <Check fontSize="inherit" style={{ cursor: 'default' }} />
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<span>
|
<span>
|
||||||
<Tooltip placement="top" title="Copy to clipboard">
|
<Tooltip placement="top" title="Copy to clipboard">
|
||||||
<span style={{ fontSize: '16px' }}>{icon}</span>
|
<span style={{ fontSize: '16px' }}>
|
||||||
|
<CustomIconButton onClick={this.handleClick} >
|
||||||
|
{icon}
|
||||||
|
</CustomIconButton>
|
||||||
|
</span>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
<span>
|
<span>
|
||||||
<Snackbar
|
<Snackbar
|
||||||
|
|||||||
34
app/src/components/CustomIconButton.tsx
Normal file
34
app/src/components/CustomIconButton.tsx
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import { IconButton } from '@material-ui/core'
|
||||||
|
import { withStyles, Theme } from '@material-ui/core/styles'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
onClick: any,
|
||||||
|
classes: any
|
||||||
|
}
|
||||||
|
|
||||||
|
const styles = (theme: Theme) => ({
|
||||||
|
button: {
|
||||||
|
padding: '6px',
|
||||||
|
fontSize: '1.2em',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
class CustomIconButton extends React.Component<Props, {}> {
|
||||||
|
constructor(props: Props) {
|
||||||
|
super(props)
|
||||||
|
}
|
||||||
|
|
||||||
|
public render() {
|
||||||
|
return (
|
||||||
|
<IconButton className={this.props.classes.button} onClick={this.onClick}>{this.props.children}</IconButton>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private onClick = (event: React.MouseEvent) => {
|
||||||
|
event.stopPropagation()
|
||||||
|
this.props.onClick(event)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles)(CustomIconButton)
|
||||||
@@ -18,7 +18,7 @@ import { StyleRulesCallback, withStyles } from '@material-ui/core/styles'
|
|||||||
import ChevronRight from '@material-ui/icons/ChevronRight'
|
import ChevronRight from '@material-ui/icons/ChevronRight'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { settingsActions, treeActions } from '../actions'
|
import { settingsActions } from '../actions'
|
||||||
import { TopicOrder } from '../reducers/Settings'
|
import { TopicOrder } from '../reducers/Settings'
|
||||||
import BrokerStatistics from './BrokerStatistics'
|
import BrokerStatistics from './BrokerStatistics'
|
||||||
import { shell } from 'electron';
|
import { shell } from 'electron';
|
||||||
|
|||||||
@@ -1,5 +1,20 @@
|
|||||||
import * as React from 'react'
|
|
||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
|
import * as React from 'react'
|
||||||
|
import Clear from '@material-ui/icons/Clear'
|
||||||
|
import Copy from '../Copy'
|
||||||
|
import DateFormatter from '../helper/DateFormatter'
|
||||||
|
import Delete from '@material-ui/icons/Delete'
|
||||||
|
import ExpandMore from '@material-ui/icons/ExpandMore'
|
||||||
|
import MessageHistory from './MessageHistory'
|
||||||
|
import NodeStats from './NodeStats'
|
||||||
|
import Topic from './Topic'
|
||||||
|
import { AppState } from '../../reducers'
|
||||||
|
import { bindActionCreators } from 'redux'
|
||||||
|
import { connect } from 'react-redux'
|
||||||
|
import { default as ReactResizeDetector } from 'react-resize-detector'
|
||||||
|
import { sidebarActons } from '../../actions'
|
||||||
|
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
||||||
|
import { TopicViewModel } from '../../TopicViewModel'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
Button,
|
Button,
|
||||||
@@ -12,22 +27,8 @@ import {
|
|||||||
Typography,
|
Typography,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
} from '@material-ui/core'
|
} from '@material-ui/core'
|
||||||
import { StyleRulesCallback, Theme, withStyles } from '@material-ui/core/styles'
|
import CustomIconButton from '../CustomIconButton';
|
||||||
|
|
||||||
import { sidebarActons } from '../../actions'
|
|
||||||
|
|
||||||
import { AppState } from '../../reducers'
|
|
||||||
import Copy from '../Copy'
|
|
||||||
import DateFormatter from '../helper/DateFormatter'
|
|
||||||
import ExpandMore from '@material-ui/icons/ExpandMore'
|
|
||||||
import Clear from '@material-ui/icons/Clear'
|
|
||||||
import MessageHistory from './MessageHistory'
|
|
||||||
import NodeStats from './NodeStats'
|
|
||||||
import Topic from './Topic'
|
|
||||||
import { connect } from 'react-redux'
|
|
||||||
import { bindActionCreators } from 'redux'
|
|
||||||
import { TopicViewModel } from '../../TopicViewModel'
|
|
||||||
import { default as ReactResizeDetector } from 'react-resize-detector'
|
|
||||||
const throttle = require('lodash.throttle')
|
const throttle = require('lodash.throttle')
|
||||||
|
|
||||||
const Publish = React.lazy(() => import('./Publish/Publish'))
|
const Publish = React.lazy(() => import('./Publish/Publish'))
|
||||||
@@ -92,17 +93,43 @@ class Sidebar extends React.Component<Props, State> {
|
|||||||
|
|
||||||
private detailsStyle = { padding: '0px 16px 8px 8px', display: 'block' }
|
private detailsStyle = { padding: '0px 16px 8px 8px', display: 'block' }
|
||||||
|
|
||||||
|
private renderTopicDeleteButton() {
|
||||||
|
if (!this.props.node) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <CustomIconButton onClick={() => this.deleteTopic(this.props.node)}><Delete /></CustomIconButton>
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderRecursiveTopicDeleteButton() {
|
||||||
|
if (!this.props.node) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return <CustomIconButton onClick={() => this.deleteTopic(this.props.node, true)}><Delete style={{ color: 'red' }} /></CustomIconButton>
|
||||||
|
}
|
||||||
|
|
||||||
|
private deleteTopic = (topic?: q.TreeNode<TopicViewModel>, recursive: boolean = false) => {
|
||||||
|
if (!topic) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.props.actions.clearTopic(topic, recursive)
|
||||||
|
}
|
||||||
|
|
||||||
private renderNode() {
|
private renderNode() {
|
||||||
const { classes, node } = this.props
|
const { classes, node } = this.props
|
||||||
|
|
||||||
const copyTopic = node ? <Copy value={node.path()} /> : null
|
const copyTopic = node ? <Copy value={node.path()} /> : null
|
||||||
|
const deleteTopic = this.renderTopicDeleteButton()
|
||||||
|
const deleteRecursiveTopic = this.renderRecursiveTopicDeleteButton()
|
||||||
const copyValue = node && node.message ? <Copy value={node.message.value} /> : null
|
const copyValue = node && node.message ? <Copy value={node.message.value} /> : null
|
||||||
const summeryStyle = { minHeight: '0' }
|
const summeryStyle = { minHeight: '0' }
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<ExpansionPanel key="topic" defaultExpanded={true} disabled={!Boolean(this.props.node)}>
|
<ExpansionPanel key="topic" defaultExpanded={true} disabled={!Boolean(this.props.node)}>
|
||||||
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
|
<ExpansionPanelSummary expandIcon={<ExpandMore />} style={summeryStyle}>
|
||||||
<Typography className={classes.heading}>Topic {copyTopic}</Typography>
|
<Typography className={classes.heading}>Topic {copyTopic} {deleteTopic} {deleteRecursiveTopic}</Typography>
|
||||||
</ExpansionPanelSummary>
|
</ExpansionPanelSummary>
|
||||||
<ExpansionPanelDetails style={this.detailsStyle}>
|
<ExpansionPanelDetails style={this.detailsStyle}>
|
||||||
<Topic node={this.props.node} didSelectNode={this.updateNode} />
|
<Topic node={this.props.node} didSelectNode={this.updateNode} />
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ class IpcMainEventBus implements EventBusInterface {
|
|||||||
public subscribe<MessageType>(subscribeEvent: Event<MessageType>, callback:(msg: MessageType) => void) {
|
public subscribe<MessageType>(subscribeEvent: Event<MessageType>, callback:(msg: MessageType) => void) {
|
||||||
console.log('subscribing', subscribeEvent.topic)
|
console.log('subscribing', subscribeEvent.topic)
|
||||||
this.ipc.on(subscribeEvent.topic, (event: any, arg: any) => {
|
this.ipc.on(subscribeEvent.topic, (event: any, arg: any) => {
|
||||||
|
console.log(subscribeEvent.topic, arg)
|
||||||
this.client = event.sender
|
this.client = event.sender
|
||||||
callback(arg)
|
callback(arg)
|
||||||
})
|
})
|
||||||
@@ -39,6 +40,8 @@ class IpcMainEventBus implements EventBusInterface {
|
|||||||
|
|
||||||
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
||||||
if (!this.client.isDestroyed()) {
|
if (!this.client.isDestroyed()) {
|
||||||
|
console.log(event.topic, msg)
|
||||||
|
|
||||||
this.client.send(event.topic, msg)
|
this.client.send(event.topic, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,6 +83,7 @@ class IpcRendererEventBus implements EventBusInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
public emit<MessageType>(event: Event<MessageType>, msg: MessageType) {
|
||||||
|
console.log(event.topic, msg)
|
||||||
this.ipc.send(event.topic, msg)
|
this.ipc.send(event.topic, msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user