mirror of
https://github.com/tobychui/zoraxy.git
synced 2025-05-30 04:08:38 +02:00
Added plugin dir parameter
- Added plugin dir parameter - Fixed critical architectural bug that effects plugin UI in production mode - Updated implementation of embed FS routing - Minor dark theme update - Fixed ztnc UI bug for msgbox and confirm box
This commit is contained in:
parent
3e031605fc
commit
136989f2ea
@ -42,8 +42,9 @@ type SubscriptionEvent struct {
|
||||
}
|
||||
|
||||
type RuntimeConstantValue struct {
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -42,8 +42,9 @@ type SubscriptionEvent struct {
|
||||
}
|
||||
|
||||
type RuntimeConstantValue struct {
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -42,8 +42,9 @@ type SubscriptionEvent struct {
|
||||
}
|
||||
|
||||
type RuntimeConstantValue struct {
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1 +1 @@
|
||||
{"ForwardRules":[{"RuleName":"EarlySpring","PortNumber":2016}],"Enabled":false}
|
||||
{"ForwardRules":[],"Enabled":false}
|
@ -42,8 +42,9 @@ type SubscriptionEvent struct {
|
||||
}
|
||||
|
||||
type RuntimeConstantValue struct {
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -226,9 +226,9 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 5000)
|
||||
parent.msgbox(data.error, false, 5000)
|
||||
}else{
|
||||
msgbox("Network Range Updated")
|
||||
parent.msgbox("Network Range Updated")
|
||||
}
|
||||
}
|
||||
})
|
||||
@ -253,7 +253,7 @@
|
||||
initNetNameAndDesc();
|
||||
if (object != undefined){
|
||||
$(object).removeClass("loading");
|
||||
msgbox("Network Metadata Updated");
|
||||
parent.msgbox("Network Metadata Updated");
|
||||
}
|
||||
$("#gannetDetailEdit").slideUp("fast");
|
||||
}
|
||||
@ -264,7 +264,7 @@
|
||||
//Get the details of the net
|
||||
$.get("./api/gan/network/name?netid=" + currentGANetID, function(data){
|
||||
if (data.error !== undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
$("#gaNetNameInput").val(data[0]);
|
||||
$(".ganetName").html(data[0]);
|
||||
@ -278,7 +278,7 @@
|
||||
//Get the details of the net
|
||||
$.get("./api/gan/network/list?netid=" + currentGANetID, function(data){
|
||||
if (data.error !== undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
currentGaNetDetails = data;
|
||||
highlightCurrentGANetCIDR();
|
||||
@ -299,9 +299,9 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 5000);
|
||||
parent.msgbox(data.error, false, 5000);
|
||||
}else{
|
||||
msgbox("IP removed from member " + memberid)
|
||||
parent.msgbox("IP removed from member " + memberid)
|
||||
}
|
||||
renderMemeberTable();
|
||||
}
|
||||
@ -331,7 +331,7 @@
|
||||
}
|
||||
|
||||
if (!isValidIPv4Address(newip)){
|
||||
msgbox(newip + " is not a valid IPv4 address", false, 5000)
|
||||
parent.msgbox(newip + " is not a valid IPv4 address", false, 5000)
|
||||
return
|
||||
}
|
||||
|
||||
@ -346,9 +346,9 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 5000);
|
||||
parent.msgbox(data.error, false, 5000);
|
||||
}else{
|
||||
msgbox("IP added to member " + memberid)
|
||||
parent.msgbox("IP added to member " + memberid)
|
||||
}
|
||||
renderMemeberTable();
|
||||
}
|
||||
@ -482,7 +482,7 @@
|
||||
|
||||
function renameMember(targetMemberAddr){
|
||||
if (targetMemberAddr == ""){
|
||||
msgbox("Member address cannot be empty", false, 5000)
|
||||
parent.msgbox("Member address cannot be empty", false, 5000)
|
||||
return
|
||||
}
|
||||
|
||||
@ -498,9 +498,9 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
msgbox("Member Name Updated");
|
||||
parent.msgbox("Member Name Updated");
|
||||
}
|
||||
renderMemeberTable(true);
|
||||
}
|
||||
@ -564,12 +564,12 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
if (isAuthed){
|
||||
msgbox("Member Authorized");
|
||||
parent.msgbox("Member Authorized");
|
||||
}else{
|
||||
msgbox("Member Deauthorized");
|
||||
parent.msgbox("Member Deauthorized");
|
||||
}
|
||||
|
||||
}
|
||||
@ -580,25 +580,26 @@
|
||||
}
|
||||
|
||||
function handleMemberDelete(addr){
|
||||
if (confirm("Confirm delete member " + addr + " ?")){
|
||||
$.cjax({
|
||||
url: "./api/gan/members/delete",
|
||||
method: "POST",
|
||||
data: {
|
||||
netid:currentGANetID,
|
||||
memid: addr,
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
msgbox("Member Deleted");
|
||||
parent.confirmBox("Confirm delete member " + addr + " ?", function(choice){
|
||||
if (choice){
|
||||
$.cjax({
|
||||
url: "./api/gan/members/delete",
|
||||
method: "POST",
|
||||
data: {
|
||||
netid:currentGANetID,
|
||||
memid: addr,
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
parent.msgbox("Member Deleted");
|
||||
}
|
||||
renderMemeberTable(true);
|
||||
}
|
||||
renderMemeberTable(true);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//Add and remove this controller node to network as member
|
||||
@ -616,13 +617,18 @@
|
||||
$(".addControllerToNetworkBtn").removeClass("disabled");
|
||||
$(".addControllerToNetworkBtn").removeClass("loading");
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
msgbox("Controller joint " + currentGANetID);
|
||||
parent.msgbox("Controller joint " + currentGANetID);
|
||||
}
|
||||
setTimeout(function(){
|
||||
renderMemeberTable(true);
|
||||
}, 3000)
|
||||
},
|
||||
error: function(){
|
||||
$(".addControllerToNetworkBtn").removeClass("disabled");
|
||||
$(".addControllerToNetworkBtn").removeClass("loading");
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -639,9 +645,9 @@
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 6000);
|
||||
parent.msgbox(data.error, false, 6000);
|
||||
}else{
|
||||
msgbox("Controller left " + currentGANetID);
|
||||
parent.msgbox("Controller left " + currentGANetID);
|
||||
}
|
||||
renderMemeberTable(true);
|
||||
$(".removeControllerFromNetworkBtn").removeClass("disabled");
|
||||
@ -655,7 +661,7 @@
|
||||
currentGANetID = ganetId;
|
||||
$(".ganetID").text(ganetId);
|
||||
initNetNameAndDesc(ganetId);
|
||||
generateIPRangeTable(netRanges);msgbox
|
||||
generateIPRangeTable(netRanges);
|
||||
initNetDetails();
|
||||
renderMemeberTable(true);
|
||||
|
||||
@ -676,7 +682,6 @@
|
||||
}
|
||||
|
||||
//Debug functions
|
||||
|
||||
if (typeof(msgbox) == "undefined"){
|
||||
msgbox = function(msg, error=false, timeout=3000){
|
||||
console.log(msg);
|
||||
|
@ -92,7 +92,7 @@
|
||||
function handleAddNetwork(){
|
||||
let networkName = $("#networkName").val().trim();
|
||||
if (networkName == ""){
|
||||
msgbox("Network name cannot be empty", false, 5000);
|
||||
parent.msgbox("Network name cannot be empty", false, 5000);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -104,7 +104,7 @@
|
||||
function initGANetID(){
|
||||
$.get("./api/gan/network/info", function(data){
|
||||
if (data.error !== undefined){
|
||||
msgbox(data.error, false, 5000)
|
||||
parent.msgbox(data.error, false, 5000)
|
||||
}else{
|
||||
if (data != ""){
|
||||
$(".ganControllerID").text(data);
|
||||
@ -121,9 +121,9 @@
|
||||
data: {},
|
||||
success: function(response) {
|
||||
if (response.error != undefined){
|
||||
msgbox(response.error, false, 5000);
|
||||
parent.msgbox(response.error, false, 5000);
|
||||
}else{
|
||||
msgbox("Network added successfully");
|
||||
parent.msgbox("Network added successfully");
|
||||
}
|
||||
console.log("Network added successfully:", response);
|
||||
listGANet();
|
||||
@ -141,7 +141,7 @@
|
||||
$("#GANetList").empty();
|
||||
if (data.error != undefined){
|
||||
console.log(data.error);
|
||||
msgbox("Unable to load auth token for GANet", false, 5000);
|
||||
parent.msgbox("Unable to load auth token for GANet", false, 5000);
|
||||
//token error or no zerotier found
|
||||
$(".gansnetworks").addClass("disabled");
|
||||
$("#GANetList").append(`<tr>
|
||||
@ -217,23 +217,28 @@
|
||||
|
||||
//Remove the given GANet
|
||||
function removeGANet(netid){
|
||||
if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?"))
|
||||
$.cjax({
|
||||
url: "./api/gan/network/remove",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {
|
||||
id: netid,
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
msgbox(data.error, false, 5000);
|
||||
}else{
|
||||
msgbox("Net " + netid + " removed");
|
||||
}
|
||||
listGANet();
|
||||
//Reusing Zoraxy confirm box
|
||||
parent.confirmBox("Confirm remove " + netid + "?", function(choice){
|
||||
if (choice == true){
|
||||
$.cjax({
|
||||
url: "./api/gan/network/remove",
|
||||
type: "POST",
|
||||
dataType: "json",
|
||||
data: {
|
||||
id: netid,
|
||||
},
|
||||
success: function(data){
|
||||
if (data.error != undefined){
|
||||
parent.msgbox(data.error, false, 5000);
|
||||
}else{
|
||||
parent.msgbox("Net " + netid + " removed");
|
||||
}
|
||||
listGANet();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
function openGANetDetails(netid){
|
||||
|
16
src/api.go
16
src/api.go
@ -2,6 +2,7 @@ package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
||||
@ -315,13 +316,20 @@ func initAPIs(targetMux *http.ServeMux) {
|
||||
},
|
||||
})
|
||||
|
||||
//Register the standard web services urls
|
||||
fs := http.FileServer(http.FS(webres))
|
||||
// Register the standard web services URLs
|
||||
var staticWebRes http.Handler
|
||||
if DEVELOPMENT_BUILD {
|
||||
fs = http.FileServer(http.Dir("web/"))
|
||||
staticWebRes = http.FileServer(http.Dir("web/"))
|
||||
} else {
|
||||
subFS, err := fs.Sub(webres, "web")
|
||||
if err != nil {
|
||||
panic("Failed to strip 'web/' from embedded resources: " + err.Error())
|
||||
}
|
||||
staticWebRes = http.FileServer(http.FS(subFS))
|
||||
}
|
||||
|
||||
//Add a layer of middleware for advance control
|
||||
advHandler := FSHandler(fs)
|
||||
advHandler := FSHandler(staticWebRes)
|
||||
targetMux.Handle("/", advHandler)
|
||||
|
||||
//Register the APIs
|
||||
|
@ -97,6 +97,7 @@ var (
|
||||
path_uuid = flag.String("uuid", "./sys.uuid", "sys.uuid file path")
|
||||
path_logFile = flag.String("log", "./log", "Log folder path")
|
||||
path_webserver = flag.String("webroot", "./www", "Static web server root folder. Only allow change in start paramters")
|
||||
path_plugin = flag.String("plugin", "./plugins", "Plugin folder path")
|
||||
|
||||
/* Maintaince Function Flags */
|
||||
geoDbUpdate = flag.Bool("update_geoip", false, "Download the latest GeoIP data and exit")
|
||||
|
@ -34,10 +34,10 @@ type ManagerOptions struct {
|
||||
PluginGroupsConfig string //The group / tag configuration file, if set the plugin groups will be loaded from this file
|
||||
|
||||
/* Runtime */
|
||||
SystemConst *zoraxyPlugin.RuntimeConstantValue
|
||||
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
|
||||
Database *database.Database `json:"-"`
|
||||
Logger *logger.Logger `json:"-"`
|
||||
SystemConst *zoraxyPlugin.RuntimeConstantValue //The system constant value
|
||||
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
|
||||
Database *database.Database `json:"-"`
|
||||
Logger *logger.Logger `json:"-"`
|
||||
|
||||
/* Internal */
|
||||
pluginGroupsMutex sync.RWMutex //Mutex for the pluginGroups
|
||||
|
@ -42,8 +42,9 @@ type SubscriptionEvent struct {
|
||||
}
|
||||
|
||||
type RuntimeConstantValue struct {
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
ZoraxyVersion string `json:"zoraxy_version"`
|
||||
ZoraxyUUID string `json:"zoraxy_uuid"`
|
||||
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -3,7 +3,6 @@ package main
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@ -23,27 +22,12 @@ import (
|
||||
|
||||
func FSHandler(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
/*
|
||||
Development Mode Override
|
||||
=> Web root is located in /
|
||||
*/
|
||||
if DEVELOPMENT_BUILD && strings.HasPrefix(r.URL.Path, "/web/") {
|
||||
u, _ := url.Parse(strings.TrimPrefix(r.URL.Path, "/web"))
|
||||
r.URL = u
|
||||
}
|
||||
|
||||
/*
|
||||
Production Mode Override
|
||||
=> Web root is located in /web
|
||||
*/
|
||||
if !DEVELOPMENT_BUILD && r.URL.Path == "/" {
|
||||
//Redirect to web UI
|
||||
http.Redirect(w, r, "/web/", http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
// Allow access to /script/*, /img/pubic/* and /login.html without authentication
|
||||
if strings.HasPrefix(r.URL.Path, ppf("/script/")) || strings.HasPrefix(r.URL.Path, ppf("/img/public/")) || r.URL.Path == ppf("/login.html") || r.URL.Path == ppf("/reset.html") || r.URL.Path == ppf("/favicon.png") {
|
||||
if strings.HasPrefix(r.URL.Path, "/script/") ||
|
||||
strings.HasPrefix(r.URL.Path, "/img/public/") ||
|
||||
r.URL.Path == "/login.html" ||
|
||||
r.URL.Path == "/reset.html" ||
|
||||
r.URL.Path == "/favicon.png" {
|
||||
if isHTMLFilePath(r.URL.Path) {
|
||||
handleInjectHTML(w, r, r.URL.Path)
|
||||
return
|
||||
@ -54,7 +38,7 @@ func FSHandler(handler http.Handler) http.Handler {
|
||||
|
||||
// Check authentication
|
||||
if !authAgent.CheckAuth(r) && requireAuth {
|
||||
http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect)
|
||||
return
|
||||
}
|
||||
|
||||
@ -105,14 +89,6 @@ func FSHandler(handler http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// Production path fix wrapper. Fix the path on production or development environment
|
||||
func ppf(relativeFilepath string) string {
|
||||
if !DEVELOPMENT_BUILD {
|
||||
return strings.ReplaceAll(filepath.Join("/web/", relativeFilepath), "\\", "/")
|
||||
}
|
||||
return relativeFilepath
|
||||
}
|
||||
|
||||
func isHTMLFilePath(requestURI string) bool {
|
||||
return strings.HasSuffix(requestURI, ".html") || strings.HasSuffix(requestURI, "/")
|
||||
}
|
||||
@ -136,9 +112,10 @@ func handleInjectHTML(w http.ResponseWriter, r *http.Request, relativeFilepath s
|
||||
} else {
|
||||
//Load from embedded fs, require trimming off the prefix slash for relative path
|
||||
relativeFilepath = strings.TrimPrefix(relativeFilepath, "/")
|
||||
relativeFilepath = filepath.ToSlash(filepath.Join("web/", relativeFilepath))
|
||||
content, err = webres.ReadFile(relativeFilepath)
|
||||
if err != nil {
|
||||
SystemWideLogger.Println("load embedded web file failed: ", err)
|
||||
SystemWideLogger.Println("Load embedded web file failed: ", err)
|
||||
http.Error(w, "Internal Server Error", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
12
src/start.go
12
src/start.go
@ -94,7 +94,7 @@ func startupSequence() {
|
||||
}
|
||||
authAgent = auth.NewAuthenticationAgent(SYSTEM_NAME, []byte(sessionKey), sysdb, true, SystemWideLogger, func(w http.ResponseWriter, r *http.Request) {
|
||||
//Not logged in. Redirecting to login page
|
||||
http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect)
|
||||
http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect)
|
||||
})
|
||||
|
||||
//Create a TLS certificate manager
|
||||
@ -305,12 +305,14 @@ func startupSequence() {
|
||||
/*
|
||||
Plugin Manager
|
||||
*/
|
||||
|
||||
pluginFolder := *path_plugin
|
||||
pluginFolder = strings.TrimSuffix(pluginFolder, "/")
|
||||
pluginManager = plugins.NewPluginManager(&plugins.ManagerOptions{
|
||||
PluginDir: "./plugins",
|
||||
PluginDir: pluginFolder,
|
||||
SystemConst: &zoraxy_plugin.RuntimeConstantValue{
|
||||
ZoraxyVersion: SYSTEM_VERSION,
|
||||
ZoraxyUUID: nodeUUID,
|
||||
ZoraxyVersion: SYSTEM_VERSION,
|
||||
ZoraxyUUID: nodeUUID,
|
||||
DevelopmentBuild: DEVELOPMENT_BUILD,
|
||||
},
|
||||
Database: sysdb,
|
||||
Logger: SystemWideLogger,
|
||||
|
@ -1,6 +1,6 @@
|
||||
<div class="">
|
||||
<iframe id="pluginContextLoader" src="" style="width: 100%; border: none;">
|
||||
|
||||
<iframe id="pluginContextLoader" src="" style="width: 100%; border: none;" allow="scripts" sandbox="allow-scripts allow-same-origin">
|
||||
|
||||
</iframe>
|
||||
</div>
|
||||
<script>
|
||||
|
@ -308,7 +308,7 @@ function initSelectablePluginList(){
|
||||
$("#selectablePluginList").append(`
|
||||
<div class="item" style="pointer-events: none; user-select: none; opacity: 0.6;">
|
||||
<p><i class="ui green circle check icon"></i> No plugins available to assign</p>
|
||||
<p>Plugins can be installed to Zoraxy by placing the plugin files in the <code>./plugins/{plugin_name}/</code> directory.</p>
|
||||
<p>Plugins can be installed to Zoraxy by placing the plugin files in the plugins directory.</p>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
@ -139,8 +139,8 @@
|
||||
<table class="ui unstackable very basic celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Country ISO Code</th>
|
||||
<th>Unique Visitors</th>
|
||||
<th style="padding: 0.4em;">Country ISO Code</th>
|
||||
<th style="padding: 0.4em;">Unique Visitors</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="countryCodetable">
|
||||
@ -155,8 +155,8 @@
|
||||
<table class="ui unstackable very basic celled table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Proxy Type</th>
|
||||
<th>Count</th>
|
||||
<th style="padding: 0.4em;">Proxy Type</th>
|
||||
<th style="padding: 0.4em;">Count</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="forwardTypeTable">
|
||||
@ -714,6 +714,9 @@
|
||||
|
||||
function updateChart() {
|
||||
//Do not remove these 3 lines, it will cause memory leak
|
||||
if (typeof(networkStatisticChart) == "undefined"){
|
||||
return;
|
||||
}
|
||||
networkStatisticChart.data.datasets[0].data = rxValues;
|
||||
networkStatisticChart.data.datasets[1].data = txValues;
|
||||
networkStatisticChart.data.labels = timestamps;
|
||||
|
@ -155,6 +155,10 @@ body.darkTheme .ui.table tfoot td {
|
||||
color: #ffffff !important;
|
||||
}
|
||||
|
||||
body.darkTheme .ui.table thead th{
|
||||
background-color: var(--table_header_color);
|
||||
}
|
||||
|
||||
body.darkTheme .ui.input input,
|
||||
body.darkTheme .ui.input input::placeholder,
|
||||
body.darkTheme .ui.input input:focus,
|
||||
@ -223,6 +227,22 @@ body.darkTheme .ui.checkbox:not(.toggle) input[type="checkbox"]{
|
||||
border: 1px solid var(--button_border_color) !important;
|
||||
}
|
||||
|
||||
/* message box */
|
||||
body.darkTheme #messageBox i{
|
||||
color: var(--text_color) !important;
|
||||
}
|
||||
body.darkTheme #messageBox.ui.green.message {
|
||||
background-color: #1ebc30 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
body.darkTheme #messageBox.ui.red.message {
|
||||
background-color: #db2828 !important;
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Generic dropdown overwrites */
|
||||
body.darkTheme .ui.selection.dropdown {
|
||||
background-color: var(--theme_bg) !important;
|
||||
@ -364,7 +384,7 @@ body.darkTheme .ui.form .grouped.fields label {
|
||||
/* Confirm Box */
|
||||
|
||||
body.darkTheme .confirmBoxBody {
|
||||
background-color: var(--theme_bg) !important;
|
||||
background-color: var(--text_color_inverted) !important;
|
||||
color: var(--text_color) !important;
|
||||
border: 1px solid var(--divider_color) !important;
|
||||
}
|
||||
@ -405,11 +425,11 @@ body.darkTheme .confirmBoxBody .questionToConfirm {
|
||||
}
|
||||
|
||||
body.darkTheme #confirmBox .ui.top.attached.progress{
|
||||
background-color: var(--theme_bg_secondary) !important;
|
||||
background-color: var(--theme_highlight) !important;
|
||||
}
|
||||
|
||||
body.darkTheme #confirmBox .ui.top.attached.progress .bar {
|
||||
background-color: var(--theme_highlight) !important;
|
||||
background-color: var(--buttom_toggle_active) !important;
|
||||
}
|
||||
|
||||
/* Tour Modal */
|
||||
|
@ -145,7 +145,7 @@ func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) {
|
||||
if uptimeMonitor != nil {
|
||||
uptimeMonitor.HandleUptimeLogRead(w, r)
|
||||
} else {
|
||||
http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError)
|
||||
http.Error(w, "500 - Internal Server Error (Still initializing)", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user