Started work on global map

Ylian Saint-Hilaire committed Aug 28, 2017 at 15:57 UTC 95f88d112578098937e9bf81f07c2ce1a5f4dcd5
2 files changed +132 -111
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.0.6-p",
3 + "version": "0.0.6-q",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
views/default.handlebars
+131 -110
@@ -102,29 +102,32 @@
102 <div id=p1 style=display:none>
103 <h1>My Devices</h1>
104 <div style=width:100%;height:24px;background-color:#d3d9d6>
105 - <div class=style7 style=width:84px;height:100%;float:left>&nbsp;</div>
105 <div class=h1 style=height:100%;float:left>&nbsp;</div>
107 - <div class=style14 style=height:100%;float:left>
106 + <div id=devListToolbar class=style14 style=height:100%;float:left>
107 &nbsp;&nbsp;<input type="button" id="SelectAllButton" onclick="selectallButtonFunction();" value="Select All" />&nbsp;
108 <input type="button" id="GroupActionButton" disabled="disabled" value="Group Action" onclick="groupActionFunction();" />&nbsp;
109 <input id="SearchInput" type="text" style=width:120px placeholder=Search onchange="onSearchInputChanged()" onkeyup="onSearchInputChanged()" autocomplete=off onfocus="onSearchFocus(1)" onblur="onSearchFocus(0)" />&nbsp;
110 <input type="checkbox" id="HostnameCheckBox" onclick="onHostnameCheckBox()" /><span title="Show device hostnames">Hostname</span>
111 </div>
112 <div class="auto-style1" style="height: 100%; float: right">
114 - <div style="height: 100%; width: 4px; float: right; background-color: #ffffff"></div>
115 - <div class="h2" style="height: 100%; float: right;">&nbsp;</div>
116 - <div style="float: right">
113 + <div style="height:100%;width:4px;float:right;background-color:#ffffff"></div>
114 + <div class=h2 style="height:100%;float:right">&nbsp;</div>
115 + <div style=float:right>
116 + View
117 + <select id=viewselect onchange=onDeviceViewChange()>
118 + <option value=1>3 wide</option>
119 + <option value=2>List</option>
120 + <option value=3>Map</option>
121 + </select>
122 + </div>
123 + <div style=float:right id=devListToolbarSort>
124 Sort
125 <select id=sortselect onchange=onSortSelectChange()>
126 <option>Mesh</option>
127 <option>Power</option>
128 <option>Device</option>
129 </select>
123 - &nbsp;View
124 - <select id=viewselect onchange=onDeviceViewChange()>
125 - <option value=1>3 wide</option>
126 - <option value=2>List</option>
127 - </select>
130 + &nbsp;
131 </div>
132 </div>
133 </div>
@@ -142,6 +145,7 @@
145 <p></p>
146 </div>
147 <div id="xdevices" style="max-height:calc(100vh - 228px);overflow-y:auto;-webkit-overflow-scrolling:touch"></div>
148 + <div id="xdevicesmap" style="height:500px;width:100%;overflow:hidden"></div>
149 </div>
150 <div id=p2 style=display:none>
151 <h1>My Account</h1>
@@ -596,6 +600,7 @@
600 var features = {{{features}}};
601 var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
602 var amtScanResults = null;
603 + var xxmap = null;
604
605 function startup() {
606 // Guard against other site's top frames (web bugs).
@@ -657,6 +662,13 @@
662 var x = '';
663 for (var c = 1; c < 27; c++) x += "<option value='" + c + "'>Ctrl-" + String.fromCharCode(64 + c) + " (" + c + ")</option>";
664 QH('specialkeylist', x);
665 +
666 + // Setup the map
667 + xxmap = new ol.Map({
668 + target: 'xdevicesmap',
669 + layers: [ new ol.layer.Tile({ source: new ol.source.OSM() }) ],
670 + view: new ol.View({ center: ol.proj.fromLonLat([0, 0]), zoom: 1.8, minZoom: 1.8 })
671 + });
672 }
673
674 function getNodeFromId(id) {
@@ -1134,119 +1146,128 @@
1146 var deviceHeaderId = 0;
1147 var deviceHeaderCount;
1148 var deviceHeaders = {};
1137 -
1149 function updateDevices() {
1150 var r = "", c = 0, current = null, count = 0, displayedMeshes = {}, view = Q('viewselect').value;
1140 - deviceHeaderId = 0;
1141 - deviceHeaderCount = {};
1142 - deviceHeaderTotal = 0;
1143 - deviceHeaders = {};
1144 - deviceHeadersTitles = {};
1145 -
1146 - // Save the list of currently checked nodeid's
1147 - var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
1148 - for (var i in elements) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
1149 -
1150 - // Go thru the list of nodes and display them
1151 - for (var i in nodes) {
1152 - if (nodes[i].v == false) continue;
1153 - var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1154 - if (meshlinks == undefined) continue;
1155 - if (sort == 0) {
1156 - // Mesh header
1157 - if (nodes[i].meshid != current) {
1158 - deviceHeaderSet();
1159 - var extra = '';
1160 - if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; }
1161 - var meshrights = meshlinks.rights;
1162 - if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1163 - r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1164 - r += getMeshActions(mesh2, meshrights);
1165 - r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></td></tr><tr>';
1166 - current = nodes[i].meshid;
1167 - displayedMeshes[current] = 1;
1168 - c = 0;
1169 - }
1170 - } else if (sort == 1) {
1171 - // Power header
1172 - if (nodes[i].pwr !== current) {
1173 - deviceHeaderSet();
1174 - if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1175 - r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></td></tr><tr>';
1176 - current = nodes[i].pwr;
1177 - c = 0;
1151 + QV('xdevices', view < 3);
1152 + QV('xdevicesmap', view == 3);
1153 + QV('devListToolbar', view < 3);
1154 + QV('devListToolbarSort', view < 3);
1155 + if (view == 3) {
1156 + setTimeout( function() { xxmap.updateSize();}, 200);
1157 + // TODO
1158 + } else {
1159 + // 3 wide or list view
1160 + deviceHeaderId = 0;
1161 + deviceHeaderCount = {};
1162 + deviceHeaderTotal = 0;
1163 + deviceHeaders = {};
1164 + deviceHeadersTitles = {};
1165 +
1166 + // Save the list of currently checked nodeid's
1167 + var checkedNodeids = [], elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
1168 + for (var i in elements) { if (elements[i].checked) { checkedNodeids.push(elements[i].value); } }
1169 +
1170 + // Go thru the list of nodes and display them
1171 + for (var i in nodes) {
1172 + if (nodes[i].v == false) continue;
1173 + var mesh2 = meshes[nodes[i].meshid], meshlinks = mesh2.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1174 + if (meshlinks == undefined) continue;
1175 + if (sort == 0) {
1176 + // Mesh header
1177 + if (nodes[i].meshid != current) {
1178 + deviceHeaderSet();
1179 + var extra = '';
1180 + if (meshes[nodes[i].meshid].mtype == 1) { extra = '<span class=devHeaderx>, Intel&reg; AMT only</span>'; }
1181 + var meshrights = meshlinks.rights;
1182 + if ((view == 1) && (current != null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1183 + r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1184 + r += getMeshActions(mesh2, meshrights);
1185 + r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + nodes[i].meshid + '")>' + EscapeHtml(meshes[nodes[i].meshid].name) + '</span>' + extra + '<span id=DevxHeader' + deviceHeaderId + ' class=devHeaderx></span></td></tr><tr>';
1186 + current = nodes[i].meshid;
1187 + displayedMeshes[current] = 1;
1188 + c = 0;
1189 + }
1190 + } else if (sort == 1) {
1191 + // Power header
1192 + if (nodes[i].pwr !== current) {
1193 + deviceHeaderSet();
1194 + if ((view == 1) && (current !== null)) { if (c == 2) { r += '<td><div style=width:301px></div></td>'; } r += '</tr></table>'; }
1195 + r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span>' + PowerStateStr2(nodes[i].pwr) + '</span><span id=DevxHeader' + deviceHeaderId + ' class="devHeaderx"></span></td></tr><tr>';
1196 + current = nodes[i].pwr;
1197 + c = 0;
1198 + }
1199 + } else if (sort == 2) {
1200 + // Device header
1201 + if (current == null) { r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr>'; current = '1'; }
1202 }
1179 - } else if (sort == 2) {
1180 - // Device header
1181 - if (current == null) { r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr>'; current = '1'; }
1182 - }
1183 -
1184 - // Node positioning
1185 - if ((view == 1) && (c > 2)) { r += '</tr><tr>'; c = 0; }
1186 - c++;
1187 - count++;
1203
1189 - var title = EscapeHtml(nodes[i].name);
1190 - if (title.length == 0) { title = '<i>None</i>'; }
1191 - if ((nodes[i].host != undefined) && (nodes[i].host.length > 0)) { title += " / " + EscapeHtml(nodes[i].host); }
1192 - var name = EscapeHtml(nodes[i].name);
1193 - if (showHostnames == true && nodes[i].host != undefined) name = EscapeHtml(nodes[i].host);
1194 - if (name.length == 0) { name = '<i>None</i>'; }
1195 -
1196 - // Node
1197 - var icon = nodes[i].icon;
1198 - var nodestate = NodeStateStr(nodes[i]);
1199 - if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
1200 - if (view == 1) {
1201 - r += '<td><div id=devs style=width:301px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div></td>';
1202 - } else {
1203 - r += '<td><div id=devs style=width:924px;height:20px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:2px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="j' + icon + '" style=width:16px;float:left;margin-top:3px></div><div style=height:100%><div class=g1></div><div class=e2 style=width:858px><div style=float:right;margin-top:1px>' + nodestate + '</div><div style=margin-top:1px title="' + title + '">' + name + '</div></div><div class=g2></div></div></div></div></td></tr><tr>';
1204 + // Node positioning
1205 + if ((view == 1) && (c > 2)) { r += '</tr><tr>'; c = 0; }
1206 + c++;
1207 + count++;
1208 +
1209 + var title = EscapeHtml(nodes[i].name);
1210 + if (title.length == 0) { title = '<i>None</i>'; }
1211 + if ((nodes[i].host != undefined) && (nodes[i].host.length > 0)) { title += " / " + EscapeHtml(nodes[i].host); }
1212 + var name = EscapeHtml(nodes[i].name);
1213 + if (showHostnames == true && nodes[i].host != undefined) name = EscapeHtml(nodes[i].host);
1214 + if (name.length == 0) { name = '<i>None</i>'; }
1215 +
1216 + // Node
1217 + var icon = nodes[i].icon;
1218 + var nodestate = NodeStateStr(nodes[i]);
1219 + if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
1220 + if (view == 1) {
1221 + r += '<td><div id=devs style=width:301px;height:50px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:12px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="i' + icon + '" style=width:50px;float:left></div><div style=height:100%><div class=g1></div><div class=e2><div class=e1 title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div></td>';
1222 + } else {
1223 + r += '<td><div id=devs style=width:924px;height:20px;padding-top:1px;padding-bottom:1px><div style=width:22px;height:50%;float:left;padding-top:2px><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div><div style=height:100%;cursor:pointer onclick=gotoDevice(\'' + nodes[i]._id + '\')><div class="j' + icon + '" style=width:16px;float:left;margin-top:3px></div><div style=height:100%><div class=g1></div><div class=e2 style=width:858px><div style=float:right;margin-top:1px>' + nodestate + '</div><div style=margin-top:1px title="' + title + '">' + name + '</div></div><div class=g2></div></div></div></div></td></tr><tr>';
1224 + }
1225 + deviceHeaderTotal++;
1226 + if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
1227 }
1205 - deviceHeaderTotal++;
1206 - if (typeof deviceHeaderCount[nodes[i].state] == 'undefined') { deviceHeaderCount[nodes[i].state] = 1; } else { deviceHeaderCount[nodes[i].state]++; }
1207 - }
1228
1209 - if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
1210 -
1211 - // Display all empty meshes, we need to do this because users can add devices to these at any time.
1212 - if (sort == 0 && Q('SearchInput').value == '') {
1213 - for (var i in meshes) {
1214 - var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1215 - if (meshlink != undefined) {
1216 - var meshrights = meshlink.rights;
1217 - if (displayedMeshes[mesh._id] == undefined) {
1218 - if (current != '') { r += '</tr></table>'; }
1219 - r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1220 - r += getMeshActions(mesh, meshrights);
1221 - r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
1222 - if (mesh.mtype == 1) {
1223 - r += '<td><div style=padding:10px><i>No Intel&reg; AMT devices in this mesh';
1224 - if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addDeviceToMesh(\"' + mesh._id + '\")>add one</a>'; }
1225 - }
1226 - if (mesh.mtype == 2) {
1227 - r += '<td><div style=padding:10px><i>No devices in this mesh';
1228 - if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addAgentToMesh(\"' + mesh._id + '\")>add one</a>'; }
1229 + if ((view == 1) && (c == 2)) r += '<td><div style=width:301px></div></td>'; // Adds device padding
1230 +
1231 + // Display all empty meshes, we need to do this because users can add devices to these at any time.
1232 + if (sort == 0 && Q('SearchInput').value == '') {
1233 + for (var i in meshes) {
1234 + var mesh = meshes[i], meshlink = mesh.links['user/{{{domain}}}/' + userinfo.name.toLowerCase()];
1235 + if (meshlink != undefined) {
1236 + var meshrights = meshlink.rights;
1237 + if (displayedMeshes[mesh._id] == undefined) {
1238 + if (current != '') { r += '</tr></table>'; }
1239 + r += '<table style=width:100%;padding-top:4px cellpadding=0 cellspacing=0><tr><td colspan=3 class=DevSt><span style=float:right>';
1240 + r += getMeshActions(mesh, meshrights);
1241 + r += '</span><span id=MxMESH style=cursor:pointer onclick=gotoMesh("' + mesh._id + '")>' + EscapeHtml(mesh.name) + '</span></td></tr><tr>';
1242 + if (mesh.mtype == 1) {
1243 + r += '<td><div style=padding:10px><i>No Intel&reg; AMT devices in this mesh';
1244 + if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addDeviceToMesh(\"' + mesh._id + '\")>add one</a>'; }
1245 + }
1246 + if (mesh.mtype == 2) {
1247 + r += '<td><div style=padding:10px><i>No devices in this mesh';
1248 + if ((meshrights & 4) != 0) { r += ', <a style=cursor:pointer onclick=addAgentToMesh(\"' + mesh._id + '\")>add one</a>'; }
1249 + }
1250 + r += '.</i></div></td>';
1251 + current = mesh._id;
1252 + count++;
1253 }
1230 - r += '.</i></div></td>';
1231 - current = mesh._id;
1232 - count++;
1254 }
1255 }
1256 }
1236 - }
1237 - r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
1257 + r += '</tr></table><div style=height:1px></div>'; // This height of 1 div fixes a problem in Linux firefox browsers
1258
1239 - QH('xdevices', r);
1240 - deviceHeaderSet();
1241 - QV('NoNodesPanel', count == 0);
1259 + QH('xdevices', r);
1260 + deviceHeaderSet();
1261 + QV('NoNodesPanel', count == 0);
1262
1243 - // Re-check nodeid's
1244 - var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
1245 - for (var i in elements) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); }
1263 + // Re-check nodeid's
1264 + var elements = document.getElementsByClassName("DeviceCheckbox"), checkcount = 0;
1265 + for (var i in elements) { elements[i].checked = (checkedNodeids.indexOf(elements[i].value) >= 0); }
1266
1247 - for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
1248 - for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
1249 - p1updateInfo();
1267 + for (var i in deviceHeaders) { QH(i, deviceHeaders[i]); }
1268 + for (var i in deviceHeadersTitles) { Q(i).title = deviceHeadersTitles[i]; }
1269 + p1updateInfo();
1270 + }
1271 }
1272
1273 function getMeshActions(mesh, meshrights) {