mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-11-01 12:43:56 +08:00
💐 Sync 2026-09-29 21:24:56
This commit is contained in:
1 parent
ac66545478
commit
ed79a5268f
87 files changed
+351
-75
No files matched your search
@@ -431,6 +431,21 @@ function mkEthIcon(size) {
|
||||
return svg;
|
||||
}
|
||||
|
||||
// Marks a device that the WiFi MAC filter lists as blocked. `pending` is the
|
||||
// backend's wifi_block_pending: the device is on the deny list AND associated
|
||||
// on a radio right now, which is proof the running hostapd ACL never got the
|
||||
// block. Saying "blocked" there is the lie this whole change exists to remove,
|
||||
// so that case gets its own wording and colour.
|
||||
function mkWifiBlockBadge(pending) {
|
||||
return E('span', {
|
||||
'class': pending ? 'tc-c-err tc-fw-bold' : 'tc-c-warn tc-fw-bold',
|
||||
'style': 'margin-left:4px;cursor:help;white-space:nowrap',
|
||||
'title': pending
|
||||
? _('On the WiFi deny list but still connected — the block is NOT in effect on the running radio. Install hostapd-utils so blocks apply immediately, or restart WiFi (disconnects every client).')
|
||||
: _('Blocked from WiFi (MAC deny list)')
|
||||
}, pending ? '📵⚠' : '📵');
|
||||
}
|
||||
|
||||
function renderSparkline(history, globalMax, width, height, limitKbit) {
|
||||
if (!history || history.length < 2) return null;
|
||||
var maxVal = globalMax || 1;
|
||||
@@ -1322,6 +1337,15 @@ function buildSummaryTable(rows, sortCol, sortDir, onSort, onSelect, speedMap, d
|
||||
linkBadge = E('span', { 'class': 'tc-c-muted' }, [mkEthIcon(14), document.createTextNode(ethLabel)]);
|
||||
}
|
||||
cellMap.conn_type = E('div', { 'class': 'td tc-center' }, linkBadge);
|
||||
// A WiFi block used to show in the row only as the line-through above,
|
||||
// which lives inside the isWifi branch — so it disappeared from the row
|
||||
// in the two cases that matter most: a block that WORKED (the device
|
||||
// stops associating, the cell falls through to "?" or eth) and a device
|
||||
// blocked while sitting on cable. Mark it in every branch, with a label
|
||||
// and a tooltip rather than a text decoration nobody reads as "blocked".
|
||||
if (r.wifi_blocked) {
|
||||
cellMap.conn_type.appendChild(mkWifiBlockBadge(r.wifi_block_pending));
|
||||
}
|
||||
|
||||
var appBadge;
|
||||
if (r.app) {
|
||||
@@ -2791,9 +2815,18 @@ return view.extend({
|
||||
parts.push(_('Dropped') + ': <b style="color:var(--tc-err)">🚫 '+(Number(dm.packets) || 0)+' pkts / '+fmtBytes(dm.bytes||0)+'</b>');
|
||||
}
|
||||
}
|
||||
var wifiPart = data.wifi_blocked
|
||||
? ' | <b style="color:var(--tc-warn)">📵 ' + _('WiFi blocked') + '</b> ('+escHtml(data.mac||'') + ')'
|
||||
: (data.mac ? ' | <span style="color:var(--tc-faint)">MAC: '+escHtml(data.mac)+'</span>' : '');
|
||||
// Listed but still associated is not a block, so it must not
|
||||
// read as one — that claim is the whole bug.
|
||||
var wifiPart;
|
||||
if (data.wifi_blocked && data.wifi_block_pending) {
|
||||
wifiPart = ' | <b style="color:var(--tc-err)">📵⚠ ' + _('WiFi block NOT in effect') + '</b> — ' +
|
||||
_('on the deny list but still connected; install hostapd-utils or restart WiFi') +
|
||||
' ('+escHtml(data.mac||'') + ')';
|
||||
} else if (data.wifi_blocked) {
|
||||
wifiPart = ' | <b style="color:var(--tc-warn)">📵 ' + _('WiFi blocked') + '</b> ('+escHtml(data.mac||'') + ')';
|
||||
} else {
|
||||
wifiPart = data.mac ? ' | <span style="color:var(--tc-faint)">MAC: '+escHtml(data.mac)+'</span>' : '';
|
||||
}
|
||||
statsDiv.className = 'alert-message ' + (data.blocked ? 'error' : 'info');
|
||||
statsDiv.innerHTML = (data.blocked
|
||||
? '<b>⛔ ' + _('BLOCKED') + '</b> — '+(Number(data.block_packets) || 0)+' pkts, '+fmtBytes(Number(data.block_bytes) || 0)+' ' + _('dropped') + ' | '
|
||||
@@ -2969,6 +3002,7 @@ return view.extend({
|
||||
var shaped = rows.filter(function(r){return (r.shape_kbit||0) > 0;}).length;
|
||||
var blocked = rows.filter(function(r){return r.blocked;}).length;
|
||||
var wifiBlk = rows.filter(function(r){return r.wifi_blocked;}).length;
|
||||
var wifiPending = rows.filter(function(r){return r.wifi_block_pending;}).length;
|
||||
var totalDropPkts = Object.keys(self._dropMap).reduce(function(s, ip) { return s + (self._dropMap[ip].packets||0); }, 0);
|
||||
|
||||
var lnk = 'cursor:pointer;text-decoration:underline;text-decoration-style:dashed';
|
||||
@@ -2987,6 +3021,15 @@ return view.extend({
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Active') + ': '), E('b', {}, String(rows.length))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('Blocked') + ': '), mkFilterVal('blocked', 'var(--tc-err)', String(blocked))]));
|
||||
parts.push(E('span', {}, [document.createTextNode(_('WiFi') + ': '), mkFilterVal('wifi_blocked', 'var(--tc-warn)', String(wifiBlk))]));
|
||||
// Without this the header counts a device as blocked on the strength of
|
||||
// the uci maclist alone — which is how a router can report "WiFi: 2"
|
||||
// while both of those devices are browsing.
|
||||
if (wifiPending > 0) {
|
||||
parts.push(E('span', {
|
||||
'style': 'color:var(--tc-err);font-weight:700;cursor:help',
|
||||
'title': _('Devices on the WiFi deny list that are still connected — those blocks are not in effect on the running radio.')
|
||||
}, '⚠ ' + wifiPending + ' ' + _('not applied')));
|
||||
}
|
||||
if (limited > 0) parts.push(E('span', {}, [document.createTextNode(_('Limited') + ': '), mkFilterVal('limited', 'var(--tc-warn)', '⚡' + limited)]));
|
||||
if (shaped > 0) parts.push(E('span', {}, [document.createTextNode(_('Shaped') + ': '), mkFilterVal('shaped', 'var(--tc-speed)', '🌊' + shaped)]));
|
||||
if (totalDropPkts > 0) {
|
||||
@@ -3130,7 +3173,19 @@ return view.extend({
|
||||
setStatus(statusDiv, 'loading', (action==='block' ? _('Adding to') : _('Removing from')) + ' ' + _('WiFi deny list') + ': ' + name + '…');
|
||||
var fn = action === 'block' ? callMacfilterAdd : callMacfilterRemove;
|
||||
fn(ip).then(function(res) {
|
||||
setStatus(statusDiv, (res && res.ok) ? (action==='block'?'action':'ok') : 'error', (res && res.msg) || '?');
|
||||
// res.ok is now true only when the RUNNING radio was verified to
|
||||
// carry the change, so a config-only write must not paint green.
|
||||
// "ban" is the partial middle state (temporary hostapd ban, no
|
||||
// ACL) and gets the attention colour rather than a hard error.
|
||||
var state;
|
||||
if (res && res.ok) {
|
||||
state = (action === 'block') ? 'action' : 'ok';
|
||||
} else if (res && res.enforcement === 'ban') {
|
||||
state = 'action';
|
||||
} else {
|
||||
state = 'error';
|
||||
}
|
||||
setStatus(statusDiv, state, (res && res.msg) || '?');
|
||||
runQuery();
|
||||
}).catch(function(e) {
|
||||
setStatus(statusDiv, 'error', '✗ '+e.message);
|
||||
|
||||
Reference in new issue
Block a user