add disableconnectall to hide buttons in multi desktop view #7636

Signed-off-by: si458 <simonsmith5521@gmail.com>

si458 committed Feb 20, 2026 at 15:41 UTC f3381055feac2017787ac344e00324f1e9f20337
8 files changed +47 -8
meshcentral-config-schema.json
+5
@@ -2491,6 +2491,11 @@
2491 "type": "boolean",
2492 "description": "When set to true, the remote desktop feature is view only.",
2493 "default": "false"
2494 + },
2495 + "disableconnectall": {
2496 + "type": "boolean",
2497 + "description": "When set to true, the 'Connect All','Disconnect All' and 'Auto' buttons are removed from the desktop tab.",
2498 + "default": "false"
2499 }
2500 }
2501 },
meshuser.js
+14 -1
@@ -552,7 +552,20 @@ module.exports.CreateMeshUser = function (parent, db, ws, req, args, domain, use
552
553 // Build server information object
554 const allFeatures = parent.getDomainUserFeatures(domain, user, req);
555 - var serverinfo = { domain: domain.id, name: domain.dns ? domain.dns : parent.certificates.CommonName, mpsname: parent.certificates.AmtMpsName, mpsport: mpsport, mpspass: args.mpspass, port: httpport, emailcheck: ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1) && (user._id.split('/')[2].startsWith('~') == false)), domainauth: (domain.auth == 'sspi'), serverTime: Date.now(), features: allFeatures.features, features2: allFeatures.features2 };
555 + var serverinfo = {
556 + domain: domain.id,
557 + name: domain.dns ? domain.dns : parent.certificates.CommonName,
558 + mpsname: parent.certificates.AmtMpsName,
559 + mpsport: mpsport,
560 + mpspass: args.mpspass,
561 + port: httpport,
562 + emailcheck: ((domain.mailserver != null) && (domain.auth != 'sspi') && (domain.auth != 'ldap') && (args.lanonly != true) && (parent.certificates.CommonName != null) && (parent.certificates.CommonName.indexOf('.') != -1) && (user._id.split('/')[2].startsWith('~') == false)),
563 + domainauth: (domain.auth == 'sspi'),
564 + serverTime: Date.now(),
565 + features: allFeatures.features,
566 + features2: allFeatures.features2,
567 + features3: allFeatures.features3
568 + };
569 serverinfo.languages = parent.renderLanguages;
570 serverinfo.tlshash = Buffer.from(parent.webCertificateFullHashs[domain.id], 'binary').toString('hex').toUpperCase(); // SHA384 of server HTTPS certificate
571 serverinfo.agentCertHash = parent.agentCertificateHashBase64;
views/default-mobile.handlebars
+1
@@ -1320,6 +1320,7 @@
1320 var debugLevel = parseInt('{{{debuglevel}}}');
1321 var features = parseInt('{{{features}}}');
1322 var features2 = parseInt('{{{features2}}}');
1323 + var features3 = parseInt('{{{features3}}}');
1324 var sessionTime = parseInt('{{{sessiontime}}}');
1325 var sessionRefreshTimer = null;
1326 var domain = '{{{domain}}}';
views/default.handlebars
+9 -3
@@ -349,10 +349,12 @@
349 <td id=kvmListToolbar class=style14 style="display:none">
350 <img style="cursor:pointer;margin-top:4px;display:none" title="Collapse All" id="CollapseAllButton2" src="images/icon-collapse.png" width=9 height=11 onclick="cmexpandaction(2)" />
351 <img style="cursor:pointer;margin-top:4px;display:none" title="Expand All" id="ExpandAllButton2" src="images/icon-expand.png" width=9 height=11 onclick="cmexpandaction(1)" />
352 - <input type="button" onclick="connectAllKvmFunction()" value="Connect All" />&nbsp;
353 - <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />&nbsp;
352 + <span id=KvmDesktopButtons>
353 + <input type="button" onclick="connectAllKvmFunction()" value="Connect All" />&nbsp;
354 + <input type="button" onclick="disconnectAllKvmFunction()" value="Disconnect All" />&nbsp;
355 + <label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect" />Auto&nbsp;</label>
356 + </span>
357 <input type="button" onclick="onDevicesScroll(true);" value="Scroll To Top" />&nbsp;
355 - <label><input type="checkbox" id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" title="Automatic connect" />Auto&nbsp;</label>
358 <input type="button" onclick="showMultiDesktopSettings()" value="Settings" />&nbsp;
359 <input id=KvmSearchInput type=search placeholder=Filter onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) autocomplete=off onfocus=onSearchFocus(1) onblur=onSearchFocus(0) />&nbsp;
360 <span id=KvmSearchInputClearButton style="display:none;position:relative"><img src="images/x16.png" type="button" onclick="clearDeviceSearch()" style="position:absolute;cursor:pointer;left:-18px;top:-8px" srcset="images/x32.png 2x" /></span>
@@ -1558,6 +1560,7 @@
1560 var debugLevel = parseInt('{{{debuglevel}}}');
1561 var features = parseInt('{{{features}}}');
1562 var features2 = parseInt('{{{features2}}}');
1563 + var features3 = parseInt('{{{features3}}}');
1564 var sessionTime = parseInt('{{{sessiontime}}}');
1565 var webRelayPort = parseInt('{{{webRelayPort}}}');
1566 var webRelayDns = '{{{webRelayDns}}}';
@@ -1742,6 +1745,9 @@
1745 // Show the modern ui switcher
1746 QV('textnewui', ((features2 & 0x40000000) == 0) ? false : true);
1747
1748 + // Show Connect All and Disconnect All
1749 + QV('KvmDesktopButtons', ((features3 & 0x00000001) == 0) ? true : false);
1750 +
1751 // Connect to the mesh server
1752 meshserver = MeshServerCreateControl(domainUrl);
1753 meshserver.onStateChanged = onStateChanged;
views/default3.handlebars
+12 -3
@@ -489,10 +489,15 @@
489 <i class="fa-solid fa-chevron-up" data-fa-transform="up-6"></i>
490 <i class="fa-solid fa-chevron-down" data-fa-transform="down-6"></i>
491 </span>
492 - <input type="button" class="btn btn-success me-1 btn-sm" onclick="connectAllKvmFunction()" value="Connect All" />
493 - <input type="button" class="btn btn-danger me-1 btn-sm" onclick="disconnectAllKvmFunction()" value="Disconnect All" />
492 + <span id="KvmDesktopButtons">
493 + <input type="button" class="btn btn-success me-1 btn-sm" onclick="connectAllKvmFunction()" value="Connect All" />
494 + <input type="button" class="btn btn-danger me-1 btn-sm" onclick="disconnectAllKvmFunction()" value="Disconnect All" />
495 + <div class="form-check form-check-inline me-1 align-middle" title="Automatic connect">
496 + <input class="form-check-input me-1" type=checkbox id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" />
497 + <label class="form-check-label" for="autoConnectDesktopCheckbox">Auto</label>
498 + </div>
499 + </span>
500 <input type="button" class="btn btn-secondary me-1 btn-sm" onclick="onDevicesScroll(true);" value="Scroll To Top" />
495 - <div class="form-check me-1" title="Automatic connect"><input class="form-check-input me-1" type=checkbox id="autoConnectDesktopCheckbox" onclick="autoConnectDesktops(event)" /><label class="form-check-label" for="autoConnectDesktopCheckbox">Auto</label></div>
501 <input type="button" class="btn btn-primary me-1 btn-sm" onclick="showMultiDesktopSettings()" value="Settings" />
502 <input type="text" id=KvmSearchInput class="form-control-sm me-1" placeholder="Filter" onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) onfocus=onSearchFocus(1) onblur=onSearchFocus(0) title="Filter: user:xxx or u:xxx ip:xxx group:xxx or g:xxx tag:xxx or t: xxx atag:xxx or a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx">
503 <span id=KvmSearchInputClearButton style="display:none;position:relative">
@@ -2075,6 +2080,7 @@
2080 var debugLevel = parseInt('{{{debuglevel}}}');
2081 var features = parseInt('{{{features}}}');
2082 var features2 = parseInt('{{{features2}}}');
2083 + var features3 = parseInt('{{{features3}}}');
2084 var sessionTime = parseInt('{{{sessiontime}}}');
2085 var webRelayPort = parseInt('{{{webRelayPort}}}');
2086 var webRelayDns = '{{{webRelayDns}}}';
@@ -2260,6 +2266,9 @@
2266 // Show the modern ui switcher
2267 QV('textnewui', ((features2 & 0x40000000) == 0) ? false : true);
2268
2269 + // Show Connect All and Disconnect All
2270 + QV('KvmDesktopButtons', ((features3 & 0x00000001) == 0) ? true : false);
2271 +
2272 // Connect to the mesh server
2273 meshserver = MeshServerCreateControl(domainUrl);
2274 meshserver.onStateChanged = onStateChanged;
views/sharing-mobile.handlebars
+1
@@ -766,6 +766,7 @@
766 var xtermResizeTimer = null;
767 var features = parseInt('{{{features}}}');
768 var features2 = parseInt('{{{features2}}}');
769 + var features3 = parseInt('{{{features3}}}');
770 var nodeName = decodeURIComponent('{{{nodeName}}}');
771
772 // Console Message Display Timers
views/sharing.handlebars
+1
@@ -320,6 +320,7 @@
320 }
321 var features = parseInt('{{{features}}}');
322 var features2 = parseInt('{{{features2}}}');
323 + var features3 = parseInt('{{{features3}}}');
324
325 // Load desktop settings
326 var t = null;
webserver.js
+4 -1
@@ -3248,6 +3248,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
3248 serverfeatures: serverFeatures,
3249 features: allFeatures.features,
3250 features2: allFeatures.features2,
3251 + features3: allFeatures.features3,
3252 sessiontime: (args.sessiontime) ? args.sessiontime : 60,
3253 mpspass: args.mpspass,
3254 passRequirements: passRequirements,
@@ -3323,6 +3324,7 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
3324 obj.getDomainUserFeatures = function (domain, user, req) {
3325 var features = 0;
3326 var features2 = 0;
3327 + var features3 = 0;
3328 if (obj.args.wanonly == true) { features += 0x00000001; } // WAN-only mode
3329 if (obj.args.lanonly == true) { features += 0x00000002; } // LAN-only mode
3330 if (obj.args.nousers == true) { features += 0x00000004; } // Single user mode
@@ -3396,7 +3398,8 @@ module.exports.CreateWebServer = function (parent, db, args, certificates, doneF
3398 if (((typeof domain.passwordrequirements != 'object') || (domain.passwordrequirements.duo2factor != false)) && (typeof domain.duo2factor == 'object') && (typeof domain.duo2factor.integrationkey == 'string') && (typeof domain.duo2factor.secretkey == 'string') && (typeof domain.duo2factor.apihostname == 'string')) { features2 += 0x20000000; } // using Duo for 2FA is allowed
3399 if (domain.showmodernuitoggle == true) { features2 += 0x40000000; } // Indicates that the new UI should be shown
3400 if (domain.sitestyle === 3) { features2 |= 0x80000000; } // Indicates that Modern UI is forced (siteStyle = 3)
3399 - return { features: features, features2: features2 };
3401 + if ((typeof domain.desktop == 'object') && (domain.desktop.disableconnectall == true)) { features3 += 0x00000001; } // Disable "Connect All" button when multiple sessions are active on a device
3402 + return { features: features, features2: features2, features3: features3 };
3403 }
3404
3405 function handleRootRequestLogin(req, res, domain, hardwareKeyChallenge, passRequirements) {