Fix broker stats
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import React from 'react'
|
||||||
import Chart from './Chart'
|
import Chart from './Chart'
|
||||||
import { ChartParameters } from '../../reducers/Charts'
|
import { ChartParameters } from '../../reducers/Charts'
|
||||||
|
import { usePollingToFetchTreeNode } from '../helper/usePollingToFetchTreeNode'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
tree?: q.Tree<any>
|
tree?: q.Tree<any>
|
||||||
@@ -14,37 +15,6 @@ export function ChartWithTreeNode(props: Props) {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialTreeNode = tree.findNode(parameters.topic)
|
const treeNode = usePollingToFetchTreeNode(tree, parameters.topic)
|
||||||
const [treeNode, setTreeNode] = React.useState<q.TreeNode<any> | undefined>(initialTreeNode)
|
|
||||||
|
|
||||||
usePollingToFetchTreeNode(treeNode, tree, parameters.topic, setTreeNode)
|
|
||||||
return <Chart treeNode={treeNode} parameters={parameters} />
|
return <Chart treeNode={treeNode} parameters={parameters} />
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* If a node is not available when the plot is shown, keep polling until it has been created
|
|
||||||
*/
|
|
||||||
function usePollingToFetchTreeNode(
|
|
||||||
treeNode: q.TreeNode<any> | undefined,
|
|
||||||
tree: q.Tree<any>,
|
|
||||||
path: string,
|
|
||||||
setTreeNode: React.Dispatch<React.SetStateAction<q.TreeNode<any> | undefined>>
|
|
||||||
) {
|
|
||||||
function pollUntilTreeNodeHasBeenFound() {
|
|
||||||
let intervalTimer: any
|
|
||||||
if (!treeNode) {
|
|
||||||
intervalTimer = setInterval(() => {
|
|
||||||
const node = tree.findNode(path)
|
|
||||||
if (node) {
|
|
||||||
setTreeNode(node)
|
|
||||||
clearInterval(intervalTimer)
|
|
||||||
}
|
|
||||||
}, 500)
|
|
||||||
}
|
|
||||||
return function cleanup() {
|
|
||||||
intervalTimer && clearInterval(intervalTimer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
React.useEffect(pollUntilTreeNodeHasBeenFound, [])
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import * as q from '../../../../backend/src/Model'
|
import * as q from '../../../../backend/src/Model'
|
||||||
import * as React from 'react'
|
import React, { useMemo } from 'react'
|
||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
|
import { Base64Message } from '../../../../backend/src/Model/Base64Message'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { StyleRulesCallback, withStyles, Theme } from '@material-ui/core/styles'
|
import { Theme, withStyles } from '@material-ui/core/styles'
|
||||||
import { TopicViewModel } from '../../model/TopicViewModel'
|
import { TopicViewModel } from '../../model/TopicViewModel'
|
||||||
import { Typography } from '@material-ui/core'
|
import { Typography } from '@material-ui/core'
|
||||||
import { Base64Message } from '../../../../backend/src/Model/Base64Message'
|
import { usePollingToFetchTreeNode } from '../helper/usePollingToFetchTreeNode'
|
||||||
import teal from '@material-ui/core/colors/teal'
|
|
||||||
|
|
||||||
const abbreviate = require('number-abbreviate')
|
const abbreviate = require('number-abbreviate')
|
||||||
|
|
||||||
interface Stats {
|
interface Stats {
|
||||||
@@ -16,10 +15,6 @@ interface Stats {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const styles = (theme: Theme) => ({
|
const styles = (theme: Theme) => ({
|
||||||
flex: {
|
|
||||||
display: 'flex',
|
|
||||||
width: '100%',
|
|
||||||
},
|
|
||||||
container: {
|
container: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '224px',
|
height: '224px',
|
||||||
@@ -34,24 +29,12 @@ interface Props {
|
|||||||
tree?: q.Tree<TopicViewModel>
|
tree?: q.Tree<TopicViewModel>
|
||||||
}
|
}
|
||||||
|
|
||||||
class BrokerStatistics extends React.Component<Props, {}> {
|
function BrokerStatistics(props: Props) {
|
||||||
constructor(props: any) {
|
const { tree, classes } = props
|
||||||
super(props)
|
const sysTopic = usePollingToFetchTreeNode(props.tree, '$SYS')
|
||||||
this.state = {}
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderPair(tree: q.Tree<TopicViewModel>, a: Stats, b: Stats) {
|
return useMemo(() => {
|
||||||
return (
|
if (!Boolean(sysTopic)) {
|
||||||
<div className={this.props.classes.flex}>
|
|
||||||
<div style={{ flex: 1 }}>{this.renderStat(tree, a)}</div>
|
|
||||||
<div style={{ flex: 1 }}>{this.renderStat(tree, b)}</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
public render() {
|
|
||||||
const { tree, classes } = this.props
|
|
||||||
if (!tree || !tree.findNode('$SYS/broker/clients/total')) {
|
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,18 +77,45 @@ class BrokerStatistics extends React.Component<Props, {}> {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tree) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classes.container}>
|
<div className={classes.container}>
|
||||||
{this.renderStat(tree, stats.broker)}
|
{renderStat(tree, stats.broker)}
|
||||||
{this.renderPair(tree, stats.sent, stats.received)}
|
{renderPair(tree, stats.sent, stats.received)}
|
||||||
{this.renderPair(tree, stats.clients, stats.subscriptions)}
|
{renderPair(tree, stats.clients, stats.subscriptions)}
|
||||||
{this.renderPair(tree, stats.sent5m, stats.received5m)}
|
{renderPair(tree, stats.sent5m, stats.received5m)}
|
||||||
{this.renderPair(tree, stats.heap, stats.heapMax)}
|
{renderPair(tree, stats.heap, stats.heapMax)}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}, [sysTopic && sysTopic.lastUpdate])
|
||||||
|
}
|
||||||
|
|
||||||
|
const mapStateToProps = (state: AppState) => {
|
||||||
|
return {
|
||||||
|
tree: state.connection.tree,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withStyles(styles)(connect(mapStateToProps)(BrokerStatistics))
|
||||||
|
|
||||||
|
function renderPair(tree: q.Tree<TopicViewModel>, a: Stats, b: Stats) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: 'flex',
|
||||||
|
width: '100%',
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ flex: 1 }}>{renderStat(tree, a)}</div>
|
||||||
|
<div style={{ flex: 1 }}>{renderStat(tree, b)}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
public renderStat(tree: q.Tree<TopicViewModel>, stat: Stats) {
|
function renderStat(tree: q.Tree<TopicViewModel>, stat: Stats) {
|
||||||
const node = tree.findNode(stat.topic)
|
const node = tree.findNode(stat.topic)
|
||||||
if (!node || !node.message) {
|
if (!node || !node.message) {
|
||||||
return null
|
return null
|
||||||
@@ -126,12 +136,3 @@ class BrokerStatistics extends React.Component<Props, {}> {
|
|||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const mapStateToProps = (state: AppState) => {
|
|
||||||
return {
|
|
||||||
tree: state.connection.tree,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export default withStyles(styles)(connect(mapStateToProps)(BrokerStatistics))
|
|
||||||
|
|||||||
38
app/src/components/helper/usePollingToFetchTreeNode.tsx
Normal file
38
app/src/components/helper/usePollingToFetchTreeNode.tsx
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
import * as q from '../../../../backend/src/Model'
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If a node is not available when the plot is shown, keep polling until it has been created
|
||||||
|
*/
|
||||||
|
export function usePollingToFetchTreeNode(tree: q.Tree<any> | undefined, path: string) {
|
||||||
|
const [treeNode, setTreeNode] = useState<q.TreeNode<any> | undefined>()
|
||||||
|
|
||||||
|
function pollUntilTreeNodeHasBeenFound() {
|
||||||
|
if (!tree) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const initialTreeNode = tree.findNode(path)
|
||||||
|
if (initialTreeNode) {
|
||||||
|
setTreeNode(initialTreeNode)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let intervalTimer: any
|
||||||
|
if (!treeNode) {
|
||||||
|
intervalTimer = setInterval(() => {
|
||||||
|
const node = tree.findNode(path)
|
||||||
|
if (node) {
|
||||||
|
setTreeNode(node)
|
||||||
|
clearInterval(intervalTimer)
|
||||||
|
}
|
||||||
|
}, 500)
|
||||||
|
}
|
||||||
|
return function cleanup() {
|
||||||
|
intervalTimer && clearInterval(intervalTimer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(pollUntilTreeNodeHasBeenFound, [tree])
|
||||||
|
return treeNode
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user