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:
Toby Chui 2025-03-28 21:24:18 +08:00
parent 3e031605fc
commit 136989f2ea
18 changed files with 152 additions and 126 deletions

View File

@ -42,8 +42,9 @@ type SubscriptionEvent struct {
} }
type RuntimeConstantValue struct { type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"` ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"` ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
} }
/* /*

View File

@ -42,8 +42,9 @@ type SubscriptionEvent struct {
} }
type RuntimeConstantValue struct { type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"` ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"` ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
} }
/* /*

View File

@ -42,8 +42,9 @@ type SubscriptionEvent struct {
} }
type RuntimeConstantValue struct { type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"` ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"` ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
} }
/* /*

View File

@ -1 +1 @@
{"ForwardRules":[{"RuleName":"EarlySpring","PortNumber":2016}],"Enabled":false} {"ForwardRules":[],"Enabled":false}

View File

@ -42,8 +42,9 @@ type SubscriptionEvent struct {
} }
type RuntimeConstantValue struct { type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"` ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"` ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
} }
/* /*

View File

@ -226,9 +226,9 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 5000) parent.msgbox(data.error, false, 5000)
}else{ }else{
msgbox("Network Range Updated") parent.msgbox("Network Range Updated")
} }
} }
}) })
@ -253,7 +253,7 @@
initNetNameAndDesc(); initNetNameAndDesc();
if (object != undefined){ if (object != undefined){
$(object).removeClass("loading"); $(object).removeClass("loading");
msgbox("Network Metadata Updated"); parent.msgbox("Network Metadata Updated");
} }
$("#gannetDetailEdit").slideUp("fast"); $("#gannetDetailEdit").slideUp("fast");
} }
@ -264,7 +264,7 @@
//Get the details of the net //Get the details of the net
$.get("./api/gan/network/name?netid=" + currentGANetID, function(data){ $.get("./api/gan/network/name?netid=" + currentGANetID, function(data){
if (data.error !== undefined){ if (data.error !== undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
$("#gaNetNameInput").val(data[0]); $("#gaNetNameInput").val(data[0]);
$(".ganetName").html(data[0]); $(".ganetName").html(data[0]);
@ -278,7 +278,7 @@
//Get the details of the net //Get the details of the net
$.get("./api/gan/network/list?netid=" + currentGANetID, function(data){ $.get("./api/gan/network/list?netid=" + currentGANetID, function(data){
if (data.error !== undefined){ if (data.error !== undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
currentGaNetDetails = data; currentGaNetDetails = data;
highlightCurrentGANetCIDR(); highlightCurrentGANetCIDR();
@ -299,9 +299,9 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 5000); parent.msgbox(data.error, false, 5000);
}else{ }else{
msgbox("IP removed from member " + memberid) parent.msgbox("IP removed from member " + memberid)
} }
renderMemeberTable(); renderMemeberTable();
} }
@ -331,7 +331,7 @@
} }
if (!isValidIPv4Address(newip)){ 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 return
} }
@ -346,9 +346,9 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 5000); parent.msgbox(data.error, false, 5000);
}else{ }else{
msgbox("IP added to member " + memberid) parent.msgbox("IP added to member " + memberid)
} }
renderMemeberTable(); renderMemeberTable();
} }
@ -482,7 +482,7 @@
function renameMember(targetMemberAddr){ function renameMember(targetMemberAddr){
if (targetMemberAddr == ""){ if (targetMemberAddr == ""){
msgbox("Member address cannot be empty", false, 5000) parent.msgbox("Member address cannot be empty", false, 5000)
return return
} }
@ -498,9 +498,9 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
msgbox("Member Name Updated"); parent.msgbox("Member Name Updated");
} }
renderMemeberTable(true); renderMemeberTable(true);
} }
@ -564,12 +564,12 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
if (isAuthed){ if (isAuthed){
msgbox("Member Authorized"); parent.msgbox("Member Authorized");
}else{ }else{
msgbox("Member Deauthorized"); parent.msgbox("Member Deauthorized");
} }
} }
@ -580,25 +580,26 @@
} }
function handleMemberDelete(addr){ function handleMemberDelete(addr){
if (confirm("Confirm delete member " + addr + " ?")){ parent.confirmBox("Confirm delete member " + addr + " ?", function(choice){
$.cjax({ if (choice){
url: "./api/gan/members/delete", $.cjax({
method: "POST", url: "./api/gan/members/delete",
data: { method: "POST",
netid:currentGANetID, data: {
memid: addr, netid:currentGANetID,
}, memid: addr,
success: function(data){ },
if (data.error != undefined){ success: function(data){
msgbox(data.error, false, 6000); if (data.error != undefined){
}else{ parent.msgbox(data.error, false, 6000);
msgbox("Member Deleted"); }else{
parent.msgbox("Member Deleted");
}
renderMemeberTable(true);
} }
renderMemeberTable(true); });
} }
}); });
}
} }
//Add and remove this controller node to network as member //Add and remove this controller node to network as member
@ -616,13 +617,18 @@
$(".addControllerToNetworkBtn").removeClass("disabled"); $(".addControllerToNetworkBtn").removeClass("disabled");
$(".addControllerToNetworkBtn").removeClass("loading"); $(".addControllerToNetworkBtn").removeClass("loading");
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
msgbox("Controller joint " + currentGANetID); parent.msgbox("Controller joint " + currentGANetID);
} }
setTimeout(function(){ setTimeout(function(){
renderMemeberTable(true); renderMemeberTable(true);
}, 3000) }, 3000)
},
error: function(){
$(".addControllerToNetworkBtn").removeClass("disabled");
$(".addControllerToNetworkBtn").removeClass("loading");
} }
}); });
} }
@ -639,9 +645,9 @@
}, },
success: function(data){ success: function(data){
if (data.error != undefined){ if (data.error != undefined){
msgbox(data.error, false, 6000); parent.msgbox(data.error, false, 6000);
}else{ }else{
msgbox("Controller left " + currentGANetID); parent.msgbox("Controller left " + currentGANetID);
} }
renderMemeberTable(true); renderMemeberTable(true);
$(".removeControllerFromNetworkBtn").removeClass("disabled"); $(".removeControllerFromNetworkBtn").removeClass("disabled");
@ -655,7 +661,7 @@
currentGANetID = ganetId; currentGANetID = ganetId;
$(".ganetID").text(ganetId); $(".ganetID").text(ganetId);
initNetNameAndDesc(ganetId); initNetNameAndDesc(ganetId);
generateIPRangeTable(netRanges);msgbox generateIPRangeTable(netRanges);
initNetDetails(); initNetDetails();
renderMemeberTable(true); renderMemeberTable(true);
@ -676,7 +682,6 @@
} }
//Debug functions //Debug functions
if (typeof(msgbox) == "undefined"){ if (typeof(msgbox) == "undefined"){
msgbox = function(msg, error=false, timeout=3000){ msgbox = function(msg, error=false, timeout=3000){
console.log(msg); console.log(msg);

View File

@ -92,7 +92,7 @@
function handleAddNetwork(){ function handleAddNetwork(){
let networkName = $("#networkName").val().trim(); let networkName = $("#networkName").val().trim();
if (networkName == ""){ if (networkName == ""){
msgbox("Network name cannot be empty", false, 5000); parent.msgbox("Network name cannot be empty", false, 5000);
return; return;
} }
@ -104,7 +104,7 @@
function initGANetID(){ function initGANetID(){
$.get("./api/gan/network/info", function(data){ $.get("./api/gan/network/info", function(data){
if (data.error !== undefined){ if (data.error !== undefined){
msgbox(data.error, false, 5000) parent.msgbox(data.error, false, 5000)
}else{ }else{
if (data != ""){ if (data != ""){
$(".ganControllerID").text(data); $(".ganControllerID").text(data);
@ -121,9 +121,9 @@
data: {}, data: {},
success: function(response) { success: function(response) {
if (response.error != undefined){ if (response.error != undefined){
msgbox(response.error, false, 5000); parent.msgbox(response.error, false, 5000);
}else{ }else{
msgbox("Network added successfully"); parent.msgbox("Network added successfully");
} }
console.log("Network added successfully:", response); console.log("Network added successfully:", response);
listGANet(); listGANet();
@ -141,7 +141,7 @@
$("#GANetList").empty(); $("#GANetList").empty();
if (data.error != undefined){ if (data.error != undefined){
console.log(data.error); 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 //token error or no zerotier found
$(".gansnetworks").addClass("disabled"); $(".gansnetworks").addClass("disabled");
$("#GANetList").append(`<tr> $("#GANetList").append(`<tr>
@ -217,23 +217,28 @@
//Remove the given GANet //Remove the given GANet
function removeGANet(netid){ function removeGANet(netid){
if (confirm("Confirm remove Network " + netid + " PERMANENTLY ?")) //Reusing Zoraxy confirm box
$.cjax({ parent.confirmBox("Confirm remove " + netid + "?", function(choice){
url: "./api/gan/network/remove", if (choice == true){
type: "POST", $.cjax({
dataType: "json", url: "./api/gan/network/remove",
data: { type: "POST",
id: netid, dataType: "json",
}, data: {
success: function(data){ id: netid,
if (data.error != undefined){ },
msgbox(data.error, false, 5000); success: function(data){
}else{ if (data.error != undefined){
msgbox("Net " + netid + " removed"); parent.msgbox(data.error, false, 5000);
} }else{
listGANet(); parent.msgbox("Net " + netid + " removed");
}
listGANet();
}
});
} }
}); });
} }
function openGANetDetails(netid){ function openGANetDetails(netid){

View File

@ -2,6 +2,7 @@ package main
import ( import (
"encoding/json" "encoding/json"
"io/fs"
"net/http" "net/http"
"net/http/pprof" "net/http/pprof"
@ -315,13 +316,20 @@ func initAPIs(targetMux *http.ServeMux) {
}, },
}) })
//Register the standard web services urls // Register the standard web services URLs
fs := http.FileServer(http.FS(webres)) var staticWebRes http.Handler
if DEVELOPMENT_BUILD { 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 //Add a layer of middleware for advance control
advHandler := FSHandler(fs) advHandler := FSHandler(staticWebRes)
targetMux.Handle("/", advHandler) targetMux.Handle("/", advHandler)
//Register the APIs //Register the APIs

View File

@ -97,6 +97,7 @@ var (
path_uuid = flag.String("uuid", "./sys.uuid", "sys.uuid file path") path_uuid = flag.String("uuid", "./sys.uuid", "sys.uuid file path")
path_logFile = flag.String("log", "./log", "Log folder 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_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 */ /* Maintaince Function Flags */
geoDbUpdate = flag.Bool("update_geoip", false, "Download the latest GeoIP data and exit") geoDbUpdate = flag.Bool("update_geoip", false, "Download the latest GeoIP data and exit")

