|
1 | 1 | import { signal, computed, effect } from "@preact/signals"; |
2 | 2 | import { Divider, SignalUpdate } from "../types"; |
3 | 3 |
|
| 4 | +export interface UpdateTreeNode { |
| 5 | + id: string; |
| 6 | + update: SignalUpdate; |
| 7 | + children: UpdateTreeNode[]; |
| 8 | + depth: number; |
| 9 | + hasChildren: boolean; |
| 10 | +} |
| 11 | + |
4 | 12 | const createUpdatesModel = () => { |
5 | 13 | const updates = signal<(SignalUpdate | Divider)[]>([]); |
6 | 14 | const lastUpdateId = signal<number>(0); |
@@ -34,6 +42,62 @@ const createUpdatesModel = () => { |
34 | 42 | return counts; |
35 | 43 | }); |
36 | 44 |
|
| 45 | + const updateTree = computed(() => { |
| 46 | + const buildTree = ( |
| 47 | + updates: (SignalUpdate | Divider)[] |
| 48 | + ): UpdateTreeNode[] => { |
| 49 | + const tree: UpdateTreeNode[] = []; |
| 50 | + const stack: UpdateTreeNode[] = []; |
| 51 | + |
| 52 | + // Process updates in reverse order to show newest first |
| 53 | + const recentUpdates = updates.slice(-100).reverse(); |
| 54 | + |
| 55 | + for (let i = 0; i < recentUpdates.length; i++) { |
| 56 | + const item = recentUpdates[i]; |
| 57 | + |
| 58 | + // Skip dividers for tree building |
| 59 | + if (item.type === "divider") { |
| 60 | + continue; |
| 61 | + } |
| 62 | + |
| 63 | + const update = item as SignalUpdate; |
| 64 | + const depth = update.depth || 0; |
| 65 | + |
| 66 | + // Create a unique ID for this node |
| 67 | + const nodeId = `${update.signalName}-${update.receivedAt}-${i}`; |
| 68 | + |
| 69 | + const node: UpdateTreeNode = { |
| 70 | + id: nodeId, |
| 71 | + update, |
| 72 | + children: [], |
| 73 | + depth, |
| 74 | + hasChildren: false, |
| 75 | + }; |
| 76 | + |
| 77 | + // Find the correct parent based on depth |
| 78 | + while (stack.length > 0 && stack[stack.length - 1].depth >= depth) { |
| 79 | + stack.pop(); |
| 80 | + } |
| 81 | + |
| 82 | + if (stack.length === 0) { |
| 83 | + // This is a root node |
| 84 | + tree.push(node); |
| 85 | + } else { |
| 86 | + // This is a child node |
| 87 | + const parent = stack[stack.length - 1]; |
| 88 | + parent.children.push(node); |
| 89 | + parent.hasChildren = true; |
| 90 | + } |
| 91 | + |
| 92 | + stack.push(node); |
| 93 | + } |
| 94 | + |
| 95 | + return tree; |
| 96 | + }; |
| 97 | + |
| 98 | + return buildTree(updates.value); |
| 99 | + }); |
| 100 | + |
37 | 101 | const clearUpdates = () => { |
38 | 102 | updates.value = []; |
39 | 103 | lastUpdateId.value = 0; |
@@ -72,6 +136,8 @@ const createUpdatesModel = () => { |
72 | 136 |
|
73 | 137 | return { |
74 | 138 | updates, |
| 139 | + updateTree, |
| 140 | + totalUpdates: computed(() => Object.keys(updateTree.value).length), |
75 | 141 | signalCounts, |
76 | 142 | addUpdate, |
77 | 143 | clearUpdates, |
|
0 commit comments