mirror of
https://github.com/caiwx86/small-packages.git
synced 2026-09-14 20:34:11 +08:00
673 lines
22 KiB
HTML
673 lines
22 KiB
HTML
<%
|
|
local dsp = require "luci.dispatcher"
|
|
local nfs = require "nixio.fs"
|
|
local has_app_filter = nfs.access("/etc/config/appfilter")
|
|
local has_access_control = nfs.access("/etc/config/macfilter")
|
|
local has_record = nfs.access("/etc/config/fwx_record")
|
|
%>
|
|
<link rel="stylesheet" href="<%=resource%>/oaf/css/common.css">
|
|
<script src="<%=resource%>/oaf/jquery-3.7.1.min.js"></script>
|
|
<script src="<%=resource%>/oaf/common.js"></script>
|
|
|
|
<style>
|
|
.oaf-whitelist-tip {
|
|
margin: 8px 0 14px;
|
|
padding: 10px 14px;
|
|
border: 1px solid var(--border-color-low, #e5e7eb);
|
|
border-radius: 6px;
|
|
background: var(--background-color-low, #f5f5f5);
|
|
color: var(--text-color-medium, #6b7280);
|
|
font-size: 13px;
|
|
line-height: 1.6;
|
|
}
|
|
|
|
.oaf-whitelist-tabs {
|
|
display: flex;
|
|
list-style: none;
|
|
gap: 0;
|
|
padding: 0;
|
|
margin: 10px 0 15px;
|
|
border-bottom: 1px solid var(--border-color-medium, #d1d5db);
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.oaf-whitelist-tab {
|
|
padding: 3px 16px;
|
|
border: 1px solid var(--border-color-medium, #d1d5db) !important;
|
|
border-bottom: none !important;
|
|
border-radius: 5px 5px 0 0;
|
|
margin-right: 6px;
|
|
background: var(--background-color-low, #f5f5f5) !important;
|
|
color: var(--text-color-medium, #6b7280) !important;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
line-height: 1.6;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.oaf-whitelist-tab:hover {
|
|
background: var(--background-color-medium, #eee) !important;
|
|
color: var(--text-color-high, #333) !important;
|
|
}
|
|
|
|
.oaf-whitelist-tab.active {
|
|
background: var(--background-color-high, #fff) !important;
|
|
color: var(--text-color-high, #333) !important;
|
|
font-weight: bold;
|
|
}
|
|
|
|
.oaf-whitelist-panel {
|
|
display: none;
|
|
}
|
|
|
|
.oaf-whitelist-panel.active {
|
|
display: block;
|
|
}
|
|
|
|
.oaf-whitelist-panel-header {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 12px;
|
|
margin-bottom: 20px;
|
|
}
|
|
|
|
.oaf-whitelist-panel-header h3 {
|
|
min-width: 0;
|
|
}
|
|
|
|
.oaf-whitelist-table-wrap {
|
|
width: 100%;
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.oaf-whitelist-table {
|
|
width: 100%;
|
|
min-width: 680px;
|
|
}
|
|
|
|
.oaf-whitelist-add-btn {
|
|
display: inline-flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
flex: 0 0 auto;
|
|
width: auto;
|
|
min-width: max-content;
|
|
white-space: nowrap;
|
|
line-height: 1.4;
|
|
margin: 0;
|
|
padding: 9px 18px;
|
|
background-color: #2885e8;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
}
|
|
|
|
.oaf-whitelist-add-btn:hover {
|
|
background-color: #1e6bb8;
|
|
}
|
|
|
|
.oaf-whitelist-delete-btn {
|
|
padding: 5px 12px;
|
|
background-color: #e5484d;
|
|
color: #fff;
|
|
border: none;
|
|
border-radius: 3px;
|
|
cursor: pointer;
|
|
font-size: 13px;
|
|
}
|
|
|
|
.oaf-whitelist-delete-btn:hover {
|
|
background-color: #c9373c;
|
|
}
|
|
|
|
.oaf-whitelist-modal,
|
|
.oaf-whitelist-message {
|
|
display: none;
|
|
position: fixed;
|
|
inset: 0;
|
|
background-color: rgba(0, 0, 0, 0.5);
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
.oaf-whitelist-modal {
|
|
z-index: 10000;
|
|
}
|
|
|
|
.oaf-whitelist-modal-content {
|
|
width: calc(100vw - 32px);
|
|
max-width: 700px;
|
|
max-height: calc(100vh - 64px);
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow: hidden;
|
|
box-sizing: border-box;
|
|
border-radius: 8px;
|
|
border: 1px solid var(--border-color-low, #d1d5db);
|
|
background: var(--background-color-high, #fff);
|
|
color: var(--text-color-high, #1f2937);
|
|
box-shadow: 0 12px 32px rgba(0, 0, 0, 0.22);
|
|
}
|
|
|
|
.oaf-whitelist-modal-header {
|
|
padding: 20px 24px 14px;
|
|
border-bottom: 1px solid var(--border-color-low, #d1d5db);
|
|
color: var(--text-color-high, #1f2937);
|
|
font-size: 20px;
|
|
font-weight: 600;
|
|
}
|
|
|
|
.oaf-whitelist-selection-toolbar {
|
|
display: flex;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
gap: 12px;
|
|
padding: 16px 24px 10px;
|
|
}
|
|
|
|
.oaf-whitelist-selection-stat {
|
|
color: var(--text-color-medium, #6b7280);
|
|
font-size: 13px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.oaf-whitelist-user-list {
|
|
min-height: 180px;
|
|
margin: 0 24px;
|
|
overflow-y: auto;
|
|
border: 1px solid var(--border-color-low, #d1d5db);
|
|
border-radius: 4px;
|
|
background: var(--background-color-low, #f5f5f5);
|
|
}
|
|
|
|
.oaf-whitelist-user-item {
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 12px;
|
|
border-bottom: 1px solid var(--border-color-low, #d1d5db);
|
|
background: var(--background-color-high, #fff);
|
|
color: var(--text-color-high, #1f2937);
|
|
cursor: pointer;
|
|
}
|
|
|
|
.oaf-whitelist-user-item:last-child {
|
|
border-bottom: none;
|
|
}
|
|
|
|
.oaf-whitelist-user-item:hover {
|
|
background: var(--background-color-medium, #eee);
|
|
}
|
|
|
|
.oaf-whitelist-user-item .oaf-check-item {
|
|
width: 100%;
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 0;
|
|
}
|
|
|
|
.oaf-whitelist-user-item .oaf-check-item > input[type="checkbox"] {
|
|
margin: 0 12px 0 0;
|
|
flex: 0 0 auto;
|
|
}
|
|
|
|
.oaf-whitelist-user-item .oaf-check-item > label {
|
|
display: flex;
|
|
align-items: center;
|
|
flex: 1;
|
|
min-width: 0;
|
|
margin: 0;
|
|
line-height: 1.4;
|
|
}
|
|
|
|
.oaf-whitelist-user-mac {
|
|
color: var(--text-color-high, #1f2937);
|
|
font-weight: 600;
|
|
overflow: hidden;
|
|
text-overflow: ellipsis;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
.oaf-whitelist-empty-state {
|
|
padding: 40px;
|
|
color: var(--text-color-medium, #6b7280);
|
|
text-align: center;
|
|
}
|
|
|
|
.oaf-whitelist-modal-buttons {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
gap: 10px;
|
|
padding: 16px 24px;
|
|
border-top: 1px solid var(--border-color-low, #d1d5db);
|
|
}
|
|
|
|
.oaf-whitelist-modal-btn {
|
|
min-width: 84px;
|
|
padding: 8px 20px;
|
|
border-radius: 4px;
|
|
cursor: pointer;
|
|
font-size: 14px;
|
|
line-height: 20px;
|
|
}
|
|
|
|
.oaf-whitelist-modal-btn-primary {
|
|
border: none;
|
|
background-color: #2885e8;
|
|
color: #fff;
|
|
}
|
|
|
|
.oaf-whitelist-modal-btn-secondary {
|
|
border: 1px solid var(--border-color-medium, #d1d5db);
|
|
background: transparent;
|
|
color: var(--text-color-high, #1f2937);
|
|
}
|
|
|
|
[data-darkmode="true"] .oaf-whitelist-user-item:hover {
|
|
background: var(--background-color-medium, rgba(255, 255, 255, 0.08));
|
|
}
|
|
|
|
.oaf-whitelist-message {
|
|
z-index: 10001;
|
|
}
|
|
|
|
.oaf-whitelist-message-content {
|
|
padding: 20px 30px;
|
|
border-radius: 5px;
|
|
background-color: rgba(0, 0, 0, 0.75);
|
|
color: #fff;
|
|
text-align: center;
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
.oaf-whitelist-tabs {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
.oaf-whitelist-tab {
|
|
min-width: max-content;
|
|
}
|
|
|
|
.oaf-whitelist-panel-header,
|
|
.oaf-whitelist-selection-toolbar {
|
|
align-items: stretch;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.oaf-whitelist-modal-content {
|
|
width: calc(100vw - 20px);
|
|
max-height: calc(100vh - 24px);
|
|
}
|
|
|
|
.oaf-whitelist-modal-buttons .oaf-whitelist-modal-btn {
|
|
flex: 1;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<script type="text/javascript">//<![CDATA[
|
|
var whitelistText = {
|
|
noEntries: '<%:No whitelist entries yet%>',
|
|
loading: '<%:Loading...%>',
|
|
deleteLabel: '<%:Delete%>',
|
|
noDevices: '<%:No available devices to add%>',
|
|
selectDevice: '<%:Please select at least one device%>',
|
|
addSuccess: '<%:Add success%>',
|
|
addFailed: '<%:Add failed%>',
|
|
confirmRemove: '<%:Are you sure you want to remove this device from whitelist?%>',
|
|
deleteSuccess: '<%:Delete success%>',
|
|
deleteFailed: '<%:Delete failed%>',
|
|
selected: '<%:Selected%>'
|
|
};
|
|
|
|
var whitelistTypes = {};
|
|
<% if has_app_filter then %>
|
|
whitelistTypes.app_filter = {
|
|
panelId: 'appFilterWhitelistPanel',
|
|
tableBodyId: 'appFilterWhitelistTableBody',
|
|
getUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "app_filter", "get_appfilter_whitelist")%>',
|
|
addUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "app_filter", "add_appfilter_whitelist")%>',
|
|
delUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "app_filter", "del_appfilter_whitelist")%>',
|
|
usersUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "app_filter", "get_all_users")%>',
|
|
list: [],
|
|
users: [],
|
|
usersLoaded: false
|
|
};
|
|
<% end %>
|
|
<% if has_access_control then %>
|
|
whitelistTypes.access_control = {
|
|
panelId: 'accessControlWhitelistPanel',
|
|
tableBodyId: 'accessControlWhitelistTableBody',
|
|
getUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "mac_filter", "get_mac_filter_whitelist")%>',
|
|
addUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "mac_filter", "add_mac_filter_whitelist")%>',
|
|
delUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "mac_filter", "del_mac_filter_whitelist")%>',
|
|
usersUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "get_all_users")%>',
|
|
list: [],
|
|
users: [],
|
|
usersLoaded: false
|
|
};
|
|
<% end %>
|
|
<% if has_record then %>
|
|
whitelistTypes.record = {
|
|
panelId: 'recordWhitelistPanel',
|
|
tableBodyId: 'recordWhitelistTableBody',
|
|
getUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "record_whitelist", "get_record_whitelist")%>',
|
|
addUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "record_whitelist", "add_record_whitelist")%>',
|
|
delUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "record_whitelist", "del_record_whitelist")%>',
|
|
usersUrl: '<%=dsp.build_url("admin", "services", "oaf", "api", "record_whitelist", "get_all_users")%>',
|
|
list: [],
|
|
users: [],
|
|
usersLoaded: false
|
|
};
|
|
<% end %>
|
|
|
|
var activeWhitelistType = null;
|
|
var modalWhitelistType = null;
|
|
|
|
function escapeWhitelistHtml(value) {
|
|
return $('<div>').text(value == null ? '' : String(value)).html();
|
|
}
|
|
|
|
function normalizeWhitelistMac(mac) {
|
|
return (mac || '').replace(/^\s+|\s+$/g, '').toUpperCase();
|
|
}
|
|
|
|
function switchWhitelistTab(type) {
|
|
if (!whitelistTypes[type]) {
|
|
return;
|
|
}
|
|
|
|
activeWhitelistType = type;
|
|
$('.oaf-whitelist-tab').removeClass('active').attr('aria-selected', 'false');
|
|
$('.oaf-whitelist-tab[data-type="' + type + '"]').addClass('active').attr('aria-selected', 'true');
|
|
$('.oaf-whitelist-panel').removeClass('active');
|
|
$('#' + whitelistTypes[type].panelId).addClass('active');
|
|
}
|
|
|
|
function loadWhitelist(type) {
|
|
var config = whitelistTypes[type];
|
|
|
|
new XHR().get(config.getUrl, null, function(x, data) {
|
|
config.list = data && data.data && Array.isArray(data.data.list) ? data.data.list : [];
|
|
renderWhitelistTable(type);
|
|
}, function() {
|
|
config.list = [];
|
|
renderWhitelistTable(type);
|
|
});
|
|
}
|
|
|
|
function loadWhitelistUsers(type, callback) {
|
|
var config = whitelistTypes[type];
|
|
|
|
new XHR().get(config.usersUrl, {flag: 2, page: 0}, function(x, data) {
|
|
config.users = data && data.data && Array.isArray(data.data.list) ? data.data.list : [];
|
|
config.usersLoaded = true;
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
}, function() {
|
|
config.users = [];
|
|
config.usersLoaded = true;
|
|
if (callback) {
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
|
|
function renderWhitelistTable(type) {
|
|
var config = whitelistTypes[type];
|
|
var tableBody = document.getElementById(config.tableBodyId);
|
|
|
|
tableBody.innerHTML = '';
|
|
if (config.list.length === 0) {
|
|
tableBody.innerHTML = '<tr><td colspan="5" style="text-align:center;padding:30px;color:#999;">' + whitelistText.noEntries + '</td></tr>';
|
|
return;
|
|
}
|
|
|
|
config.list.forEach(function(user, index) {
|
|
var row = document.createElement('tr');
|
|
var mac = normalizeWhitelistMac(user.mac || '');
|
|
row.innerHTML = '<td>' + (index + 1) + '</td>' +
|
|
'<td style="font-family:monospace;font-weight:bold;">' + escapeWhitelistHtml(mac) + '</td>' +
|
|
'<td>' + escapeWhitelistHtml(user.hostname || '--') + '</td>' +
|
|
'<td>' + escapeWhitelistHtml(user.nickname || '--') + '</td>' +
|
|
'<td><button type="button" class="oaf-whitelist-delete-btn" onclick="removeWhitelistUser(\'' + type + '\',\'' + mac + '\')">' + whitelistText.deleteLabel + '</button></td>';
|
|
tableBody.appendChild(row);
|
|
});
|
|
}
|
|
|
|
function showWhitelistModal(type) {
|
|
modalWhitelistType = type;
|
|
$('#oafWhitelistModal').css('display', 'flex');
|
|
|
|
if (!whitelistTypes[type].usersLoaded) {
|
|
$('#oafWhitelistUserList').html('<div class="oaf-whitelist-empty-state">' + whitelistText.loading + '</div>');
|
|
updateWhitelistSelectionStats();
|
|
loadWhitelistUsers(type, function() {
|
|
if (modalWhitelistType === type) {
|
|
renderAvailableWhitelistUsers(type);
|
|
}
|
|
});
|
|
return;
|
|
}
|
|
|
|
renderAvailableWhitelistUsers(type);
|
|
}
|
|
|
|
function renderAvailableWhitelistUsers(type) {
|
|
var config = whitelistTypes[type];
|
|
var whitelistMacs = config.list.map(function(user) { return normalizeWhitelistMac(user.mac || ''); });
|
|
var availableUsers = config.users.filter(function(user) { return whitelistMacs.indexOf(normalizeWhitelistMac(user.mac || '')) === -1; });
|
|
var userList = $('#oafWhitelistUserList').empty();
|
|
|
|
if (availableUsers.length === 0) {
|
|
userList.html('<div class="oaf-whitelist-empty-state">' + whitelistText.noDevices + '</div>');
|
|
updateWhitelistSelectionStats();
|
|
return;
|
|
}
|
|
|
|
availableUsers.forEach(function(user) {
|
|
var mac = normalizeWhitelistMac(user.mac || '');
|
|
var extraInfo = user.nickname || ((user.hostname && user.hostname !== '*') ? user.hostname : user.ip) || '';
|
|
var displayText = extraInfo ? mac + ' (' + extraInfo + ')' : mac;
|
|
var item = $('<div class="oaf-whitelist-user-item"></div>');
|
|
var checkId = 'oaf-whitelist-user-' + modalWhitelistType + '-' + mac.replace(/[^a-zA-Z0-9_-]/g, '-');
|
|
var checkWrap = $('<div class="oaf-check-item"></div>');
|
|
var checkbox = $('<input type="checkbox">')
|
|
.attr('id', checkId)
|
|
.val(mac)
|
|
.on('change', updateWhitelistSelectionStats);
|
|
var label = $('<label class="oaf-whitelist-user-mac"></label>')
|
|
.attr('for', checkId)
|
|
.text(displayText);
|
|
|
|
checkWrap.append(checkbox).append(label);
|
|
item.append(checkWrap);
|
|
item.on('click', function(event) {
|
|
if (!$(event.target).closest('.oaf-check-item').length) {
|
|
checkbox.prop('checked', !checkbox.prop('checked')).trigger('change');
|
|
}
|
|
});
|
|
userList.append(item);
|
|
});
|
|
|
|
updateWhitelistSelectionStats();
|
|
}
|
|
|
|
function updateWhitelistSelectionStats() {
|
|
var allCount = $('#oafWhitelistUserList input[type="checkbox"]').length;
|
|
var selectedCount = $('#oafWhitelistUserList input[type="checkbox"]:checked').length;
|
|
$('#oafWhitelistSelectionStats').text(whitelistText.selected + ': ' + selectedCount + ' / ' + allCount);
|
|
}
|
|
|
|
function toggleAllWhitelistUsers() {
|
|
var checkboxes = $('#oafWhitelistUserList input[type="checkbox"]');
|
|
var selectedCount = checkboxes.filter(':checked').length;
|
|
checkboxes.prop('checked', checkboxes.length > 0 && selectedCount !== checkboxes.length);
|
|
updateWhitelistSelectionStats();
|
|
}
|
|
|
|
function closeWhitelistModal() {
|
|
$('#oafWhitelistModal').hide();
|
|
modalWhitelistType = null;
|
|
}
|
|
|
|
function addWhitelistUsers() {
|
|
var config = whitelistTypes[modalWhitelistType];
|
|
var selectedMacs = $('#oafWhitelistUserList input[type="checkbox"]:checked').map(function() {
|
|
return this.value;
|
|
}).get();
|
|
|
|
if (selectedMacs.length === 0) {
|
|
showWhitelistMessage(whitelistText.selectDevice);
|
|
return;
|
|
}
|
|
|
|
new XHR().post(config.addUrl, {data: JSON.stringify({mac_list: selectedMacs})}, function(x, data) {
|
|
if (data && data.code == 2000) {
|
|
var type = modalWhitelistType;
|
|
closeWhitelistModal();
|
|
loadWhitelist(type);
|
|
showWhitelistMessage(whitelistText.addSuccess);
|
|
} else {
|
|
showWhitelistMessage(whitelistText.addFailed);
|
|
}
|
|
}, function() {
|
|
showWhitelistMessage(whitelistText.addFailed);
|
|
});
|
|
}
|
|
|
|
function removeWhitelistUser(type, mac) {
|
|
var config = whitelistTypes[type];
|
|
|
|
if (!confirm(whitelistText.confirmRemove)) {
|
|
return;
|
|
}
|
|
|
|
new XHR().post(config.delUrl, {mac: mac}, function(x, data) {
|
|
if (data && data.code == 2000) {
|
|
loadWhitelist(type);
|
|
showWhitelistMessage(whitelistText.deleteSuccess);
|
|
} else {
|
|
showWhitelistMessage(whitelistText.deleteFailed);
|
|
}
|
|
}, function() {
|
|
showWhitelistMessage(whitelistText.deleteFailed);
|
|
});
|
|
}
|
|
|
|
function showWhitelistMessage(message) {
|
|
$('#oafWhitelistMessageText').text(message);
|
|
$('#oafWhitelistMessage').css('display', 'flex');
|
|
setTimeout(function() {
|
|
$('#oafWhitelistMessage').hide();
|
|
}, 1500);
|
|
}
|
|
|
|
$(function() {
|
|
var types = Object.keys(whitelistTypes);
|
|
|
|
if (types.length === 0) {
|
|
return;
|
|
}
|
|
|
|
switchWhitelistTab(types[0]);
|
|
types.forEach(function(type) {
|
|
loadWhitelist(type);
|
|
loadWhitelistUsers(type);
|
|
});
|
|
|
|
$('#oafWhitelistModal').on('click', function(event) {
|
|
if (event.target === this) {
|
|
closeWhitelistModal();
|
|
}
|
|
});
|
|
});
|
|
//]]></script>
|
|
|
|
<div class="cbi-section cbi-tblsection">
|
|
<div class="oaf-whitelist-tip">
|
|
<%:Users in the whitelist are not subject to control. For terminals using random MAC addresses, you can use the whitelist mechanism together with filtering rules: select All Users in a filtering rule, and the rule will apply to all new users.%>
|
|
</div>
|
|
|
|
<div class="oaf-whitelist-tabs" role="tablist">
|
|
<% if has_app_filter then %>
|
|
<button type="button" class="oaf-whitelist-tab" data-type="app_filter" role="tab" aria-selected="false" onclick="switchWhitelistTab('app_filter')"><%:App Filter Whitelist%></button>
|
|
<% end %>
|
|
<% if has_access_control then %>
|
|
<button type="button" class="oaf-whitelist-tab" data-type="access_control" role="tab" aria-selected="false" onclick="switchWhitelistTab('access_control')"><%:Access Control Whitelist%></button>
|
|
<% end %>
|
|
<% if has_record then %>
|
|
<button type="button" class="oaf-whitelist-tab" data-type="record" role="tab" aria-selected="false" onclick="switchWhitelistTab('record')"><%:Record Whitelist%></button>
|
|
<% end %>
|
|
</div>
|
|
|
|
<% if has_app_filter then %>
|
|
<div id="appFilterWhitelistPanel" class="oaf-whitelist-panel" role="tabpanel">
|
|
<div class="oaf-whitelist-panel-header">
|
|
<h3 style="margin:0;"><%:App Filter Whitelist%></h3>
|
|
<button type="button" class="oaf-whitelist-add-btn" onclick="showWhitelistModal('app_filter')">+ <%:Add to Whitelist%></button>
|
|
</div>
|
|
<div class="oaf-whitelist-table-wrap">
|
|
<table class="common-table oaf-whitelist-table">
|
|
<thead><tr><th><%:No.%></th><th><%:MAC Address%></th><th><%:Hostname%></th><th><%:Nickname%></th><th><%:Operation%></th></tr></thead>
|
|
<tbody id="appFilterWhitelistTableBody"><tr><td colspan="5" style="text-align:center;padding:30px;color:#999;"><%:Loading...%></td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if has_access_control then %>
|
|
<div id="accessControlWhitelistPanel" class="oaf-whitelist-panel" role="tabpanel">
|
|
<div class="oaf-whitelist-panel-header">
|
|
<h3 style="margin:0;"><%:Access Control Whitelist%></h3>
|
|
<button type="button" class="oaf-whitelist-add-btn" onclick="showWhitelistModal('access_control')">+ <%:Add to Whitelist%></button>
|
|
</div>
|
|
<div class="oaf-whitelist-table-wrap">
|
|
<table class="common-table oaf-whitelist-table">
|
|
<thead><tr><th><%:No.%></th><th><%:MAC Address%></th><th><%:Hostname%></th><th><%:Nickname%></th><th><%:Operation%></th></tr></thead>
|
|
<tbody id="accessControlWhitelistTableBody"><tr><td colspan="5" style="text-align:center;padding:30px;color:#999;"><%:Loading...%></td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
|
|
<% if has_record then %>
|
|
<div id="recordWhitelistPanel" class="oaf-whitelist-panel" role="tabpanel">
|
|
<div class="oaf-whitelist-panel-header">
|
|
<h3 style="margin:0;"><%:Record Whitelist%></h3>
|
|
<button type="button" class="oaf-whitelist-add-btn" onclick="showWhitelistModal('record')">+ <%:Add to Whitelist%></button>
|
|
</div>
|
|
<div class="oaf-whitelist-table-wrap">
|
|
<table class="common-table oaf-whitelist-table">
|
|
<thead><tr><th><%:No.%></th><th><%:MAC Address%></th><th><%:Hostname%></th><th><%:Nickname%></th><th><%:Operation%></th></tr></thead>
|
|
<tbody id="recordWhitelistTableBody"><tr><td colspan="5" style="text-align:center;padding:30px;color:#999;"><%:Loading...%></td></tr></tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
<% end %>
|
|
</div>
|
|
|
|
<div id="oafWhitelistModal" class="oaf-whitelist-modal">
|
|
<div class="oaf-whitelist-modal-content">
|
|
<div class="oaf-whitelist-modal-header"><%:Add to Whitelist%></div>
|
|
<div class="oaf-whitelist-selection-toolbar">
|
|
<button type="button" class="oaf-whitelist-modal-btn oaf-whitelist-modal-btn-secondary" onclick="toggleAllWhitelistUsers()"><%:Select All%></button>
|
|
<span id="oafWhitelistSelectionStats" class="oaf-whitelist-selection-stat"><%:Selected%>: 0 / 0</span>
|
|
</div>
|
|
<div id="oafWhitelistUserList" class="oaf-whitelist-user-list"></div>
|
|
<div class="oaf-whitelist-modal-buttons">
|
|
<button type="button" class="oaf-whitelist-modal-btn oaf-whitelist-modal-btn-primary" onclick="addWhitelistUsers()"><%:OK%></button>
|
|
<button type="button" class="oaf-whitelist-modal-btn oaf-whitelist-modal-btn-secondary" onclick="closeWhitelistModal()"><%:Cancel%></button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="oafWhitelistMessage" class="oaf-whitelist-message">
|
|
<div class="oaf-whitelist-message-content">
|
|
<p id="oafWhitelistMessageText" style="margin:0;"></p>
|
|
</div>
|
|
</div>
|