add Negate (!) to search/filter #7676
Signed-off-by: si458 <simonsmith5521@gmail.com>
si458 committed
Mar 11, 2026 at 13:01 UTC
c5e47bf58ea5c90ef694ec018a72eda9f8b3e9e4
4 files changed
+47
-34
translate/translate.json
+25
-24
@@ -31190,32 +31190,33 @@
31190
]
31191
},
31192
{
31193
- "bs": "Filter: user:xxx ili u:xxx ip:xxx group:xxx ili g:xxx tag:xxx ili t: xxx atag:xxx ili a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31194
- "ca": "Filtre: usuari:xxx o u:xxx ip:xxx grup:xxx o g:xxx etiqueta:xxx o t: xxx atag:xxx o a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31195
- "cs": "Filtr: uživatel:xxx nebo u:xxx ip:xxx skupina:xxx nebo g:xxx tag:xxx nebo t: xxx atag:xxx nebo a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31196
- "da": "Filter: bruger:xxx eller u:xxx ip:xxx group:xxx eller g:xxx tag:xxx eller t: xxx atag:xxx eller a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: nuupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31197
- "de": "Filter: user:xxx oder u:xxx ip:xxx group:xxx oder g:xxx tag:xxx oder t: xxx atag:xxx oder a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: kein Update wsc:nofirewall wsc:beliebig connectivity:xxx c:xxx",
31198
- "en": "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",
31199
- "es": "Filtro: usuario:xxx o u:xxx ip:xxx grupo:xxx o g:xxx etiqueta:xxx o t: xxx atag:xxx o a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:cualquiera connectivity:xxx c:xxx",
31200
- "fi": "Suodatin: user:xxx tai u:xxx ip:xxx group:xxx tai g:xxx tag:xxx tai t: xxx atag:xxx tai a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31201
- "fr": "Filtre : utilisateur:xxx ou u:xxx ip:xxx groupe:xxx ou g:xxx tag:xxx ou t:xxx atag:xxx ou a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31202
- "hi": "फ़िल्टर: उपयोगकर्ता: xxx या यू: xxx आईपी: xxx समूह: xxx या जी: xxx टैग: xxx या टी: xxx atag: xxx या a: xxx ओएस: xxx amt: xxx desc: xxx wsc: ठीक wsc: noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31203
- "hu": "Szűrőpő: user:xxx vagy u:xxx ip:xxx group:xxx vagy g:xxx tag:xxx vagy t: xxx atag:xxx vagy a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31204
- "it": "Filtro: utente:xxx o u:xxx ip:xxx gruppo:xxx o g:xxx tag:xxx o t: xxx atag:xxx o a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:qualsiasi connectivity:xxx c:xxx",
31205
- "ja": "フィルタ:user:xxxまたはu:xxx ip:xxx group:xxxまたはg:xxx tag:xxxまたはt:xxx atag:xxxまたはa:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31206
- "ko": "필터: 사용자:xxx 또는 u:xxx ip:xxx 그룹:xxx 또는 g:xxx 태그:xxx 또는 t: xxx atag:xxx 또는 a:xxx os:xxx amt:xxx 설명:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31207
- "nl": "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",
31208
- "pl": "Filtr: użytkownik:xxx lub u:xxx ip:xxx grupa:xxx lub g:xxx tag:xxx lub t: xxx atag:xxx lub a:xxx os:xxx amt:xxx opis:xxx wsc:ok wsc:brakav wsc:brakaktualizacji wsc:brakfirewalla wsc:każdy connectivity:xxx c:xxx",
31209
- "pt": "Filtro: user:xxx ou u:xxx ip:xxx group:xxx ou g:xxx tag:xxx ou t: xxx atag:xxx ou a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31210
- "pt-br": "Filtro: usuário: xxx ou u:xxx ip:xxx grupo:xxx ou g:xxx tag:xxx ou t: xxx atag:xxx ou a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31211
- "ru": "Фильтр: 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",
31212
- "sv": "Filter: user:xxx eller u:xxx ip:xxx group:xxx eller g:xxx tag:xxx eller t: xxx atag:xxx eller a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: nupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31213
- "tr": "Filtre: user:xxx veya u:xxx ip:xxx group:xxx veya g:xxx etiketi:xxx veya t: xxx atag:xxx veya a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc: noupdate wsc:nofirewall wsc:herhangi biri connectivity:xxx c:xxx",
31214
- "uk": "Фільтр: user:xxx або u:xxx ip:xxx group:xxx або g:xxx tag:xxx або t: xxx atag:xxx або a:xxx os:xxx amt:xxx desc:xxx wsc:ok wsc:noav wsc:noupdate wsc:nofirewall wsc:any connectivity:xxx c:xxx",
31215
- "zh-chs": "过滤器: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",
31216
- "zh-cht": "過濾器: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",
31193
+ "bs": "Filtrirajte uređaje po imenu ili prefiksu: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefiks sa ! za isključivanje, npr. !tag:abc",
31194
+ "ca": "Filtra dispositius per nom o prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix amb ! per negar, p.ex. !tag:abc",
31195
+ "cs": "Filtrovat zařízení podle jména nebo prefixu: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix ! pro negaci, např. !tag:abc",
31196
+ "da": "Filtrer enheder efter navn eller præfiks: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Brug ! for at udelukke, f.eks. !tag:abc",
31197
+ "de": "Geräte nach Name oder Präfix filtern: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Präfix ! zum Ausschließen, z.B. !tag:abc",
31198
+ "en": "Filter devices by name or prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix with ! to negate, e.g. !tag:abc",
31199
+ "es": "Filtrar dispositivos por nombre o prefijo: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefijo ! para negar, p.ej. !tag:abc",
31200
+ "fi": "Suodata laitteita nimen tai etuliitteen mukaan: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Käytä ! kieltämiseen, esim. !tag:abc",
31201
+ "fr": "Filtrer les appareils par nom ou préfixe : user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Préfixe ! pour exclure, ex. !tag:abc",
31202
+ "hi": "नाम या प्रीफ़िक्स से डिवाइस फ़िल्टर करें: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - ! से नकारें, जैसे !tag:abc",
31203
+ "hu": "Eszközök szűrése név vagy előtag alapján: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - ! előtag a kizáráshoz, pl. !tag:abc",
31204
+ "it": "Filtra dispositivi per nome o prefisso: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefisso ! per negare, es. !tag:abc",
31205
+ "ja": "名前またはプレフィックスでデバイスをフィルタ: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - !を付けると除外, 例: !tag:abc",
31206
+ "ko": "이름 또는 접두사로 장치 필터링: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - !로 제외, 예: !tag:abc",
31207
+ "nl": "Filter apparaten op naam of prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix ! om uit te sluiten, bijv. !tag:abc",
31208
+ "pl": "Filtruj urządzenia po nazwie lub prefiksie: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefiks ! aby wykluczyć, np. !tag:abc",
31209
+ "pt": "Filtrar dispositivos por nome ou prefixo: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefixo ! para negar, ex. !tag:abc",
31210
+ "pt-br": "Filtrar dispositivos por nome ou prefixo: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefixo ! para negar, ex. !tag:abc",
31211
+ "ru": "Фильтр устройств по имени или префиксу: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Префикс ! для исключения, например !tag:abc",
31212
+ "sv": "Filtrera enheter efter namn eller prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix ! för att utesluta, t.ex. !tag:abc",
31213
+ "tr": "Cihazları ada veya önek ile filtrele: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - ! öneki ile hariç tut, örn. !tag:abc",
31214
+ "uk": "Фільтр пристроїв за іменем або префіксом: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Префікс ! для виключення, наприклад !tag:abc",
31215
+ "zh-chs": "按名称或前缀筛选设备:user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - 用 ! 排除,例如 !tag:abc",
31216
+ "zh-cht": "按名稱或前綴篩選裝置:user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - 用 ! 排除,例如 !tag:abc",
31217
"xloc": [
31218
"default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->devListToolbar",
31219
+ "default.handlebars->container->column_l->p1->devListToolbarSpan->1->0->kvmListToolbar",
31220
"default3.handlebars->container->column_l->p1->devListToolbarSpan->devListToolbar",
31221
"default3.handlebars->container->column_l->p1->devListToolbarSpan->kvmListToolbar"
31222
]
views/default-mobile.handlebars
+12
-6
@@ -3104,18 +3104,22 @@
3104
function onSearchInputChanged() {
3105
var x = Q('SearchInput').value.toLowerCase().trim(); putstore('_search', Q('SearchInput').value);
3106
QS('SearchInput')['background-color'] = (x == '') ? '#FFFFFF' : '#FDFFBE';
3107
+ var negate = x.startsWith('!');
3108
+ if (negate) x = x.substring(1);
3109
+ var rawVal = Q('SearchInput').value.trim();
3110
+ if (negate) rawVal = rawVal.substring(1);
3111
var userSearch = null, ipSearch = null, groupSearch = null, tagSearch = null, agentTagSearch = null, wscSearch = null, osSearch = null, amtSearch = null;
3112
if (x.startsWith('user:'.toLowerCase())) { userSearch = x.substring('user:'.length); }
3113
else if (x.startsWith('u:'.toLowerCase())) { userSearch = x.substring('u:'.length); }
3114
else if (x.startsWith('ip:'.toLowerCase())) { ipSearch = x.substring('ip:'.length); }
3115
else if (x.startsWith('group:'.toLowerCase())) { groupSearch = x.substring('group:'.length); }
3116
else if (x.startsWith('g:'.toLowerCase())) { groupSearch = x.substring('g:'.length); }
3113
- else if (x.startsWith('tag:'.toLowerCase())) { tagSearch = Q('SearchInput').value.trim().substring('tag:'.length); }
3114
- else if (x.startsWith('t:'.toLowerCase())) { tagSearch = Q('SearchInput').value.trim().substring('t:'.length); }
3115
- else if (x.startsWith('atag:'.toLowerCase())) { agentTagSearch = Q('SearchInput').value.trim().substring('atag:'.length).toLowerCase(); }
3116
- else if (x.startsWith('a:'.toLowerCase())) { agentTagSearch = Q('SearchInput').value.trim().substring('a:'.length).toLowerCase(); }
3117
- else if (x.startsWith('os:'.toLowerCase())) { osSearch = Q('SearchInput').value.trim().substring('os:'.length).toLowerCase(); }
3118
- else if (x.startsWith('amt:'.toLowerCase())) { amtSearch = Q('SearchInput').value.trim().substring('amt:'.length).toLowerCase(); }
3117
+ else if (x.startsWith('tag:'.toLowerCase())) { tagSearch = rawVal.substring('tag:'.length); }
3118
+ else if (x.startsWith('t:'.toLowerCase())) { tagSearch = rawVal.substring('t:'.length); }
3119
+ else if (x.startsWith('atag:'.toLowerCase())) { agentTagSearch = rawVal.substring('atag:'.length).toLowerCase(); }
3120
+ else if (x.startsWith('a:'.toLowerCase())) { agentTagSearch = rawVal.substring('a:'.length).toLowerCase(); }
3121
+ else if (x.startsWith('os:'.toLowerCase())) { osSearch = rawVal.substring('os:'.length).toLowerCase(); }
3122
+ else if (x.startsWith('amt:'.toLowerCase())) { amtSearch = rawVal.substring('amt:'.length).toLowerCase(); }
3123
else if (x == 'wsc:ok') { wscSearch = 1; }
3124
else if (x == 'wsc:noav') { wscSearch = 2; }
3125
else if (x == 'wsc:noupdate') { wscSearch = 3; }
@@ -3197,6 +3201,8 @@
3201
} catch (ex) { for (var d in nodes) { nodes[d].v = true; } }
3202
}
3203
3204
+ if (negate) { for (var d in nodes) { nodes[d].v = !nodes[d].v; } }
3205
+
3206
// Check power state
3207
var onlineOnly = Q('OnlineCheckBox').checked;
3208
if (onlineOnly) { for (var d in nodes) { if ((nodes[d].conn == null) || (nodes[d].conn == 0)) { nodes[d].v = false; } } }
views/default.handlebars
+5
-2
@@ -329,7 +329,7 @@
329
<input type=button id=SelectAllButton onclick="selectallButtonFunction();" value="Select All" />
330
<input type=button id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />
331
<input type=button id=ScrollToTopButton onclick="onDevicesScroll(true);" style="display:none;margin-right:4px" value="Scroll To Top" />
332
- <input id=SearchInput type=input autocomplete=off 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"/>
332
+ <input id=SearchInput type=input autocomplete=off placeholder=Filter onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) onfocus=onSearchFocus(1) onblur=onSearchFocus(0) title="Filter devices by name or prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix with ! to negate, e.g. !tag:abc"/>
333
<span id=SearchInputClearButton 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>
334
<select id=DevFilterSelect onchange=onOnlineCheckBox(event) title="Device Filter">
335
<option value=0>All</option>
@@ -356,7 +356,7 @@
356
</span>
357
<input type="button" onclick="onDevicesScroll(true);" value="Scroll To Top" />
358
<input type="button" onclick="showMultiDesktopSettings()" value="Settings" />
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) />
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) title="Filter devices by name or prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix with ! to negate, e.g. !tag:abc" />
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>
361
</td>
362
<td id=devMapToolbar class=style14 style="display:none">
@@ -6376,6 +6376,8 @@
6376
}
6377
6378
function getDevicesThatMatchFilter(x) {
6379
+ var negate = x.startsWith('!');
6380
+ if (negate) x = x.substring(1);
6381
var r = [];
6382
var userSearch = null, ipSearch = null, groupSearch = null, tagSearch = null, agentTagSearch = null, wscSearch = null, osSearch = null, amtSearch = null, descSearch = null, connectivitySearch = null;
6383
if (x.startsWith('user:'.toLowerCase())) { userSearch = x.substring('user:'.length); }
@@ -6504,6 +6506,7 @@
6506
} catch (ex) { for (var d in nodes) { r.push(d); } }
6507
}
6508
6509
+ if (negate) { var allIds = []; for (var d in nodes) { allIds.push(d); } return allIds.filter(function(d) { return r.indexOf(d) < 0; }); }
6510
return r;
6511
}
6512
views/default3.handlebars
+5
-2
@@ -452,7 +452,7 @@
452
<input type=button class="btn btn-secondary me-1 btn-sm" id=SelectAllButton onclick="selectallButtonFunction();" value="Select All" />
453
<input type=button class="btn btn-primary me-1 btn-sm" id=GroupActionButton disabled="disabled" value="Group Action" onclick=groupActionFunction() />
454
<input type=button class="btn btn-secondary me-1 btn-sm" id=ScrollToTopButton onclick="onDevicesScroll(true);" value="Scroll To Top" />
455
- <input type="text" id=SearchInput class="form-control-sm me-1 btn-sm" 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">
455
+ <input type="text" id=SearchInput class="form-control-sm me-1 btn-sm" placeholder="Filter" onchange=onDeviceSearchChanged(event) onclick=onDeviceSearchChanged(event) onkeyup=onDeviceSearchChanged(event) onfocus=onSearchFocus(1) onblur=onSearchFocus(0) title="Filter devices by name or prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix with ! to negate, e.g. !tag:abc">
456
<span id=SearchInputClearButton style="display:none;position:relative">
457
<span class="fa-layers fa-fw" role="button" onclick="clearDeviceSearch()" style="position:absolute;left:-25px;top:-15px">
458
<i class="fa-solid fa-circle" style="color:var(--bs-secondary-bg)"></i>
@@ -493,7 +493,7 @@
493
</span>
494
<input type="button" class="btn btn-secondary me-1 btn-sm" onclick="onDevicesScroll(true);" value="Scroll To Top" />
495
<input type="button" class="btn btn-primary me-1 btn-sm" onclick="showMultiDesktopSettings()" value="Settings" />
496
- <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">
496
+ <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 devices by name or prefix: user: (u:) ip: group: (g:) tag: (t:) atag: (a:) os: amt: desc: wsc:ok/noav/noupdate/nofirewall/any connectivity: (c:) - Prefix with ! to negate, e.g. !tag:abc">
497
<span id=KvmSearchInputClearButton style="display:none;position:relative">
498
<span class="fa-layers fa-fw" role="button" onclick="clearDeviceSearch()" style="position:absolute;left:-25px;top:-15px">
499
<i class="fa-solid fa-circle" style="color:var(--bs-secondary-bg)"></i>
@@ -7265,6 +7265,8 @@
7265
}
7266
7267
function getDevicesThatMatchFilter(x) {
7268
+ var negate = x.startsWith('!');
7269
+ if (negate) x = x.substring(1);
7270
var r = [];
7271
var userSearch = null, ipSearch = null, groupSearch = null, tagSearch = null, agentTagSearch = null, wscSearch = null, osSearch = null, amtSearch = null, descSearch = null, connectivitySearch = null;
7272
if (x.startsWith('user:'.toLowerCase())) { userSearch = x.substring('user:'.length); }
@@ -7393,6 +7395,7 @@
7395
} catch (ex) { for (var d in nodes) { r.push(d); } }
7396
}
7397
7398
+ if (negate) { var allIds = []; for (var d in nodes) { allIds.push(d); } return allIds.filter(function(d) { return r.indexOf(d) < 0; }); }
7399
return r;
7400
}
7401