mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-06-03 06:07:20 +02:00
Added blacklist ip table, uptime monitor interface
This commit is contained in:
parent
44c1e60fb8
commit
2c586aee32
@ -315,6 +315,24 @@
|
||||
|
||||
</tbody>
|
||||
</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>
|
||||
$(".dropdown").dropdown();
|
||||
|
||||
@ -427,13 +445,15 @@
|
||||
icon = "home icon";
|
||||
}
|
||||
$('#blacklistIpTable').append(`
|
||||
<tr>
|
||||
<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>
|
||||
<tr class="blacklistItem" ip="${encodeURIComponent(ip)}">
|
||||
<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>
|
||||
</tr>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
initBlacklistQuickBanTable();
|
||||
});
|
||||
}
|
||||
initIpBanTable();
|
||||
@ -563,6 +583,7 @@
|
||||
error: function() {
|
||||
alert("Failed to remove IP address from blacklist.");
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -594,6 +615,99 @@
|
||||
}
|
||||
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>
|
@ -25,23 +25,27 @@
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<i class="exchange icon"></i>
|
||||
<i class="arrows alternate horizontal icon"></i>
|
||||
<div class="content">
|
||||
<span></span>
|
||||
<div class="sub header"></div>
|
||||
<span id="forwardtype"></span>
|
||||
<div class="sub header" id="forwardtypeList">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
<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">
|
||||
<i class="exchange icon"></i>
|
||||
<i class="map marker alternate icon"></i>
|
||||
<div class="content">
|
||||
<span></span>
|
||||
<div class="sub header"></div>
|
||||
<span id="country"></span>
|
||||
<div class="sub header" id="countryList">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
@ -81,35 +85,39 @@
|
||||
<div class="ui two column stackable grid">
|
||||
<div class="column">
|
||||
<p>Visitor Counts</p>
|
||||
<table class="ui basic celled table">
|
||||
<table class="ui unstackable celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Country ISO Code</th>
|
||||
<th>Visitor Count</th>
|
||||
<th>Unique Visitors</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- insert table rows here -->
|
||||
<tbody id="countryCodetable">
|
||||
<tr>
|
||||
<td colspan="2">No Data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="column">
|
||||
<p>Proxy Request Types</p>
|
||||
<table class="ui basic celled table">
|
||||
<table class="ui unstackable celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Proxy Type</th>
|
||||
<th>Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<!-- insert table rows here -->
|
||||
<tbody id="forwardTypeTable">
|
||||
<tr>
|
||||
<td colspan="2">No Data</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<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>
|
||||
let loopbackProxiedInterface = false;
|
||||
//Initial the start stop button if this is reverse proxied
|
||||
@ -148,7 +156,7 @@
|
||||
|
||||
function abbreviateNumber(value) {
|
||||
var newValue = value;
|
||||
var suffixes = ["", "K", "M", "B", "T"];
|
||||
var suffixes = ["", "k", "m", "b", "t"];
|
||||
var suffixNum = 0;
|
||||
while (newValue >= 1000 && suffixNum < suffixes.length - 1) {
|
||||
newValue /= 1000;
|
||||
@ -161,6 +169,90 @@
|
||||
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(){
|
||||
$.get("/api/stats/summary?fast=true", function(data){
|
||||
|
@ -33,7 +33,7 @@
|
||||
$("#subdList").append(`<tr>
|
||||
<td data-label="">${subd.MatchingDomain}</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>`);
|
||||
});
|
||||
}
|
||||
|
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>
|
||||
<td data-label="">${vdir.Root}</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>`);
|
||||
});
|
||||
}
|
||||
|
@ -145,7 +145,7 @@
|
||||
</div>
|
||||
<div class="ui divider"></div>
|
||||
<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>
|
||||
<br><br>
|
||||
|
||||
|
@ -20,6 +20,9 @@
|
||||
<img class="logo" src="img/logo.svg">
|
||||
</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;">
|
||||
<button class="ui basic icon button" onclick="logout();"><i class="sign-out icon"></i></button>
|
||||
</div>
|
||||
@ -63,8 +66,8 @@
|
||||
<i class="remove icon"></i> HTTP over Websocket
|
||||
</a>
|
||||
<div class="ui divider menudivider">Others</div>
|
||||
<a class="item" tag="">
|
||||
<i class="remove icon"></i> Uptime Monitor
|
||||
<a class="item" tag="utm">
|
||||
<i class="green time icon"></i> Uptime Monitor
|
||||
</a>
|
||||
<a class="item" tag="">
|
||||
<i class="remove icon"></i> Network Tools
|
||||
@ -105,6 +108,9 @@
|
||||
<!-- UPnP based port fowarding -->
|
||||
<div id="upnp" class="functiontab" target="upnp.html"></div>
|
||||
|
||||
<!-- Up Time Monitor -->
|
||||
<div id="utm" class="functiontab" target="uptime.html"></div>
|
||||
|
||||
<!-- Utilities -->
|
||||
<div id="utils" class="functiontab" target="utils.html"></div>
|
||||
</div>
|
||||
@ -207,6 +213,11 @@
|
||||
alert("Invalid tabid given");
|
||||
return;
|
||||
}
|
||||
if (window.innerWidth < 750){
|
||||
//RWD mode, hide toolbar
|
||||
$(".toolbar").fadeOut('fast');
|
||||
}
|
||||
|
||||
$("#mainmenu").find(".item").removeClass("active");
|
||||
$(targetBtn).addClass("active");
|
||||
$(".functiontab").hide();
|
||||
@ -215,6 +226,12 @@
|
||||
window.location.hash = tabID;
|
||||
}
|
||||
|
||||
$(window).on("resize", function(){
|
||||
if (window.innerWidth >= 750 && $(".toolbar").is(":visible") == false){
|
||||
$(".toolbar").show();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</body>
|
||||
|
@ -41,6 +41,7 @@ body{
|
||||
|
||||
.toolbar{
|
||||
width: 240px;
|
||||
min-width: 240px;
|
||||
}
|
||||
|
||||
.contentWindow{
|
||||
@ -48,11 +49,28 @@ body{
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.menutoggle{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 750px) {
|
||||
.toolbar {
|
||||
position: fixed;
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
width: 50%;
|
||||
background-color: white;
|
||||
top: 3.6em;
|
||||
right: 0;
|
||||
height: 100%;
|
||||
margin-bottom: 1em;
|
||||
z-index: 9;
|
||||
padding: 1em;
|
||||
display:none;
|
||||
border-left: 1px solid rgb(206, 206, 206);
|
||||
}
|
||||
|
||||
.menutoggle{
|
||||
display: inline-block !important;
|
||||
}
|
||||
|
||||
#mainmenu{
|
||||
@ -63,6 +81,8 @@ body{
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
.menudivider{
|
||||
@ -95,7 +115,7 @@ body{
|
||||
}
|
||||
|
||||
.statustab{
|
||||
min-height: 5em;
|
||||
min-height: 5.5em;
|
||||
}
|
||||
|
||||
#summaryTotalCount{
|
||||
@ -111,3 +131,40 @@ body{
|
||||
.statustab.summary span, .statustab.summary i{
|
||||
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 class="ui divider"></div>
|
||||
<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>
|
||||
<br><br>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user