mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-04 22:57:20 +02:00
Added blacklist ip table, uptime monitor interface
This commit is contained in:
parent
44c1e60fb8
commit
2c586aee32
@ -315,6 +315,24 @@
|
|||||||
|
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<h4>Visitor IP list</h4>
|
||||||
|
<button style="margin-top: -1em;" onclick="initBlacklistQuickBanTable();" class="ui green small right floated circular basic icon button"><i class="ui refresh icon"></i></button>
|
||||||
|
<p>Observe strange traffic on your sites? Ban them in the list below.</p>
|
||||||
|
|
||||||
|
<table class="ui celled unstackable table" id="ipTable">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>IP</th>
|
||||||
|
<th>Access Count</th>
|
||||||
|
<th>Blacklist</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div class="pagination"></div>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
$(".dropdown").dropdown();
|
$(".dropdown").dropdown();
|
||||||
|
|
||||||
@ -427,13 +445,15 @@
|
|||||||
icon = "home icon";
|
icon = "home icon";
|
||||||
}
|
}
|
||||||
$('#blacklistIpTable').append(`
|
$('#blacklistIpTable').append(`
|
||||||
<tr>
|
<tr class="blacklistItem" ip="${encodeURIComponent(ip)}">
|
||||||
<td><i class="${icon}"></i> ${ip}</td>
|
<td><i class="${icon}"></i> ${ip}</td>
|
||||||
<td><button class="ui icon basic mini red button" onclick="removeIpBlacklist('${ip}');"><i class="trash alternate icon"></i></button></td>
|
<td><button class="ui icon basic mini red button" onclick="removeIpBlacklist('${ip}');"><i class="trash alternate icon"></i></button></td>
|
||||||
</tr>
|
</tr>
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initBlacklistQuickBanTable();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
initIpBanTable();
|
initIpBanTable();
|
||||||
@ -563,6 +583,7 @@
|
|||||||
error: function() {
|
error: function() {
|
||||||
alert("Failed to remove IP address from blacklist.");
|
alert("Failed to remove IP address from blacklist.");
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -594,6 +615,99 @@
|
|||||||
}
|
}
|
||||||
initBlacklistEnableState();
|
initBlacklistEnableState();
|
||||||
|
|
||||||
|
//Load the summary to ip access table
|
||||||
|
function initBlacklistQuickBanTable(){
|
||||||
|
$.get("/api/stats/summary", function(data){
|
||||||
|
initIpAccessTable(data.RequestClientIp);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
initBlacklistQuickBanTable();
|
||||||
|
|
||||||
|
var blacklist_entriesPerPage = 30;
|
||||||
|
var blacklist_currentPage = 1;
|
||||||
|
var blacklist_totalPages = 0;
|
||||||
|
|
||||||
|
function initIpAccessTable(ipAccessCounts){
|
||||||
|
blacklist_totalPages = Math.ceil(Object.keys(ipAccessCounts).length / blacklist_entriesPerPage);
|
||||||
|
|
||||||
|
function sortkv(obj) {
|
||||||
|
var sortable = [];
|
||||||
|
for (var key in obj) {
|
||||||
|
if (obj.hasOwnProperty(key)) {
|
||||||
|
sortable.push([key, obj[key]]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sortable.sort(function(a, b) {
|
||||||
|
return b[1] - a[1];
|
||||||
|
});
|
||||||
|
var sortedObj = {};
|
||||||
|
sortable.forEach(function(item) {
|
||||||
|
sortedObj[item[0]] = item[1];
|
||||||
|
});
|
||||||
|
return sortedObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
ipAccessCounts = sortkv(ipAccessCounts);
|
||||||
|
|
||||||
|
function renderTable() {
|
||||||
|
var tableBody = $("#ipTable tbody");
|
||||||
|
tableBody.empty();
|
||||||
|
|
||||||
|
var startIndex = (blacklist_currentPage - 1) * blacklist_entriesPerPage;
|
||||||
|
var endIndex = startIndex + blacklist_entriesPerPage;
|
||||||
|
var slicedEntries = Object.entries(ipAccessCounts).slice(startIndex, endIndex);
|
||||||
|
|
||||||
|
slicedEntries.forEach(function([ip, accessCount]) {
|
||||||
|
var row = $("<tr>").appendTo(tableBody);
|
||||||
|
$("<td>").text(ip).appendTo(row);
|
||||||
|
$("<td>").text(accessCount).appendTo(row);
|
||||||
|
if (ipInBlacklist(ip)){
|
||||||
|
$("<td>").html(`<button class="ui basic green small icon button" title"Unban IP" onclick="handleUnban('${ip}');"><i class="green check icon"></i></button>`).appendTo(row);
|
||||||
|
}else{
|
||||||
|
$("<td>").html(`<button class="ui basic red small icon button" title"Ban IP" onclick="handleBanIp('${ip}');"><i class="red ban icon"></i></button>`).appendTo(row);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPagination() {
|
||||||
|
var paginationDiv = $(".pagination");
|
||||||
|
paginationDiv.empty();
|
||||||
|
|
||||||
|
for (var i = 1; i <= blacklist_totalPages; i++) {
|
||||||
|
var button = $("<button>").text(i).addClass("ui small basic compact button");
|
||||||
|
if (i === blacklist_currentPage) {
|
||||||
|
button.addClass("disabled");
|
||||||
|
}
|
||||||
|
button.click(function() {
|
||||||
|
blacklist_currentPage = parseInt($(this).text());
|
||||||
|
renderTable();
|
||||||
|
renderPagination();
|
||||||
|
});
|
||||||
|
button.appendTo(paginationDiv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderTable();
|
||||||
|
renderPagination();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ipInBlacklist(targetIp){
|
||||||
|
let inBlacklist = false;
|
||||||
|
$(".blacklistItem").each(function(){
|
||||||
|
if ($(this).attr("ip") == encodeURIComponent(targetIp)){
|
||||||
|
inBlacklist = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return inBlacklist;
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleBanIp(targetIp){
|
||||||
|
$("#ipAddressInput").val(targetIp);
|
||||||
|
addIpBlacklist();
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleUnban(targetIp){
|
||||||
|
removeIpBlacklist(targetIp);
|
||||||
|
}
|
||||||
</script>
|
</script>
|
@ -25,23 +25,27 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div id="connections" class="ui yellow statustab inverted segment">
|
<div id="connections" class="ui statustab segment" style="background-color: #f0ece1; border: 0px solid transparent;">
|
||||||
<h4 class="ui header">
|
<h4 class="ui header">
|
||||||
<i class="exchange icon"></i>
|
<i class="arrows alternate horizontal icon"></i>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<span></span>
|
<span id="forwardtype"></span>
|
||||||
<div class="sub header"></div>
|
<div class="sub header" id="forwardtypeList">
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<div id="connections" class="ui pink statustab inverted segment">
|
<div id="connections" class="ui statustab inverted segment" style="background-color: #7d8e88;">
|
||||||
<h4 class="ui header">
|
<h4 class="ui header">
|
||||||
<i class="exchange icon"></i>
|
<i class="map marker alternate icon"></i>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<span></span>
|
<span id="country"></span>
|
||||||
<div class="sub header"></div>
|
<div class="sub header" id="countryList">
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</h4>
|
</h4>
|
||||||
</div>
|
</div>
|
||||||
@ -81,35 +85,39 @@
|
|||||||
<div class="ui two column stackable grid">
|
<div class="ui two column stackable grid">
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<p>Visitor Counts</p>
|
<p>Visitor Counts</p>
|
||||||
<table class="ui basic celled table">
|
<table class="ui unstackable celled table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Country ISO Code</th>
|
<th>Country ISO Code</th>
|
||||||
<th>Visitor Count</th>
|
<th>Unique Visitors</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="countryCodetable">
|
||||||
<!-- insert table rows here -->
|
<tr>
|
||||||
|
<td colspan="2">No Data</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<div class="column">
|
<div class="column">
|
||||||
<p>Proxy Request Types</p>
|
<p>Proxy Request Types</p>
|
||||||
<table class="ui basic celled table">
|
<table class="ui unstackable celled table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th>Proxy Type</th>
|
<th>Proxy Type</th>
|
||||||
<th>Count</th>
|
<th>Count</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody id="forwardTypeTable">
|
||||||
<!-- insert table rows here -->
|
<tr>
|
||||||
|
<td colspan="2">No Data</td>
|
||||||
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<br>
|
<br>
|
||||||
<button class="ui basic green button"><i class="refresh icon"></i> Refresh</button>
|
<button class="ui basic green button" onclick="getDailySummaryDetails();"><i class="refresh icon"></i> Refresh</button>
|
||||||
<script>
|
<script>
|
||||||
let loopbackProxiedInterface = false;
|
let loopbackProxiedInterface = false;
|
||||||
//Initial the start stop button if this is reverse proxied
|
//Initial the start stop button if this is reverse proxied
|
||||||
@ -148,7 +156,7 @@
|
|||||||
|
|
||||||
function abbreviateNumber(value) {
|
function abbreviateNumber(value) {
|
||||||
var newValue = value;
|
var newValue = value;
|
||||||
var suffixes = ["", "K", "M", "B", "T"];
|
var suffixes = ["", "k", "m", "b", "t"];
|
||||||
var suffixNum = 0;
|
var suffixNum = 0;
|
||||||
while (newValue >= 1000 && suffixNum < suffixes.length - 1) {
|
while (newValue >= 1000 && suffixNum < suffixes.length - 1) {
|
||||||
newValue /= 1000;
|
newValue /= 1000;
|
||||||
@ -161,6 +169,90 @@
|
|||||||
return newValue + suffixes[suffixNum];
|
return newValue + suffixes[suffixNum];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getDailySummaryDetails(){
|
||||||
|
function sortObjectByValue(obj) {
|
||||||
|
// Convert object to array of [key, value] pairs
|
||||||
|
const entries = Object.entries(obj);
|
||||||
|
|
||||||
|
// Sort array based on value of each pair
|
||||||
|
entries.sort((a, b) => {
|
||||||
|
return b[1] - a[1];
|
||||||
|
});
|
||||||
|
|
||||||
|
// Convert sorted array back to object
|
||||||
|
const sortedObj = {};
|
||||||
|
for (const [key, value] of entries) {
|
||||||
|
sortedObj[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return sortedObj;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.get("/api/stats/countries", function(data){
|
||||||
|
data = sortObjectByValue(data);
|
||||||
|
$("#country").html((Object.keys(data)[0])?Object.keys(data)[0]:"No Data");
|
||||||
|
$("#countryList").html(`
|
||||||
|
<div style="color: white;">
|
||||||
|
${(Object.keys(data)[1])?Object.keys(data)[1]:"No Data"}<br>
|
||||||
|
${(Object.keys(data)[2])?Object.keys(data)[2]:"No Data"}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
//populate the table
|
||||||
|
$("#countryCodetable").html("");
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
$("#countryCodetable").append(`<tr>
|
||||||
|
<td>${key}</td>
|
||||||
|
<td>${value}</td>
|
||||||
|
</tr>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(data).length == 0){
|
||||||
|
$("#countryCodetable").append(`<tr>
|
||||||
|
<td colspan="2">No Data</td>
|
||||||
|
</tr>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
//Filter forward type
|
||||||
|
function fft(ft){
|
||||||
|
if (ft.indexOf("-") >= 0){
|
||||||
|
ft = ft.replace("-", " (");
|
||||||
|
ft = ft + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ft = ft.charAt(0).toUpperCase() + ft.slice(1);
|
||||||
|
return ft;
|
||||||
|
}
|
||||||
|
|
||||||
|
$.get("/api/stats/summary", function(data){
|
||||||
|
data = sortObjectByValue(data.ForwardTypes);
|
||||||
|
$("#forwardtype").html((Object.keys(data)[0])?fft(Object.keys(data)[0]) + ": " + abbreviateNumber(data[Object.keys(data)[0]]):"No Data");
|
||||||
|
$("#forwardtypeList").html(`
|
||||||
|
<div>
|
||||||
|
${(Object.keys(data)[1])?fft(Object.keys(data)[1]) + ": " + abbreviateNumber(data[Object.keys(data)[1]]):"No Data"}<br>
|
||||||
|
${(Object.keys(data)[2])?fft(Object.keys(data)[2]) + ": " + abbreviateNumber(data[Object.keys(data)[2]]):"No Data"}
|
||||||
|
</div>
|
||||||
|
`);
|
||||||
|
|
||||||
|
$("#forwardTypeTable").html("");
|
||||||
|
for (const [key, value] of Object.entries(data)) {
|
||||||
|
$("#forwardTypeTable").append(`<tr>
|
||||||
|
<td>${key}</td>
|
||||||
|
<td>${value}</td>
|
||||||
|
</tr>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Object.keys(data).length == 0){
|
||||||
|
$("#forwardTypeTable").append(`<tr>
|
||||||
|
<td colspan="2">No Data</td>
|
||||||
|
</tr>`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
getDailySummaryDetails();
|
||||||
|
|
||||||
|
|
||||||
function getDailySummary(){
|
function getDailySummary(){
|
||||||
$.get("/api/stats/summary?fast=true", function(data){
|
$.get("/api/stats/summary?fast=true", function(data){
|
||||||
|
@ -33,7 +33,7 @@
|
|||||||
$("#subdList").append(`<tr>
|
$("#subdList").append(`<tr>
|
||||||
<td data-label="">${subd.MatchingDomain}</td>
|
<td data-label="">${subd.MatchingDomain}</td>
|
||||||
<td data-label="">${subd.Domain} ${tlsIcon}</td>
|
<td data-label="">${subd.Domain} ${tlsIcon}</td>
|
||||||
<td data-label=""><button class="ui circular mini red basic button" onclick='deleteEndpoint("subd","${subd.MatchingDomain}")'><i class="remove icon"></i> Remove Subdomain</button></td>
|
<td data-label=""><button class="ui circular mini red basic button" onclick='deleteEndpoint("subd","${subd.MatchingDomain}")'><i class="remove icon"></i> Delete</button></td>
|
||||||
</tr>`);
|
</tr>`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
165
src/web/components/uptime.html
Normal file
165
src/web/components/uptime.html
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
<h3><i class="clock green icon"></i> Uptime Monitor</h3>
|
||||||
|
<p>Check the online state of proxied targets</p>
|
||||||
|
|
||||||
|
<div class="ui toggle checkbox" id="utmEnable">
|
||||||
|
<input type="checkbox" name="utmEnable">
|
||||||
|
<label>Enable External Access</label>
|
||||||
|
</div>
|
||||||
|
<div class="ui message">
|
||||||
|
You can expose the uptime monitor interface to public by adding: <br>
|
||||||
|
<code>%uptime_monitor%</code>
|
||||||
|
<br>as a subdomain or virtual directory target URL in the "Create Proxy Rules" tab.
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
<div id="utmrender" class="ui basic segment">
|
||||||
|
<div class="ui basic segment">
|
||||||
|
<h4 class="ui header">
|
||||||
|
<i class="red remove icon"></i>
|
||||||
|
<div class="content">
|
||||||
|
Uptime Monitoring service is currently unavailable
|
||||||
|
<div class="sub header">This might cause by an error in cluster communication within the host servers. Please wait for administrator to resolve the issue.</div>
|
||||||
|
</div>
|
||||||
|
</h4>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div align="center">
|
||||||
|
<button class="ui basic circular green icon button" onclick="reloadUptimeList();"><i class="refresh icon"></i></button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<script>
|
||||||
|
|
||||||
|
$('#utmEnable').checkbox({
|
||||||
|
onChange: function() {
|
||||||
|
var utmEnable = $('input[name="utmEnable"]').is(":checked");
|
||||||
|
$.post({
|
||||||
|
url: '/api/toggle-utm',
|
||||||
|
data: {utmEnable: utmEnable},
|
||||||
|
success: function(response) {
|
||||||
|
console.log(response);
|
||||||
|
},
|
||||||
|
error: function(error) {
|
||||||
|
console.log(error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function initUptimeTable(){
|
||||||
|
$.get("/api/utm/list", function(data){
|
||||||
|
let records = data;
|
||||||
|
renderRecords(records);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
initUptimeTable();
|
||||||
|
|
||||||
|
function reloadUptimeList(){
|
||||||
|
$("#utmrender").html(`<div class="ui segment">
|
||||||
|
<div class="ui active inverted dimmer" style="z-index: 2;">
|
||||||
|
<div class="ui text loader">Loading</div>
|
||||||
|
</div>
|
||||||
|
<br><br><br><br>
|
||||||
|
</div>`);
|
||||||
|
setTimeout(initUptimeTable, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
//For every 5 minutes
|
||||||
|
setInterval(function(){
|
||||||
|
$.get("/api/utm/list", function(data){
|
||||||
|
console.log("Status Updated");
|
||||||
|
records = data;
|
||||||
|
renderRecords(records);
|
||||||
|
});
|
||||||
|
}, (300 * 1000));
|
||||||
|
|
||||||
|
function renderRecords(records){
|
||||||
|
$("#utmrender").html("");
|
||||||
|
for (let [key, value] of Object.entries(records)) {
|
||||||
|
renderUptimeData(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_time(s) {
|
||||||
|
const date = new Date(s * 1e3);
|
||||||
|
return(date.toLocaleString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function renderUptimeData(key, value){
|
||||||
|
if (value.length == 0){
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = value[0].ID;
|
||||||
|
let name = value[0].Name;
|
||||||
|
let url = value[0].URL;
|
||||||
|
let protocol = value[0].Protocol;
|
||||||
|
|
||||||
|
//Generate the status dot
|
||||||
|
let statusDotList = ``;
|
||||||
|
for(var i = 0; i < (288 - value.length); i++){
|
||||||
|
//Padding
|
||||||
|
statusDotList += `<div class="padding statusDot"></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
let ontimeRate = 0;
|
||||||
|
for (var i = 0; i < value.length; i++){
|
||||||
|
//Render status to html
|
||||||
|
let thisStatus = value[i];
|
||||||
|
let dotType = "";
|
||||||
|
if (thisStatus.Online){
|
||||||
|
if (thisStatus.StatusCode < 200 || thisStatus.StatusCode >= 300){
|
||||||
|
dotType = "error";
|
||||||
|
}else{
|
||||||
|
dotType = "online";
|
||||||
|
}
|
||||||
|
ontimeRate++;
|
||||||
|
}else{
|
||||||
|
dotType = "offline";
|
||||||
|
}
|
||||||
|
|
||||||
|
let datetime = format_time(thisStatus.Timestamp);
|
||||||
|
statusDotList += `<div title="${datetime}" class="${dotType} statusDot"></div>`
|
||||||
|
}
|
||||||
|
|
||||||
|
ontimeRate = ontimeRate / value.length * 100;
|
||||||
|
let ontimeColor = "#df484a"
|
||||||
|
if (ontimeRate > 0.8){
|
||||||
|
ontimeColor = "#3bd671";
|
||||||
|
}else if(ontimeRate > 0.5) {
|
||||||
|
ontimeColor = "#f29030";
|
||||||
|
}
|
||||||
|
//Check of online status now
|
||||||
|
let currentOnlineStatus = "Unknown";
|
||||||
|
let onlineStatusCss = ``;
|
||||||
|
if (value[value.length - 1].Online){
|
||||||
|
currentOnlineStatus = `<i class="circle icon"></i> Online`;
|
||||||
|
onlineStatusCss = `color: #3bd671;`;
|
||||||
|
}else{
|
||||||
|
currentOnlineStatus = `<i class="circle icon"></i> Offline`;
|
||||||
|
onlineStatusCss = `color: #df484a;`;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Generate the html
|
||||||
|
$("#utmrender").append(`<div class="ui basic segment statusbar">
|
||||||
|
<div class="domain">
|
||||||
|
<div style="position: absolute; top: 0; right: 0.4em;">
|
||||||
|
<p class="onlineStatus" style="display: inline-block; font-size: 1.3em; padding-right: 0.5em; padding-left: 0.3em; ${onlineStatusCss}">${currentOnlineStatus}</p>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<h3 class="ui header" style="margin-bottom: 0.2em;">${name}</h3>
|
||||||
|
<a href="${url}" target="_blank">${url}</a> | <span style="color: ${ontimeColor};">${(ontimeRate).toFixed(2)}%<span>
|
||||||
|
</div>
|
||||||
|
<div class="ui basic label protocol" style="position: absolute; bottom: 0; right: 0.2em; margin-bottom: -0.6em;">
|
||||||
|
proto: ${protocol}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="status" style="marign-top: 1em;">
|
||||||
|
${statusDotList}
|
||||||
|
</div>
|
||||||
|
<div class="ui divider"></div>
|
||||||
|
</div>`);
|
||||||
|
}
|
||||||
|
|
||||||
|
</script>
|
@ -38,7 +38,7 @@
|
|||||||
$("#vdirList").append(`<tr>
|
$("#vdirList").append(`<tr>
|
||||||
<td data-label="">${vdir.Root}</td>
|
<td data-label="">${vdir.Root}</td>
|
||||||
<td data-label="">${vdir.Domain} ${tlsIcon}</td>
|
<td data-label="">${vdir.Domain} ${tlsIcon}</td>
|
||||||
<td data-label=""><button class="ui circular mini red basic button" onclick='deleteEndpoint("vdir","${vdir.Root}")'><i class="remove icon"></i> Remove Virtual Directory</button></td>
|
<td data-label=""><button class="ui circular mini red basic button" onclick='deleteEndpoint("vdir","${vdir.Root}")'><i class="remove icon"></i> Delete</button></td>
|
||||||
</tr>`);
|
</tr>`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui container" style="color: grey; font-size: 90%">
|
<div class="ui container" style="color: grey; font-size: 90%">
|
||||||
<p>Reverse Proxy by imuslab, Licensed under MIT</p>
|
<p>Powered by Zoraxy</p>
|
||||||
</div>
|
</div>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
@ -20,6 +20,9 @@
|
|||||||
<img class="logo" src="img/logo.svg">
|
<img class="logo" src="img/logo.svg">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="ui right floated buttons menutoggle" style="padding-top: 2px;">
|
||||||
|
<button class="ui basic icon button" onclick="$('.toolbar').fadeToggle('fast');"><i class="content icon"></i></button>
|
||||||
|
</div>
|
||||||
<div class="ui right floated buttons" style="padding-top: 2px;">
|
<div class="ui right floated buttons" style="padding-top: 2px;">
|
||||||
<button class="ui basic icon button" onclick="logout();"><i class="sign-out icon"></i></button>
|
<button class="ui basic icon button" onclick="logout();"><i class="sign-out icon"></i></button>
|
||||||
</div>
|
</div>
|
||||||
@ -63,8 +66,8 @@
|
|||||||
<i class="remove icon"></i> HTTP over Websocket
|
<i class="remove icon"></i> HTTP over Websocket
|
||||||
</a>
|
</a>
|
||||||
<div class="ui divider menudivider">Others</div>
|
<div class="ui divider menudivider">Others</div>
|
||||||
<a class="item" tag="">
|
<a class="item" tag="utm">
|
||||||
<i class="remove icon"></i> Uptime Monitor
|
<i class="green time icon"></i> Uptime Monitor
|
||||||
</a>
|
</a>
|
||||||
<a class="item" tag="">
|
<a class="item" tag="">
|
||||||
<i class="remove icon"></i> Network Tools
|
<i class="remove icon"></i> Network Tools
|
||||||
@ -105,6 +108,9 @@
|
|||||||
<!-- UPnP based port fowarding -->
|
<!-- UPnP based port fowarding -->
|
||||||
<div id="upnp" class="functiontab" target="upnp.html"></div>
|
<div id="upnp" class="functiontab" target="upnp.html"></div>
|
||||||
|
|
||||||
|
<!-- Up Time Monitor -->
|
||||||
|
<div id="utm" class="functiontab" target="uptime.html"></div>
|
||||||
|
|
||||||
<!-- Utilities -->
|
<!-- Utilities -->
|
||||||
<div id="utils" class="functiontab" target="utils.html"></div>
|
<div id="utils" class="functiontab" target="utils.html"></div>
|
||||||
</div>
|
</div>
|
||||||
@ -207,6 +213,11 @@
|
|||||||
alert("Invalid tabid given");
|
alert("Invalid tabid given");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (window.innerWidth < 750){
|
||||||
|
//RWD mode, hide toolbar
|
||||||
|
$(".toolbar").fadeOut('fast');
|
||||||
|
}
|
||||||
|
|
||||||
$("#mainmenu").find(".item").removeClass("active");
|
$("#mainmenu").find(".item").removeClass("active");
|
||||||
$(targetBtn).addClass("active");
|
$(targetBtn).addClass("active");
|
||||||
$(".functiontab").hide();
|
$(".functiontab").hide();
|
||||||
@ -215,6 +226,12 @@
|
|||||||
window.location.hash = tabID;
|
window.location.hash = tabID;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$(window).on("resize", function(){
|
||||||
|
if (window.innerWidth >= 750 && $(".toolbar").is(":visible") == false){
|
||||||
|
$(".toolbar").show();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
@ -41,6 +41,7 @@ body{
|
|||||||
|
|
||||||
.toolbar{
|
.toolbar{
|
||||||
width: 240px;
|
width: 240px;
|
||||||
|
min-width: 240px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.contentWindow{
|
.contentWindow{
|
||||||
@ -48,11 +49,28 @@ body{
|
|||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.menutoggle{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
@media screen and (max-width: 750px) {
|
@media screen and (max-width: 750px) {
|
||||||
.toolbar {
|
.toolbar {
|
||||||
|
position: fixed;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 50%;
|
||||||
|
background-color: white;
|
||||||
|
top: 3.6em;
|
||||||
|
right: 0;
|
||||||
|
height: 100%;
|
||||||
margin-bottom: 1em;
|
margin-bottom: 1em;
|
||||||
|
z-index: 9;
|
||||||
|
padding: 1em;
|
||||||
|
display:none;
|
||||||
|
border-left: 1px solid rgb(206, 206, 206);
|
||||||
|
}
|
||||||
|
|
||||||
|
.menutoggle{
|
||||||
|
display: inline-block !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
#mainmenu{
|
#mainmenu{
|
||||||
@ -63,6 +81,8 @@ body{
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.menudivider{
|
.menudivider{
|
||||||
@ -95,7 +115,7 @@ body{
|
|||||||
}
|
}
|
||||||
|
|
||||||
.statustab{
|
.statustab{
|
||||||
min-height: 5em;
|
min-height: 5.5em;
|
||||||
}
|
}
|
||||||
|
|
||||||
#summaryTotalCount{
|
#summaryTotalCount{
|
||||||
@ -111,3 +131,40 @@ body{
|
|||||||
.statustab.summary span, .statustab.summary i{
|
.statustab.summary span, .statustab.summary i{
|
||||||
color: rgb(37, 37, 37);
|
color: rgb(37, 37, 37);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Uptime Monitor
|
||||||
|
*/
|
||||||
|
#utm{
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.domain{
|
||||||
|
margin-bottom: 1em;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.statusDot{
|
||||||
|
height: 1.8em;
|
||||||
|
border-radius: 0.4em;
|
||||||
|
width: 0.4em;
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
display:inline-block;
|
||||||
|
cursor: pointer;
|
||||||
|
margin-left: 0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.online.statusDot{
|
||||||
|
background-color: #3bd671;
|
||||||
|
}
|
||||||
|
.error.statusDot{
|
||||||
|
background-color: #f29030;
|
||||||
|
}
|
||||||
|
.offline.statusDot{
|
||||||
|
background-color: #df484a;
|
||||||
|
}
|
||||||
|
.padding.statusDot{
|
||||||
|
cursor: auto;
|
||||||
|
}
|
@ -146,7 +146,7 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
<div class="ui container" style="color: grey; font-size: 90%">
|
<div class="ui container" style="color: grey; font-size: 90%">
|
||||||
<p>Reverse Proxy by imuslab, Licensed under MIT</p>
|
<p>Powered by Zoraxy</p>
|
||||||
</div>
|
</div>
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user