View File

@ -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 PluginGroupsConfig string //The group / tag configuration file, if set the plugin groups will be loaded from this file
/* Runtime */ /* Runtime */
SystemConst *zoraxyPlugin.RuntimeConstantValue SystemConst *zoraxyPlugin.RuntimeConstantValue //The system constant value
CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function CSRFTokenGen func(*http.Request) string `json:"-"` //The CSRF token generator function
Database *database.Database `json:"-"` Database *database.Database `json:"-"`
Logger *logger.Logger `json:"-"` Logger *logger.Logger `json:"-"`
/* Internal */ /* Internal */
pluginGroupsMutex sync.RWMutex //Mutex for the pluginGroups pluginGroupsMutex sync.RWMutex //Mutex for the pluginGroups

View File

@ -42,8 +42,9 @@ type SubscriptionEvent struct {
} }
type RuntimeConstantValue struct { type RuntimeConstantValue struct {
ZoraxyVersion string `json:"zoraxy_version"` ZoraxyVersion string `json:"zoraxy_version"`
ZoraxyUUID string `json:"zoraxy_uuid"` ZoraxyUUID string `json:"zoraxy_uuid"`
DevelopmentBuild bool `json:"development_build"` //Whether the Zoraxy is a development build or not
} }
/* /*

View File

@ -3,7 +3,6 @@ package main
import ( import (
"fmt" "fmt"
"net/http" "net/http"
"net/url"
"os" "os"
"path/filepath" "path/filepath"
"strings" "strings"
@ -23,27 +22,12 @@ import (
func FSHandler(handler http.Handler) http.Handler { func FSHandler(handler http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 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 // 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) { if isHTMLFilePath(r.URL.Path) {
handleInjectHTML(w, r, r.URL.Path) handleInjectHTML(w, r, r.URL.Path)
return return
@ -54,7 +38,7 @@ func FSHandler(handler http.Handler) http.Handler {
// Check authentication // Check authentication
if !authAgent.CheckAuth(r) && requireAuth { if !authAgent.CheckAuth(r) && requireAuth {
http.Redirect(w, r, ppf("/login.html"), http.StatusTemporaryRedirect) http.Redirect(w, r, "/login.html", http.StatusTemporaryRedirect)
return 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 { func isHTMLFilePath(requestURI string) bool {
return strings.HasSuffix(requestURI, ".html") || strings.HasSuffix(requestURI, "/") return strings.HasSuffix(requestURI, ".html") || strings.HasSuffix(requestURI, "/")
} }
@ -136,9 +112,10 @@ func handleInjectHTML(w http.ResponseWriter, r *http.Request, relativeFilepath s
} else { } else {
//Load from embedded fs, require trimming off the prefix slash for relative path //Load from embedded fs, require trimming off the prefix slash for relative path
relativeFilepath = strings.TrimPrefix(relativeFilepath, "/") relativeFilepath = strings.TrimPrefix(relativeFilepath, "/")
relativeFilepath = filepath.ToSlash(filepath.Join("web/", relativeFilepath))
content, err = webres.ReadFile(relativeFilepath) content, err = webres.ReadFile(relativeFilepath)
if err != nil { 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) http.Error(w, "Internal Server Error", http.StatusInternalServerError)
return return
} }

View File

@ -94,7 +94,7 @@ func startupSequence() {
} }
authAgent = auth.NewAuthenticationAgent(SYSTEM_NAME, []byte(sessionKey), sysdb, true, SystemWideLogger, func(w http.ResponseWriter, r *http.Request) { authAgent = auth.NewAuthenticationAgent(SYSTEM_NAME, []byte(sessionKey), sysdb, true, SystemWideLogger, func(w http.ResponseWriter, r *http.Request) {
//Not logged in. Redirecting to login page //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 //Create a TLS certificate manager
@ -305,12 +305,14 @@ func startupSequence() {
/* /*
Plugin Manager Plugin Manager
*/ */
pluginFolder := *path_plugin
pluginFolder = strings.TrimSuffix(pluginFolder, "/")
pluginManager = plugins.NewPluginManager(&plugins.ManagerOptions{ pluginManager = plugins.NewPluginManager(&plugins.ManagerOptions{
PluginDir: "./plugins", PluginDir: pluginFolder,
SystemConst: &zoraxy_plugin.RuntimeConstantValue{ SystemConst: &zoraxy_plugin.RuntimeConstantValue{
ZoraxyVersion: SYSTEM_VERSION, ZoraxyVersion: SYSTEM_VERSION,
ZoraxyUUID: nodeUUID, ZoraxyUUID: nodeUUID,
DevelopmentBuild: DEVELOPMENT_BUILD,
}, },
Database: sysdb, Database: sysdb,
Logger: SystemWideLogger, Logger: SystemWideLogger,

View File

@ -1,6 +1,6 @@
<div class=""> <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> </iframe>
</div> </div>
<script> <script>

View File

@ -308,7 +308,7 @@ function initSelectablePluginList(){
$("#selectablePluginList").append(` $("#selectablePluginList").append(`
<div class="item" style="pointer-events: none; user-select: none; opacity: 0.6;"> <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><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> </div>
`); `);
} }

View File

@ -139,8 +139,8 @@
<table class="ui unstackable very basic celled table"> <table class="ui unstackable very basic celled table">
<thead> <thead>
<tr> <tr>
<th>Country ISO Code</th> <th style="padding: 0.4em;">Country ISO Code</th>
<th>Unique Visitors</th> <th style="padding: 0.4em;">Unique Visitors</th>
</tr> </tr>
</thead> </thead>
<tbody id="countryCodetable"> <tbody id="countryCodetable">
@ -155,8 +155,8 @@
<table class="ui unstackable very basic celled table"> <table class="ui unstackable very basic celled table">
<thead> <thead>
<tr> <tr>
<th>Proxy Type</th> <th style="padding: 0.4em;">Proxy Type</th>
<th>Count</th> <th style="padding: 0.4em;">Count</th>
</tr> </tr>
</thead> </thead>
<tbody id="forwardTypeTable"> <tbody id="forwardTypeTable">
@ -714,6 +714,9 @@
function updateChart() { function updateChart() {
//Do not remove these 3 lines, it will cause memory leak //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[0].data = rxValues;
networkStatisticChart.data.datasets[1].data = txValues; networkStatisticChart.data.datasets[1].data = txValues;
networkStatisticChart.data.labels = timestamps; networkStatisticChart.data.labels = timestamps;

View File

@ -155,6 +155,10 @@ body.darkTheme .ui.table tfoot td {
color: #ffffff !important; 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,
body.darkTheme .ui.input input::placeholder, body.darkTheme .ui.input input::placeholder,
body.darkTheme .ui.input input:focus, 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; 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 */ /* Generic dropdown overwrites */
body.darkTheme .ui.selection.dropdown { body.darkTheme .ui.selection.dropdown {
background-color: var(--theme_bg) !important; background-color: var(--theme_bg) !important;
@ -364,7 +384,7 @@ body.darkTheme .ui.form .grouped.fields label {
/* Confirm Box */ /* Confirm Box */
body.darkTheme .confirmBoxBody { body.darkTheme .confirmBoxBody {
background-color: var(--theme_bg) !important; background-color: var(--text_color_inverted) !important;
color: var(--text_color) !important; color: var(--text_color) !important;
border: 1px solid var(--divider_color) !important; border: 1px solid var(--divider_color) !important;
} }
@ -405,11 +425,11 @@ body.darkTheme .confirmBoxBody .questionToConfirm {
} }
body.darkTheme #confirmBox .ui.top.attached.progress{ 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 { body.darkTheme #confirmBox .ui.top.attached.progress .bar {
background-color: var(--theme_highlight) !important; background-color: var(--buttom_toggle_active) !important;
} }
/* Tour Modal */ /* Tour Modal */

View File

@ -145,7 +145,7 @@ func HandleUptimeMonitorListing(w http.ResponseWriter, r *http.Request) {
if uptimeMonitor != nil { if uptimeMonitor != nil {
uptimeMonitor.HandleUptimeLogRead(w, r) uptimeMonitor.HandleUptimeLogRead(w, r)
} else { } else {
http.Error(w, "500 - Internal Server Error", http.StatusInternalServerError) http.Error(w, "500 - Internal Server Error (Still initializing)", http.StatusInternalServerError)
return return
} }
} }