Refactor
This commit is contained in:
@@ -28,6 +28,7 @@
|
|||||||
"file-loader": "^4.0.0",
|
"file-loader": "^4.0.0",
|
||||||
"get-value": "^3.0.1",
|
"get-value": "^3.0.1",
|
||||||
"immutable": "^4.0.0-rc.12",
|
"immutable": "^4.0.0-rc.12",
|
||||||
|
"in-viewport": "^3.6.0",
|
||||||
"js-base64": "^2.5.1",
|
"js-base64": "^2.5.1",
|
||||||
"json-to-ast": "^2.1.0",
|
"json-to-ast": "^2.1.0",
|
||||||
"lodash.debounce": "^4.0.8",
|
"lodash.debounce": "^4.0.8",
|
||||||
|
|||||||
@@ -99,13 +99,16 @@ export const togglePause = (tree?: q.Tree<TopicViewModel>) => (dispatch: Dispatc
|
|||||||
const tree = getState().tree.get('tree')
|
const tree = getState().tree.get('tree')
|
||||||
const changes = tree ? tree.unmergedChanges().length : 0
|
const changes = tree ? tree.unmergedChanges().length : 0
|
||||||
|
|
||||||
|
if (tree) {
|
||||||
|
paused ? tree.resume() : tree.pause()
|
||||||
|
}
|
||||||
|
|
||||||
if (paused && changes > 0) {
|
if (paused && changes > 0) {
|
||||||
dispatch(globalActions.showNotification('Applying recorded changes.'))
|
dispatch(globalActions.showNotification('Applying recorded changes.'))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow for notification to be displayed
|
// Allow for notification to be displayed
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
tree && tree.applyUnmergedChanges()
|
|
||||||
if (paused && changes > 0) {
|
if (paused && changes > 0) {
|
||||||
dispatch(globalActions.showNotification(`Successfully applied ${changes} changes.`))
|
dispatch(globalActions.showNotification(`Successfully applied ${changes} changes.`))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function useStagedRendering(treeNode: q.TreeNode<any>) {
|
|||||||
if (alreadyAdded < edges.length) {
|
if (alreadyAdded < edges.length) {
|
||||||
renderMoreAnimationFrame = (window as any).requestIdleCallback(
|
renderMoreAnimationFrame = (window as any).requestIdleCallback(
|
||||||
() => {
|
() => {
|
||||||
setAlreadyAdded(alreadyAdded * 1.5)
|
setAlreadyAdded(Math.max(25, alreadyAdded * 1.5))
|
||||||
},
|
},
|
||||||
{ timeout: 500 }
|
{ timeout: 500 }
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useEffect } from 'react'
|
import React, { useEffect } from 'react'
|
||||||
|
var inViewport = require('in-viewport')
|
||||||
|
|
||||||
export function useAnimationToIndicateTopicUpdate(
|
export function useAnimationToIndicateTopicUpdate(
|
||||||
ref: React.MutableRefObject<HTMLDivElement | undefined>,
|
ref: React.MutableRefObject<HTMLDivElement | undefined>,
|
||||||
@@ -9,6 +10,10 @@ export function useAnimationToIndicateTopicUpdate(
|
|||||||
) {
|
) {
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (ref.current && shouldAnimate && Date.now() - lastUpdate < 3000 && !selected) {
|
if (ref.current && shouldAnimate && Date.now() - lastUpdate < 3000 && !selected) {
|
||||||
|
if (!inViewport(ref.current)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let timeout: any
|
let timeout: any
|
||||||
let animationFrame = requestAnimationFrame(() => {
|
let animationFrame = requestAnimationFrame(() => {
|
||||||
ref.current && ref.current.classList.add(className)
|
ref.current && ref.current.classList.add(className)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { useEffect, useState } from 'react'
|
|||||||
export function useIsAllowedToAutoExpandState(props: Props): boolean {
|
export function useIsAllowedToAutoExpandState(props: Props): boolean {
|
||||||
const { settings, treeNode, isRoot } = props
|
const { settings, treeNode, isRoot } = props
|
||||||
const [isAllowedToAutoExpand, setAllowAutoExpand] = useState(false)
|
const [isAllowedToAutoExpand, setAllowAutoExpand] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const newIsAllowedToAutoExpand = isRoot || treeNode.edgeCount() <= settings.get('autoExpandLimit')
|
const newIsAllowedToAutoExpand = isRoot || treeNode.edgeCount() <= settings.get('autoExpandLimit')
|
||||||
if (newIsAllowedToAutoExpand !== isAllowedToAutoExpand) {
|
if (newIsAllowedToAutoExpand !== isAllowedToAutoExpand) {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export function useViewModelSubscriptions(
|
|||||||
setSelected: (value: boolean) => void,
|
setSelected: (value: boolean) => void,
|
||||||
setCollapsedOverride: (value: boolean) => void
|
setCollapsedOverride: (value: boolean) => void
|
||||||
) {
|
) {
|
||||||
|
useEffect(() => {
|
||||||
const selectionDidChange = () => {
|
const selectionDidChange = () => {
|
||||||
const selected = treeNode.viewModel && treeNode.viewModel.isSelected()
|
const selected = treeNode.viewModel && treeNode.viewModel.isSelected()
|
||||||
treeNode.viewModel && setSelected(Boolean(selected))
|
treeNode.viewModel && setSelected(Boolean(selected))
|
||||||
@@ -21,13 +22,6 @@ export function useViewModelSubscriptions(
|
|||||||
treeNode.viewModel && setCollapsedOverride(!treeNode.viewModel.isExpanded())
|
treeNode.viewModel && setCollapsedOverride(!treeNode.viewModel.isExpanded())
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
addSubscriber()
|
|
||||||
return function cleanup() {
|
|
||||||
removeSubscriber()
|
|
||||||
}
|
|
||||||
}, [treeNode])
|
|
||||||
|
|
||||||
function addSubscriber() {
|
function addSubscriber() {
|
||||||
treeNode.viewModel = new TopicViewModel()
|
treeNode.viewModel = new TopicViewModel()
|
||||||
treeNode.viewModel.selectionChange.subscribe(selectionDidChange)
|
treeNode.viewModel.selectionChange.subscribe(selectionDidChange)
|
||||||
@@ -41,4 +35,10 @@ export function useViewModelSubscriptions(
|
|||||||
treeNode.viewModel = undefined
|
treeNode.viewModel = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSubscriber()
|
||||||
|
return function cleanup() {
|
||||||
|
removeSubscriber()
|
||||||
|
}
|
||||||
|
}, [treeNode])
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,10 +48,6 @@ function TreeNodeComponent(props: Props) {
|
|||||||
const isCollapsed =
|
const isCollapsed =
|
||||||
Boolean(collapsedOverride) === collapsedOverride ? Boolean(collapsedOverride) : !isAllowedToAutoExpand
|
Boolean(collapsedOverride) === collapsedOverride ? Boolean(collapsedOverride) : !isAllowedToAutoExpand
|
||||||
|
|
||||||
const toggle = useCallback(() => {
|
|
||||||
setCollapsedOverride(!isCollapsed)
|
|
||||||
}, [isCollapsed])
|
|
||||||
|
|
||||||
const didSelectTopic = useCallback(
|
const didSelectTopic = useCallback(
|
||||||
(event?: React.MouseEvent) => {
|
(event?: React.MouseEvent) => {
|
||||||
event && event.stopPropagation()
|
event && event.stopPropagation()
|
||||||
@@ -64,17 +60,17 @@ function TreeNodeComponent(props: Props) {
|
|||||||
(event: React.MouseEvent) => {
|
(event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
didSelectTopic()
|
didSelectTopic()
|
||||||
toggle()
|
setCollapsedOverride(!isCollapsed)
|
||||||
},
|
},
|
||||||
[toggle, didSelectTopic]
|
[isCollapsed, didSelectTopic]
|
||||||
)
|
)
|
||||||
|
|
||||||
const toggleCollapsed = useCallback(
|
const toggleCollapsed = useCallback(
|
||||||
(event: React.MouseEvent) => {
|
(event: React.MouseEvent) => {
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
toggle()
|
setCollapsedOverride(!isCollapsed)
|
||||||
},
|
},
|
||||||
[toggle]
|
[isCollapsed]
|
||||||
)
|
)
|
||||||
|
|
||||||
const didObtainFocus = useCallback(() => {
|
const didObtainFocus = useCallback(() => {
|
||||||
|
|||||||
@@ -4,11 +4,10 @@ import TreeNode from './TreeNode'
|
|||||||
import { AppState } from '../../reducers'
|
import { AppState } from '../../reducers'
|
||||||
import { bindActionCreators } from 'redux'
|
import { bindActionCreators } from 'redux'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
|
import { KeyCodes } from '../../utils/KeyCodes'
|
||||||
import { SettingsState } from '../../reducers/Settings'
|
import { SettingsState } from '../../reducers/Settings'
|
||||||
import { TopicViewModel } from '../../model/TopicViewModel'
|
import { TopicViewModel } from '../../model/TopicViewModel'
|
||||||
import { treeActions } from '../../actions'
|
import { treeActions } from '../../actions'
|
||||||
import { KeyCodes } from '../../utils/KeyCodes'
|
|
||||||
|
|
||||||
const MovingAverage = require('moving-average')
|
const MovingAverage = require('moving-average')
|
||||||
|
|
||||||
const averagingTimeInterval = 10 * 1000
|
const averagingTimeInterval = 10 * 1000
|
||||||
@@ -70,17 +69,17 @@ class TreeComponent extends React.PureComponent<Props, State> {
|
|||||||
public componentWillReceiveProps(nextProps: Props) {
|
public componentWillReceiveProps(nextProps: Props) {
|
||||||
if (this.props.tree !== nextProps.tree) {
|
if (this.props.tree !== nextProps.tree) {
|
||||||
if (this.props.tree) {
|
if (this.props.tree) {
|
||||||
this.props.tree.didReceive.unsubscribe(this.throttledTreeUpdate)
|
this.props.tree.didUpdate.unsubscribe(this.throttledTreeUpdate)
|
||||||
}
|
}
|
||||||
if (nextProps.tree) {
|
if (nextProps.tree) {
|
||||||
nextProps.tree.didReceive.subscribe(this.throttledTreeUpdate)
|
nextProps.tree.didUpdate.subscribe(this.throttledTreeUpdate)
|
||||||
}
|
}
|
||||||
this.setState(this.state)
|
this.setState(this.state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public componentWillUnmount() {
|
public componentWillUnmount() {
|
||||||
this.props.tree && this.props.tree.didReceive.unsubscribe(this.throttledTreeUpdate)
|
this.props.tree && this.props.tree.didUpdate.unsubscribe(this.throttledTreeUpdate)
|
||||||
}
|
}
|
||||||
|
|
||||||
public throttledTreeUpdate = () => {
|
public throttledTreeUpdate = () => {
|
||||||
@@ -99,9 +98,6 @@ class TreeComponent extends React.PureComponent<Props, State> {
|
|||||||
this.updateTimer = undefined
|
this.updateTimer = undefined
|
||||||
this.renderTime = performance.now()
|
this.renderTime = performance.now()
|
||||||
|
|
||||||
if (!this.props.paused && this.props.tree) {
|
|
||||||
this.props.tree.applyUnmergedChanges()
|
|
||||||
}
|
|
||||||
window.requestIdleCallback(
|
window.requestIdleCallback(
|
||||||
() => {
|
() => {
|
||||||
this.setState({ lastUpdate: this.renderTime })
|
this.setState({ lastUpdate: this.renderTime })
|
||||||
|
|||||||
@@ -3038,6 +3038,11 @@ imurmurhash@^0.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
|
||||||
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
|
||||||
|
|
||||||
|
in-viewport@^3.6.0:
|
||||||
|
version "3.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/in-viewport/-/in-viewport-3.6.0.tgz#c59b4cdcaa41adb5bf5b8fe390c7d34259891f4a"
|
||||||
|
integrity sha512-MhaJ7Pr3NhUyAfpULysTZZBUAYfJAX1O8PccW2gvXlbQduMrJz7qQQ5yzC7SAr/0g5LbeRk432yNjsLMCnYzJg==
|
||||||
|
|
||||||
indexes-of@^1.0.1:
|
indexes-of@^1.0.1:
|
||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
|
||||||
|
|||||||
@@ -12,7 +12,11 @@ export class Tree<ViewModel extends Destroyable> extends TreeNode<ViewModel> {
|
|||||||
public isTree = true
|
public isTree = true
|
||||||
private cachedHash = `${Math.random()}`
|
private cachedHash = `${Math.random()}`
|
||||||
private unmergedMessages: ChangeBuffer = new ChangeBuffer()
|
private unmergedMessages: ChangeBuffer = new ChangeBuffer()
|
||||||
public didReceive = new EventDispatcher<void>()
|
public didUpdate = new EventDispatcher<void>()
|
||||||
|
|
||||||
|
public updateInterval: any
|
||||||
|
private paused: boolean = false
|
||||||
|
private applyChangesHasCompleted = true
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super(undefined, undefined)
|
super(undefined, undefined)
|
||||||
@@ -20,14 +24,27 @@ export class Tree<ViewModel extends Destroyable> extends TreeNode<ViewModel> {
|
|||||||
|
|
||||||
private handleNewData = (msg: MqttMessage) => {
|
private handleNewData = (msg: MqttMessage) => {
|
||||||
this.unmergedMessages.push(msg)
|
this.unmergedMessages.push(msg)
|
||||||
this.didReceive.dispatch()
|
}
|
||||||
|
|
||||||
|
private runUpdates() {
|
||||||
|
this.updateInterval = setInterval(() => {
|
||||||
|
if (!this.paused && this.applyChangesHasCompleted) {
|
||||||
|
this.applyChangesHasCompleted = false
|
||||||
|
if ((window as any).requestIdleCallback) {
|
||||||
|
;(window as any).requestIdleCallback(() => this.applyUnmergedChanges(), { timeout: 500 })
|
||||||
|
} else {
|
||||||
|
this.applyUnmergedChanges()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, 300)
|
||||||
}
|
}
|
||||||
|
|
||||||
public destroy() {
|
public destroy() {
|
||||||
super.destroy()
|
super.destroy()
|
||||||
|
this.updateInterval && clearInterval(this.updateInterval)
|
||||||
this.updateSource && this.updateSource.unsubscribe(this.subscriptionEvent, this.handleNewData)
|
this.updateSource && this.updateSource.unsubscribe(this.subscriptionEvent, this.handleNewData)
|
||||||
this.updateSource = undefined
|
this.updateSource = undefined
|
||||||
this.didReceive.removeAllListeners()
|
this.didUpdate.removeAllListeners()
|
||||||
}
|
}
|
||||||
|
|
||||||
public updateWithConnection(
|
public updateWithConnection(
|
||||||
@@ -41,12 +58,21 @@ export class Tree<ViewModel extends Destroyable> extends TreeNode<ViewModel> {
|
|||||||
|
|
||||||
this.subscriptionEvent = makeConnectionMessageEvent(connectionId)
|
this.subscriptionEvent = makeConnectionMessageEvent(connectionId)
|
||||||
this.updateSource.subscribe(this.subscriptionEvent, this.handleNewData)
|
this.updateSource.subscribe(this.subscriptionEvent, this.handleNewData)
|
||||||
|
this.runUpdates()
|
||||||
}
|
}
|
||||||
|
|
||||||
public hash() {
|
public hash() {
|
||||||
return this.cachedHash
|
return this.cachedHash
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public pause() {
|
||||||
|
this.paused = true
|
||||||
|
}
|
||||||
|
|
||||||
|
public resume() {
|
||||||
|
this.paused = false
|
||||||
|
}
|
||||||
|
|
||||||
public applyUnmergedChanges() {
|
public applyUnmergedChanges() {
|
||||||
this.unmergedMessages.popAll().forEach(bufferedItem => {
|
this.unmergedMessages.popAll().forEach(bufferedItem => {
|
||||||
const edges = bufferedItem.message.topic.split('/')
|
const edges = bufferedItem.message.topic.split('/')
|
||||||
@@ -61,6 +87,9 @@ export class Tree<ViewModel extends Destroyable> extends TreeNode<ViewModel> {
|
|||||||
this.updateWithNode(node.firstNode())
|
this.updateWithNode(node.firstNode())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.didUpdate.dispatch()
|
||||||
|
this.applyChangesHasCompleted = true
|
||||||
}
|
}
|
||||||
|
|
||||||
public unmergedChanges(): ChangeBuffer {
|
public unmergedChanges(): ChangeBuffer {
|
||||||
|
|||||||
Reference in New Issue
Block a user