github.com/v2pro/plz@v0.0.0-20221028024117-e5f9aec5b631/witch/webroot/state-viewer.html (about) 1 <script type="text/x-template" id="state-node-template"> 2 <div style="padding-left:18px"> 3 <div @click="callbacks.onNodeClick(node)"> 4 <span class="el-tree-node__expand-icon el-icon-caret-right" 5 :class="{ 'is-leaf': node.isLeaf, expanded: !node.isLeaf && callbacks.isExpanded(node) }"></span> 6 {{ node.label }} 7 <span v-if="node.value">: {{ node.value }}</span> 8 <el-button v-if="node.isDumpVar" size="mini" @click="callbacks.visualize(node,$event)">visualize</el-button> 9 </div> 10 <state-node v-for="child in node.children" :node="child" 11 :callbacks="callbacks" :key="child.id" 12 v-show="!node.isLeaf && callbacks.isExpanded(node)"/> 13 </div> 14 </script> 15 <script type="text/x-template" id="state-viewer-template"> 16 <div> 17 <el-row> 18 <el-col :span="20"> 19 <div v-show="selectedSnapshot === null">No snapshot to show, please click "Poll Current State"</div> 20 <div v-if="selectedSnapshot" style="margin-bottom: 8px;">Snapshot Taken 21 At: {{ selectedSnapshot.timestamp }}</div> 22 <state-node v-for="node in tree.children" :node="node" :callbacks="callbacks" :key="node.id"> 23 </state-node> 24 </el-col> 25 <el-col :span="4" style="pdding-right: 1em; padding-left: 1em;"> 26 <snapshots ref="snapshots" :selectedSnapshot.sync="selectedSnapshot"></snapshots> 27 </el-col> 28 </el-row> 29 <el-dialog 30 :title="dialogTitle" 31 :visible.sync="dialogVisible" 32 :fullscreen="true"> 33 <viz :addrMap="addrMap"></viz> 34 </el-dialog> 35 </div> 36 </script> 37 <script> 38 function Node(options) { 39 this.id = ''; 40 this.label = ''; 41 this.value = null; 42 this.isLeaf = false; 43 this.data = null; 44 this.indention = 0; 45 this.children = []; 46 this.root = null; 47 for (var k in options) { 48 this[k] = options[k]; 49 } 50 } 51 52 Node.prototype.addChild = function (options) { 53 var child = new Node(options); 54 child.root = this.root; 55 child.id = this.id + '>' + options.label; 56 child.indention = this.indention + 18; 57 this.children.push(child); 58 this.root.all_nodes[child.id] = child; 59 return child; 60 }; 61 Node.prototype.addObject = function (object, addrMap) { 62 var isArray = Array.isArray(object); 63 for (var k in object) { 64 var label = k; 65 if (isArray) { 66 label = '[' + label + ']'; 67 } 68 var v = object[k]; 69 if (Array.isArray(v)) { 70 var childNode = this.addChild({label: label, addrMap: addrMap}); 71 childNode.addObject(v, addrMap); 72 } else if (v === null) { 73 this.addChild({label: label, addrMap: addrMap, value: '<null>', isLeaf: true}); 74 break; 75 } else { 76 this.addValue(label, v, addrMap) 77 } 78 } 79 }; 80 Node.prototype.addValue = function (label, v, addrMap) { 81 switch (typeof v) { 82 case 'string': 83 this.addChild({label: label, addrMap: addrMap, value: v, isLeaf: true}); 84 break; 85 case 'boolean': 86 this.addChild({label: label, addrMap: addrMap, value: '' + v, isLeaf: true}); 87 break; 88 case 'number': 89 this.addChild({label: label, addrMap: addrMap, value: '' + v, isLeaf: true}); 90 break; 91 case 'object': 92 if (v.__root__) { 93 var childNode = this.addChild({ 94 label: label, addrMap: v, isDumpVar: true, data: v.__root__ 95 }); 96 childNode.addObject(v.__root__, v); 97 } else if (v.__ptr__) { 98 this.addChild({label: label, addrMap: addrMap, data: v}) 99 } else { 100 var childNode = this.addChild({label: label, addrMap: addrMap}); 101 childNode.addObject(v, addrMap); 102 } 103 break; 104 } 105 }; 106 Vue.component('state-node', { 107 template: '#state-node-template', 108 props: ['node', 'callbacks'] 109 }); 110 Vue.component('state-viewer', { 111 template: '#state-viewer-template', 112 data: function () { 113 return { 114 tree: new Node(), // view model 115 selectedSnapshot: null, 116 callbacks: this, 117 expansion: {}, 118 dialogVisible: false, 119 dialogTitle: '', 120 addrMap: null 121 } 122 }, 123 watch: { 124 selectedSnapshot: function () { 125 this.tree = new Node({id: 'root'}); 126 this.tree.root = this.tree; 127 this.tree.all_nodes = {}; 128 this.tree.addObject(this.selectedSnapshot.data); 129 for (var nodeId in this.expansion) { 130 var node = this.tree.all_nodes[nodeId]; 131 if (node) { 132 this.expandPtr(node); 133 } 134 } 135 } 136 }, 137 methods: { 138 onNodeClick: function (node) { 139 Vue.set(this.expansion, node.id, !this.expansion[node.id]); 140 this.expandPtr(node); 141 }, 142 expandPtr: function (node) { 143 if (node.data && node.data.__ptr__) { 144 var objectAddr = node.data.__ptr__; 145 node.data = null; // avoid reload children 146 var object = node.addrMap[objectAddr]; 147 if ((typeof object) === 'object') { 148 node.addObject(object, node.addrMap); 149 } else { 150 node.addValue('value', object, node.addrMap); 151 } 152 } 153 }, 154 isExpanded: function (node) { 155 return this.expansion[node.id]; 156 }, 157 visualize: function (node, event) { 158 event.stopPropagation(); 159 this.addrMap = node.addrMap; 160 this.dialogTitle = node.label; 161 this.dialogVisible = true; 162 } 163 } 164 }); 165 </script>