More user interface improvements

Ylian Saint-Hilaire committed Sep 18, 2018 at 14:47 UTC e0ee698e2ae505a2e41628f2728291584a96da05
6 files changed +121 -28
package.json
+1 -1
@@ -1,6 +1,6 @@
1 {
2 "name": "meshcentral",
3 - "version": "0.2.0-m",
3 + "version": "0.2.0-o",
4 "keywords": [
5 "Remote Management",
6 "Intel AMT",
public/images/views.png
Binary files /dev/null and b/public/images/views.png differ
public/scripts/agent-desktop-0.0.2.js
+5 -5
@@ -84,7 +84,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
84 }
85
86 obj.send = function (x) {
87 - //console.log("KSend(" + x.length + "): " + rstr2hex(x));
87 + if (obj.debugmode > 1) { console.log("KSend(" + x.length + "): " + rstr2hex(x)); }
88 obj.parent.send(x);
89 }
90
@@ -159,7 +159,7 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
159 }
160
161 obj.ProcessScreenMsg = function (width, height) {
162 - if (obj.debugmode == 1) { console.log("ScreenSize: " + width + " x " + height); }
162 + if (obj.debugmode > 0) { console.log("ScreenSize: " + width + " x " + height); }
163 obj.Canvas.setTransform(1, 0, 0, 1, 0, 0);
164 obj.rotation = 0;
165 obj.FirstDraw = true;
@@ -178,19 +178,19 @@ var CreateAgentRemoteDesktop = function (canvasid, scrolldiv) {
178 }
179
180 obj.ProcessDataEx = function (str) {
181 + if (obj.debugmode > 1) { console.log("KRecv(" + str.length + "): " + rstr2hex(str.substring(0, Math.min(str.length, 40)))); }
182 if (str.length < 4) return;
183 var cmdmsg = null, X = 0, Y = 0, command = ReadShort(str, 0), cmdsize = ReadShort(str, 2);
183 - if ((cmdsize != str.length) && (obj.debugmode == 1)) { console.log(cmdsize, str.length, cmdsize == str.length); }
184 + if ((cmdsize != str.length) && (obj.debugmode > 0)) { console.log(cmdsize, str.length, cmdsize == str.length); }
185 if (command >= 18) { console.error("Invalid KVM command " + command + " of size " + cmdsize); console.log("Invalid KVM data", str.length, str, rstr2hex(str)); return; }
186 if (cmdsize > str.length) { console.error("KVM invalid command size", cmdsize, str.length); return; }
187 //meshOnDebug("KVM Command: " + command + " Len:" + cmdsize);
187 - //if (obj.debugmode == 1) { console.log("KVM Command: " + command + " Len:" + cmdsize); }
188
189 if (command == 3 || command == 4 || command == 7) {
190 cmdmsg = str.substring(4, cmdsize);
191 X = ((cmdmsg.charCodeAt(0) & 0xFF) << 8) + (cmdmsg.charCodeAt(1) & 0xFF);
192 Y = ((cmdmsg.charCodeAt(2) & 0xFF) << 8) + (cmdmsg.charCodeAt(3) & 0xFF);
193 - if (obj.debugmode == 1) { console.log("CMD" + command + " at X=" + X + " Y=" + Y); }
193 + if (obj.debugmode > 0) { console.log("CMD" + command + " at X=" + X + " Y=" + Y); }
194 }
195
196 switch (command) {
public/scripts/amt-terminal-0.0.2.js
+2 -1
@@ -14,10 +14,10 @@ var CreateAmtRemoteTerminal = function (divid) {
14 obj.terminalEmulation = 1;
15 // ###END###{Terminal-Enumation-All}
16 obj.fxEmulation = 0;
17 + obj.lineFeed = '\r\n';
18
19 obj.width = 80; // 80 or 100
20 obj.height = 25; // 25 or 30
20 - obj.lineFeed = '\r\n';
21
22 var _Terminal_CellHeight = 21;
23 var _Terminal_CellWidth = 13;
@@ -414,6 +414,7 @@ var CreateAmtRemoteTerminal = function (divid) {
414 _TermMoveUp(1);
415 _termy = (obj.height - 1);
416 }
417 + if (obj.lineFeed = '\n') { _termx = 0; } // *** If we are in Linux mode, \n will also return the cursor to the first col
418 break;
419 case '\r': // Carriage Return
420 _termx = 0;
public/styles/style.css
+54 -1
@@ -447,7 +447,6 @@ a {
447 .e2 {
448 float: left;
449 height: 100%;
450 - width: 201px;
450 background-color: #c9c9c9;
451 }
452
@@ -604,3 +603,57 @@ a {
603 padding-top: 4px;
604 padding-bottom: 4px;
605 }
606 +
607 +.viewSelector {
608 + width:32px;
609 + height:32px;
610 + background-color:#DDD;
611 + border-radius:3px;
612 + float:left;
613 + margin-left:5px;
614 + cursor: pointer;
615 + opacity: 0.3;
616 +}
617 +
618 +.viewSelectorSel {
619 + background-color:#BBB;
620 + opacity: 0.8;
621 +}
622 +
623 + .viewSelector:hover {
624 + opacity: 0.5;
625 + background-color:#AAA;
626 + }
627 +
628 +
629 +.viewSelector1 {
630 + margin-left:2px;
631 + margin-top:2px;
632 + background: url(../images/views.png) -0px 0px;
633 + height: 28px;
634 + width: 28px;
635 +}
636 +
637 +.viewSelector2 {
638 + margin-left:2px;
639 + margin-top:2px;
640 + background: url(../images/views.png) -28px 0px;
641 + height: 28px;
642 + width: 28px;
643 +}
644 +
645 +.viewSelector3 {
646 + margin-left:2px;
647 + margin-top:2px;
648 + background: url(../images/views.png) -56px 0px;
649 + height: 28px;
650 + width: 28px;
651 +}
652 +
653 +.viewSelector4 {
654 + margin-left:2px;
655 + margin-top:2px;
656 + background: url(../images/views.png) -84px 0px;
657 + height: 28px;
658 + width: 28px;
659 +}
\ No newline at end of file
views/default.handlebars
+59 -20
@@ -143,7 +143,12 @@
143 <div id=p0message style=margin:50px;text-align:center>Server disconnected, <href onclick=reload() style=cursor:pointer><u>click to reconnect</u></href>.</div>
144 </div>
145 <div id=p1 style=display:none>
146 - <h1>My Devices</h1>
146 + <div style="float:right" id="devListToolbarViewIcons">
147 + <div id=devViewButton1 class="viewSelector" onclick=onDeviceViewChange(1) title="Columns"><div class="viewSelector1"></div></div>
148 + <div id=devViewButton2 class=viewSelector onclick=onDeviceViewChange(2) title="List"><div class="viewSelector2"></div></div>
149 + <div id=devViewButton3 class=viewSelector onclick=onDeviceViewChange(3) title="Desktops"><div class="viewSelector3"></div></div>
150 + <div id=devViewButton4 class=viewSelector onclick=onDeviceViewChange(4) title="Map"><div class="viewSelector4"></div></div>
151 + </div><div><h1>My Devices</h1></div>
152 <div style=width:100%;height:24px;background-color:#d3d9d6>
153 <div class=h1 style=height:100%;float:left>&nbsp;</div>
154 <div id=devListToolbar class=style14 style=height:100%;float:left>
@@ -155,7 +160,7 @@
160 <div id=kvmListToolbar class=style14 style=height:100%;float:left>
161 &nbsp;&nbsp;<input type="button" onclick="connectAllKvmFunction()" value="Connect All" />&nbsp;
162 <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />&nbsp;
158 - <input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" />AutoConnect&nbsp;
163 + <input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect" />Auto&nbsp;
164 <input type="button" onclick="showMultiDesktopSettings()" value="Settings" />&nbsp;
165 </div>
166 <div id=devMapToolbar class=style14 style=height:100%;float:left>
@@ -163,10 +168,10 @@
168 <input type=button value=Search title="Search for location" onclick=getSearchLocation() />
169 <input type=button id=refreshmap title="Reset map view" value=Reset style=margin-left:5px onclick=refreshMap(false,true) />
170 </div>
166 - <div class="auto-style1" style="height: 100%; float: right">
171 + <div class="auto-style1" style=height:100%;float:right>
172 <div style="height:100%;width:4px;float:right;background-color:#ffffff"></div>
173 <div class=h2 style="height:100%;float:right">&nbsp;</div>
169 - <div style=float:right id=devListToolbarView>
174 + <div style="float:right;display:none" id=devListToolbarView>
175 View
176 <select id=viewselect onchange=onDeviceViewChange()>
177 <option value=1>Columns</option>
@@ -327,7 +332,7 @@
332 <input type=submit id=p5fileCatchAllSubmit style="display:none" />
333 </form>
334 -->
330 - <div id="p5PublicShare" style="display:none;width:100%;padding:4px;overflow:auto;-webkit-user-select:none;background-color:lightsteelblue">This files is shared publically, click "link" to get public url.</div>
335 + <div id="p5PublicShare" style="display:none;width:100%;overflow:auto;-webkit-user-select:none;background-color:lightsteelblue"><div style="padding:4px">This files is shared publically, click "link" to get public url.</div></div>
336 <div id="bigok" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&checkmark;</b></div>
337 <div id="bigfail" style="width:256px;overflow:hidden;position:absolute;left:337px;top:20px;text-align:center;font-size:1600%;color:#AAAAAA;display:none"><b>&#10007;</b></div>
338 <span id="p5files"></span>
@@ -474,10 +479,13 @@
479 <tr>
480 <td style="padding-top:2px;padding-bottom:2px;background:#C0C0C0">
481 <div style="float:right;text-align:right">
477 - <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">&nbsp;
478 - <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">&nbsp;&nbsp;
479 - <select id="specialkeylist" onkeypress="return false"></select>
480 - <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />&nbsp;
482 + <span id="terminalSettingsButtons" style="display:none">
483 + <input id="id_tcrbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="CR+LF" title="Toggle what the return key will send" onclick="termToggleCr()">
484 + <input id="id_tfxkeysbutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Intel (F10 = ESC+[OM)" title="Toggle F1 to F10 keys emulation type" onclick="termToggleFx()">
485 + <input id="id_ttypebutton" type="button" onkeypress="return false" onkeydown="return false" class="bottombutton" value="Extended Ascii" title="Toggle terminal emulation type" onclick="termToggleType()">
486 + </span>
487 + <select id="specialkeylist" onkeypress="return false" style="margin-left:5px"></select>
488 + <input id="specialkeylistinput" type="button" onkeypress="return false" class="bottombutton" value="Send" title="Send the selected special key" onclick="sendSpecialKey()" />
489 </div>
490 <div>
491 &nbsp;
@@ -807,7 +815,7 @@
815 var multiDesktopFilter = null;
816 var serverPublicNamePort = "{{{serverDnsName}}}:{{{serverPublicPort}}}";
817 var amtScanResults = null;
810 - var debugmode = false;
818 + var debugmode = 0;
819 var clickOnce = (((features & 256) != 0) && detectClickOnce());
820 var attemptWebRTC = ((features & 128) != 0);
821 var webPageFullScreen = getstore('webPageFullScreen', true);
@@ -826,7 +834,7 @@
834
835 // Check if we are in debug mode
836 args = parseUriArgs();
829 - debugmode = (args.debug == 1);
837 + debugmode = args.debug;
838 if (args.webrtc != null) { attemptWebRTC = (args.webrtc == 1); }
839 QV('p13AutoConnect', debugmode); // Files
840 QV('autoconnectbutton2', debugmode); // Terminal
@@ -874,6 +882,9 @@
882 // Display the page devices
883 onSortSelectChange();
884 onSearchInputChanged();
885 + for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
886 + Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
887 +
888
889 // Setup upload drag & drop
890 Q('p5filetable').addEventListener("drop", p5fileDragDrop, false);
@@ -1464,7 +1475,10 @@
1475 return;
1476 }
1477
1467 - function onDeviceViewChange() {
1478 + function onDeviceViewChange(i) {
1479 + if (i != null) { Q('viewselect').value = i; }
1480 + for (var j = 1; j < 5; j++) { Q('devViewButton' + j).classList.remove('viewSelectorSel'); }
1481 + Q('devViewButton' + Q('viewselect').value).classList.add('viewSelectorSel');
1482 putstore("deviceView", Q('viewselect').value);
1483 putstore("viewsize", Q('sizeselect').value);
1484 updateDevices();
@@ -1572,7 +1586,8 @@
1586 QV('devMapToolbar', view == 4);
1587 QV('devListToolbarSize', view == 3);
1588 QV('NoMeshesPanel', meshcount == 0);
1575 - QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
1589 + //QV('devListToolbarView', (meshcount != 0) && (nodes.length > 0));
1590 + QV('devListToolbarViewIcons', (meshcount != 0) && (nodes.length > 0));
1591 QV('devListToolbarSort', (meshcount != 0) && (nodes.length > 0) && (view < 4));
1592 if ((meshcount == 0) || (nodes.length == 0)) { view = 1; sort = 0; }
1593 if (view == 4) {
@@ -1647,7 +1662,9 @@
1662 var nodestate = NodeStateStr(nodes[i]);
1663 if ((!nodes[i].conn) || (nodes[i].conn == 0)) { icon += ' gray'; }
1664 if (view == 1) {
1650 - r += '<div id=devs style=display:inline-block;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>';
1665 + var xw = Math.floor(Q('xdevices').clientWidth / 301);
1666 + xw = 301 + Math.floor((Q('xdevices').clientWidth - (xw * 301)) / xw);
1667 + r += '<div id=devs style=display:inline-block;width:' + xw + 'px;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 style=width:' + (xw - 100) + 'px title="' + title + '">' + name + '</div><div>' + nodestate + '</div></div><div class=g2></div></div></div></div>';
1668 } else if (view == 2) {
1669 r += '<tr><td><div id=devs class=bar18 style=height:18px;width:100%;font-size:medium>';
1670 r += '<div style=width:22px;float:left;background-color:white><input class="' + nodes[i].meshid + ' DeviceCheckbox" onclick=p1updateInfo() value=devid_' + nodes[i]._id + ' type=checkbox></div>';
@@ -1749,7 +1766,13 @@
1766
1767 // Take care of KVM surfaces in desktop view mode
1768 if (view == 3) {
1752 - var vsize = [{x:180,y:101}, {x:302,y:169}, {x:454,y:255}][Q('sizeselect').selectedIndex];
1769 + // Figure out and adjust the size to fill the width of the div
1770 + var vsize = [{ x: 180, y: 101 }, { x: 302, y: 169 }, { x: 454, y: 255 }][Q('sizeselect').selectedIndex];
1771 + var realw = vsize.x + 2, tw = Q('xdevices').clientWidth - 30, xw = Math.floor(tw / realw);
1772 + xw = realw + Math.floor((tw - (xw * realw)) / xw);
1773 + vsize.y = vsize.y * (xw / vsize.x);
1774 + vsize.x = xw;
1775 +
1776 for (var i in multiDesktop) { multiDesktop[i].xxdelete = true; }
1777 for (var i in kvmDivs) {
1778 var id = kvmDivs[i], shortid = id.split('/')[2], desk = multiDesktop[id];
@@ -2045,7 +2068,7 @@
2068 x += "<div id=agins_windows>To add a new computer to mesh " + EscapeHtml(mesh.name) + ", download the mesh agent and install it the computer to manage. This agent has server and mesh information embedded within it.<br /><br />";
2069 x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=3&meshid=' + meshid.split('/')[2] + '" target="_blank" title="32bit version of the MeshAgent">Windows (.exe)</a>');
2070 x += addHtmlValue('Mesh Agent', '<a href="meshagents?id=4&meshid=' + meshid.split('/')[2] + '" target="_blank" title="64bit version of the MeshAgent">Windows x64 (.exe)</a>');
2048 - if (debugmode == true) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
2071 + if (debugmode > 0) { x += addHtmlValue('Settings File', '<a href="meshsettings?id=' + meshid.split('/')[2] + '" target="_blank">' + EscapeHtml(mesh.name) + ' settings (.msh)</a>'); }
2072 x += "</div>";
2073
2074 // Linux agent install
@@ -3845,6 +3868,7 @@
3868 var hwonline = ((terminalNode.conn & 6) != 0); // If CIRA (2) or AMT (4) connected, enable hardware terminal
3869 QE('connectbutton2h', hwonline);
3870
3871 + // Key buttons
3872 QE('ctrlcbutton', termState);
3873 QE('ctrlxbutton', termState);
3874 QE('escbutton', termState);
@@ -3852,6 +3876,14 @@
3876 QE('pastebutton', termState);
3877 QE('specialkeylist', termState);
3878 QE('specialkeylistinput', termState);
3879 +
3880 + // Terminal settings
3881 + QV('terminalSettingsButtons', (terminal) && (terminal.contype == 2));
3882 + if (terminal) {
3883 + Q('id_ttypebutton').value = terminalEmulations[terminal.m.terminalEmulation];
3884 + Q('id_tfxkeysbutton').value = fxEmulations[terminal.m.fxEmulation];
3885 + Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n')?'CR+LF':'LF';
3886 + }
3887 }
3888
3889 // Called when the terminal state changes
@@ -3903,6 +3935,7 @@
3935 terminal.Start(terminalNode._id);
3936 terminal.contype = 1;
3937 terminal.m.terminalEmulation = 0;
3938 + terminal.m.fxEmulation = 0;
3939 Q('id_ttypebutton').value = terminalEmulations[0];
3940 }
3941 } else {
@@ -3929,6 +3962,12 @@
3962 Q('id_tfxkeysbutton').blur(); // Deselect the connect button so the button does not get key presses.
3963 }
3964
3965 + function termToggleCr() {
3966 + if (!terminal || xxdialogMode) return;
3967 + if (terminal.m.lineFeed == '\n') { terminal.m.lineFeed = '\r\n'; } else { terminal.m.lineFeed = '\n'; }
3968 + Q('id_tcrbutton').value = (terminal.m.lineFeed == '\r\n') ? 'CR+LF' : 'LF';
3969 + }
3970 +
3971 function termSendKey(key, id) {
3972 if (!terminal || xxdialogMode) return;
3973 terminal.m.TermSendKey(key);
@@ -4514,7 +4553,7 @@
4553 if (consoleNode.consoleText == null) { consoleNode.consoleText = ''; }
4554 if (samenode == false) {
4555 QH('p15agentConsoleText', consoleNode.consoleText);
4517 - Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
4556 + Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
4557 }
4558 var online = ((consoleNode.conn & 1) != 0)?true:false;
4559 QH('p15statetext', online?"Mesh Agent is online":"Mesh Agent is offline");
@@ -4541,7 +4580,7 @@
4580 var v = Q('p15consoleText').value, t = '<div style=color:green>&gt; ' + EscapeHtml(Q('p15consoleText').value) + '<br/></div>';
4581 Q('p15agentConsoleText').innerHTML += t;
4582 consoleNode.consoleText += t;
4544 - Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
4583 + Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
4584 Q('p15consoleText').value = '';
4585
4586 // Send the command to the mesh agent
@@ -4563,7 +4602,7 @@
4602 if (node.consoleText == null) { node.consoleText = data; } else { node.consoleText += data; }
4603 if (consoleNode == node) {
4604 Q('p15agentConsoleText').innerHTML += data;
4566 - Q('p15agentConsole').scrollTop = Q('p15agentConsole').scrollHeight;
4605 + Q('p15agentConsoleText').scrollTop = Q('p15agentConsoleText').scrollHeight;
4606 }
4607 }
4608
@@ -5879,7 +5918,7 @@
5918 if (((b & 8) || x) && f) f(x, t);
5919 }
5920
5882 - function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px"); deskAdjust(); deskAdjust(); drawDeviceTimeline(); }
5921 + function center() { QS('dialog').left = ((((getDocWidth() - 400) / 2)) + "px"); deskAdjust(); deskAdjust(); drawDeviceTimeline(); updateDevicesEx(); }
5922 function messagebox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t, 1); }
5923 function statusbox(t, m) { QH('id_dialogMessage', m); setDialogMode(1, t); }
5924 function getDocWidth() { if (window.innerWidth) return window.innerWidth; if (document.documentElement && document.documentElement.clientWidth && document.documentElement.clientWidth != 0) return document.documentElement.clientWidth; return document.getElementsByTagName('body')[0].clientWidth; }