Make topics selectable
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import { Hashable, TreeNode } from './'
|
||||
const sha1 = require('sha1')
|
||||
|
||||
export class Edge implements Hashable {
|
||||
export class Edge<ViewModel> implements Hashable {
|
||||
public name: string
|
||||
|
||||
public target!: TreeNode
|
||||
public source?: TreeNode | undefined
|
||||
public target!: TreeNode<ViewModel>
|
||||
public source?: TreeNode<ViewModel> | undefined
|
||||
private cachedHash?: string
|
||||
|
||||
constructor(name: string) {
|
||||
@@ -32,7 +32,7 @@ export class Edge implements Hashable {
|
||||
return this.cachedHash
|
||||
}
|
||||
|
||||
public firstEdge(): Edge {
|
||||
public firstEdge(): Edge<ViewModel> {
|
||||
if (this.source && this.source.sourceEdge) {
|
||||
return this.source.sourceEdge.firstEdge()
|
||||
}
|
||||
|
||||
@@ -1,20 +1,22 @@
|
||||
import { TreeNode } from './'
|
||||
import { EventBusInterface, makeConnectionMessageEvent, MqttMessage } from '../../../events'
|
||||
import { EventBusInterface, makeConnectionMessageEvent, MqttMessage, EventDispatcher } from '../../../events'
|
||||
import { TreeNodeFactory } from './TreeNodeFactory'
|
||||
|
||||
export class Tree extends TreeNode {
|
||||
export class Tree<ViewModel> extends TreeNode<ViewModel> {
|
||||
public connectionId?: string
|
||||
public updateSource?: EventBusInterface
|
||||
public nodeFilter?: (node: TreeNode) => boolean
|
||||
public nodeFilter?: (node: TreeNode<ViewModel>) => boolean
|
||||
private subscriptionEvent?: any
|
||||
public isTree = true
|
||||
private cachedHash = `${Math.random()}`
|
||||
private unmergedMessages: MqttMessage[] = []
|
||||
public didReceive = new EventDispatcher<void, Tree<ViewModel>>(this)
|
||||
|
||||
constructor() {
|
||||
super(undefined, undefined)
|
||||
}
|
||||
|
||||
public updateWithConnection(emitter: EventBusInterface, connectionId: string, nodeFilter?:(node: TreeNode) => boolean) {
|
||||
public updateWithConnection(emitter: EventBusInterface, connectionId: string, nodeFilter?:(node: TreeNode<ViewModel>) => boolean) {
|
||||
this.updateSource = emitter
|
||||
this.connectionId = connectionId
|
||||
this.nodeFilter = nodeFilter
|
||||
@@ -27,15 +29,22 @@ export class Tree extends TreeNode {
|
||||
return this.cachedHash
|
||||
}
|
||||
|
||||
private handleNewData = (msg: MqttMessage) => {
|
||||
const edges = msg.topic.split('/')
|
||||
const node = TreeNodeFactory.fromEdgesAndValue(edges, msg.payload)
|
||||
node.mqttMessage = msg
|
||||
public applyUnmergedChanges() {
|
||||
this.unmergedMessages.forEach((msg) => {
|
||||
const edges = msg.topic.split('/')
|
||||
const node = TreeNodeFactory.fromEdgesAndValue<ViewModel, any>(edges, msg.payload)
|
||||
node.mqttMessage = msg
|
||||
|
||||
if (this.nodeFilter && !this.nodeFilter(node)) {
|
||||
return
|
||||
}
|
||||
this.updateWithNode(node.firstNode())
|
||||
if (!this.nodeFilter || this.nodeFilter(node)) {
|
||||
this.updateWithNode(node.firstNode())
|
||||
}
|
||||
})
|
||||
this.unmergedMessages = []
|
||||
}
|
||||
|
||||
private handleNewData = (msg: MqttMessage) => {
|
||||
this.unmergedMessages.push(msg)
|
||||
this.didReceive.dispatch()
|
||||
}
|
||||
|
||||
public stopUpdating() {
|
||||
|
||||
@@ -1,28 +1,29 @@
|
||||
import { Edge, Message, RingBuffer } from './'
|
||||
import { EventDispatcher, MqttMessage } from '../../../events'
|
||||
|
||||
export class TreeNode {
|
||||
public sourceEdge?: Edge
|
||||
export class TreeNode<ViewModel> {
|
||||
public sourceEdge?: Edge<ViewModel>
|
||||
public message?: Message
|
||||
public mqttMessage?: MqttMessage
|
||||
public messageHistory: RingBuffer<Message> = new RingBuffer<Message>(3000, 100)
|
||||
public edges: {[s: string]: Edge} = {}
|
||||
public edgeArray: Edge[] = []
|
||||
public viewModel?: ViewModel
|
||||
public edges: {[s: string]: Edge<ViewModel>} = {}
|
||||
public edgeArray: Edge<ViewModel>[] = []
|
||||
public collapsed = false
|
||||
public messages: number = 0
|
||||
public lastUpdate: number = Date.now()
|
||||
public onMerge = new EventDispatcher<void, TreeNode>(this)
|
||||
public onEdgesChange = new EventDispatcher<void, TreeNode>(this)
|
||||
public onMessage = new EventDispatcher<Message, TreeNode>(this)
|
||||
public onMerge = new EventDispatcher<void, TreeNode<ViewModel>>(this)
|
||||
public onEdgesChange = new EventDispatcher<void, TreeNode<ViewModel>>(this)
|
||||
public onMessage = new EventDispatcher<Message, TreeNode<ViewModel>>(this)
|
||||
public isTree = false
|
||||
|
||||
private cachedPath?: string
|
||||
private cachedChildTopics?: TreeNode[]
|
||||
private cachedChildTopics?: TreeNode<ViewModel>[]
|
||||
private cachedLeafMessageCount?: number
|
||||
private cachedChildTopicCount?: number
|
||||
|
||||
public unconnectedClone() {
|
||||
const node = new TreeNode()
|
||||
const node = new TreeNode<ViewModel>()
|
||||
node.message = this.message
|
||||
node.mqttMessage = this.mqttMessage
|
||||
node.messageHistory = this.messageHistory.clone()
|
||||
@@ -32,7 +33,7 @@ export class TreeNode {
|
||||
return node
|
||||
}
|
||||
|
||||
constructor(sourceEdge?: Edge, message?: Message) {
|
||||
constructor(sourceEdge?: Edge<ViewModel>, message?: Message) {
|
||||
if (sourceEdge) {
|
||||
this.sourceEdge = sourceEdge
|
||||
sourceEdge.target = this
|
||||
@@ -63,7 +64,7 @@ export class TreeNode {
|
||||
return `N${(this.sourceEdge ? this.sourceEdge.hash() : '')}`
|
||||
}
|
||||
|
||||
public firstNode(): TreeNode {
|
||||
public firstNode(): TreeNode<ViewModel> {
|
||||
return this.sourceEdge && this.sourceEdge.source ? this.sourceEdge.source.firstNode() : this
|
||||
}
|
||||
|
||||
@@ -78,11 +79,11 @@ export class TreeNode {
|
||||
return this.cachedPath
|
||||
}
|
||||
|
||||
private previous(): TreeNode | undefined {
|
||||
private previous(): TreeNode<ViewModel> | undefined {
|
||||
return this.sourceEdge ? this.sourceEdge.source || undefined : undefined
|
||||
}
|
||||
|
||||
public addEdge(edge: Edge, emitUpdate: boolean = false) {
|
||||
public addEdge(edge: Edge<ViewModel>, emitUpdate: boolean = false) {
|
||||
this.edges[edge.name] = edge
|
||||
this.edgeArray.push(edge)
|
||||
edge.source = this
|
||||
@@ -92,7 +93,7 @@ export class TreeNode {
|
||||
}
|
||||
}
|
||||
|
||||
public branch(): TreeNode[] {
|
||||
public branch(): TreeNode<ViewModel>[] {
|
||||
const previous = this.previous()
|
||||
if (!previous) {
|
||||
return [this]
|
||||
@@ -101,7 +102,7 @@ export class TreeNode {
|
||||
return previous.branch().concat([this])
|
||||
}
|
||||
|
||||
public updateWithNode(node: TreeNode) {
|
||||
public updateWithNode(node: TreeNode<ViewModel>) {
|
||||
if (node.message) {
|
||||
this.setMessage(node.message)
|
||||
this.onMessage.dispatch(node.message)
|
||||
@@ -119,7 +120,7 @@ export class TreeNode {
|
||||
.reduce((a, b) => a + b, 0) + this.messages
|
||||
}
|
||||
|
||||
return this.cachedLeafMessageCount
|
||||
return this.cachedLeafMessageCount as number
|
||||
}
|
||||
|
||||
public childTopicCount(): number {
|
||||
@@ -129,14 +130,14 @@ export class TreeNode {
|
||||
.reduce((a, b) => a + b, this.edgeArray.length === 0 ? 1 : 0)
|
||||
}
|
||||
|
||||
return this.cachedChildTopicCount
|
||||
return this.cachedChildTopicCount as number
|
||||
}
|
||||
|
||||
public edgeCount(): number {
|
||||
return this.edgeArray.length
|
||||
}
|
||||
|
||||
public childTopics(): TreeNode[] {
|
||||
public childTopics(): TreeNode<ViewModel>[] {
|
||||
if (this.cachedChildTopics === undefined) {
|
||||
const initialValue = this.message && this.message.value ? [this] : []
|
||||
|
||||
@@ -145,16 +146,16 @@ export class TreeNode {
|
||||
.reduce((a, b) => a.concat(b), initialValue)
|
||||
}
|
||||
|
||||
return this.cachedChildTopics
|
||||
return this.cachedChildTopics as TreeNode<ViewModel>[]
|
||||
}
|
||||
|
||||
public findNode (path: String): TreeNode | undefined {
|
||||
public findNode (path: String): TreeNode<ViewModel> | undefined {
|
||||
const topics = path.split('/')
|
||||
|
||||
return this.findChild(topics)
|
||||
}
|
||||
|
||||
private findChild(edges: string[]): TreeNode | undefined {
|
||||
private findChild(edges: string[]): TreeNode<ViewModel> | undefined {
|
||||
if (edges.length === 0) {
|
||||
return this
|
||||
}
|
||||
@@ -167,7 +168,7 @@ export class TreeNode {
|
||||
return nextEdge.target.findChild(edges.slice(1))
|
||||
}
|
||||
|
||||
private mergeEdges(node: TreeNode) {
|
||||
private mergeEdges(node: TreeNode<ViewModel>) {
|
||||
const edgeKeys = Object.keys(node.edges)
|
||||
let edgesDidUpdate = false
|
||||
|
||||
|
||||
@@ -5,11 +5,11 @@ interface HasLength {
|
||||
}
|
||||
|
||||
export abstract class TreeNodeFactory {
|
||||
public static insertNodeAtPosition(edgeNames: string[], node: TreeNode) {
|
||||
let currentNode: TreeNode = new Tree()
|
||||
public static insertNodeAtPosition<ViewModel>(edgeNames: string[], node: TreeNode<ViewModel>) {
|
||||
let currentNode: TreeNode<ViewModel> = new Tree()
|
||||
let edge
|
||||
for (const edgeName of edgeNames) {
|
||||
edge = new Edge(edgeName)
|
||||
edge = new Edge<ViewModel>(edgeName)
|
||||
currentNode.addEdge(edge)
|
||||
currentNode = new TreeNode(edge)
|
||||
edge.target = currentNode
|
||||
@@ -18,15 +18,15 @@ export abstract class TreeNodeFactory {
|
||||
node.sourceEdge!.target = node
|
||||
}
|
||||
|
||||
public static fromEdgesAndValue<T extends HasLength>(edgeNames: string[], value?: T): TreeNode {
|
||||
const node = new TreeNode()
|
||||
public static fromEdgesAndValue<ViewModel, T extends HasLength>(edgeNames: string[], value?: T): TreeNode<ViewModel> {
|
||||
const node = new TreeNode<ViewModel>()
|
||||
node.setMessage({
|
||||
value,
|
||||
length: value ? value.length : 0,
|
||||
received: new Date(),
|
||||
})
|
||||
|
||||
this.insertNodeAtPosition(edgeNames, node)
|
||||
this.insertNodeAtPosition<ViewModel>(edgeNames, node)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user