Enhance log display behavior and menu state management
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
@@ -467,6 +467,10 @@ nav p {
|
|||||||
padding: 8px;
|
padding: 8px;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
background: rgba(13, 31, 49, 0.72);
|
background: rgba(13, 31, 49, 0.72);
|
||||||
|
white-space: pre-wrap;
|
||||||
|
overflow-wrap: anywhere;
|
||||||
|
word-break: break-word;
|
||||||
|
line-height: 1.45;
|
||||||
}
|
}
|
||||||
|
|
||||||
#logScreen p {
|
#logScreen p {
|
||||||
@@ -689,6 +693,45 @@ nav p {
|
|||||||
max-height: 96px;
|
max-height: 96px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #clientInfo,
|
||||||
|
body.menu-log-focus .dashboard-cards,
|
||||||
|
body.menu-log-focus #myStreamsBox {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content {
|
||||||
|
padding: 8px;
|
||||||
|
padding-bottom: calc(12px + env(safe-area-inset-bottom));
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content h3 {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content-interaction {
|
||||||
|
top: 8px;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
padding: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content-interaction .search {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content-interaction input[type=button] {
|
||||||
|
min-height: 38px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content_log {
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.menu-log-focus #content_log pre {
|
||||||
|
margin-bottom: 4px;
|
||||||
|
padding: 7px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
.phone {
|
.phone {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,15 +21,22 @@ function showLogs(bottom) {
|
|||||||
var log = new Log();
|
var log = new Log();
|
||||||
var logs = SERVER["log"]["log"];
|
var logs = SERVER["log"]["log"];
|
||||||
var div = document.getElementById("content_log");
|
var div = document.getElementById("content_log");
|
||||||
|
var wrapper = document.getElementById("box-wrapper");
|
||||||
|
var shouldStickToBottom = bottom;
|
||||||
div.innerHTML = "";
|
div.innerHTML = "";
|
||||||
|
if (wrapper != null && shouldStickToBottom == false) {
|
||||||
|
var distanceToBottom = wrapper.scrollHeight - wrapper.scrollTop - wrapper.clientHeight;
|
||||||
|
if (distanceToBottom < 80) {
|
||||||
|
shouldStickToBottom = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
var keys = getObjKeys(logs);
|
var keys = getObjKeys(logs);
|
||||||
keys.forEach(function (logID) {
|
keys.forEach(function (logID) {
|
||||||
var entry = log.createLog(logs[logID]);
|
var entry = log.createLog(logs[logID]);
|
||||||
div.append(entry);
|
div.append(entry);
|
||||||
});
|
});
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (bottom == true) {
|
if (shouldStickToBottom == true && wrapper != null) {
|
||||||
var wrapper = document.getElementById("box-wrapper");
|
|
||||||
wrapper.scrollTop = wrapper.scrollHeight;
|
wrapper.scrollTop = wrapper.scrollHeight;
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
|
|||||||
@@ -895,9 +895,28 @@ function setActiveMenu(menuID) {
|
|||||||
items[i].removeAttribute("aria-current");
|
items[i].removeAttribute("aria-current");
|
||||||
}
|
}
|
||||||
var activeItem = document.getElementById(ACTIVE_MENU_ID);
|
var activeItem = document.getElementById(ACTIVE_MENU_ID);
|
||||||
|
var activeMenuKey = "";
|
||||||
if (activeItem != null) {
|
if (activeItem != null) {
|
||||||
activeItem.classList.add("menu-active");
|
activeItem.classList.add("menu-active");
|
||||||
activeItem.setAttribute("aria-current", "page");
|
activeItem.setAttribute("aria-current", "page");
|
||||||
|
var menuKeyValue = activeItem.getAttribute("data-menu");
|
||||||
|
if (menuKeyValue != null) {
|
||||||
|
activeMenuKey = menuKeyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (document.body != null) {
|
||||||
|
if (activeMenuKey.length > 0) {
|
||||||
|
document.body.setAttribute("data-active-menu", activeMenuKey);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.body.removeAttribute("data-active-menu");
|
||||||
|
}
|
||||||
|
if (activeMenuKey == "log") {
|
||||||
|
document.body.classList.add("menu-log-focus");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
document.body.classList.remove("menu-log-focus");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function renderStatusCards() {
|
function renderStatusCards() {
|
||||||
@@ -989,6 +1008,9 @@ function PageReady() {
|
|||||||
calculateWrapperHeight();
|
calculateWrapperHeight();
|
||||||
}, true);
|
}, true);
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
|
if (document.hidden == true) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
updateLog();
|
updateLog();
|
||||||
}, 10000);
|
}, 10000);
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ var Server = /** @class */ (function () {
|
|||||||
errorState = "idle";
|
errorState = "idle";
|
||||||
}
|
}
|
||||||
finishRequest(errorState, false);
|
finishRequest(errorState, false);
|
||||||
if (WS_AVAILABLE == false) {
|
if (WS_AVAILABLE == false && isLogUpdate == false) {
|
||||||
alert("No websocket connection to xTeVe could be established. Check your network configuration.");
|
alert("No websocket connection to xTeVe could be established. Check your network configuration.");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
|
"sync"
|
||||||
|
|
||||||
"crypto/hmac"
|
"crypto/hmac"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
@@ -29,6 +30,7 @@ var databaseFile = "authentication.json"
|
|||||||
|
|
||||||
var data = make(map[string]any)
|
var data = make(map[string]any)
|
||||||
var tokens = make(map[string]any)
|
var tokens = make(map[string]any)
|
||||||
|
var tokensMu sync.RWMutex
|
||||||
|
|
||||||
var initAuthentication = false
|
var initAuthentication = false
|
||||||
|
|
||||||
@@ -256,20 +258,21 @@ func CheckTheValidityOfTheToken(token string) (newToken string, err error) {
|
|||||||
|
|
||||||
err = createError(011)
|
err = createError(011)
|
||||||
|
|
||||||
|
tokensMu.Lock()
|
||||||
|
defer tokensMu.Unlock()
|
||||||
|
|
||||||
if v, ok := tokens[token]; ok {
|
if v, ok := tokens[token]; ok {
|
||||||
var expires = v.(map[string]any)["expires"].(time.Time)
|
expires := v.(map[string]any)["expires"].(time.Time)
|
||||||
var userID = v.(map[string]any)["id"].(string)
|
|
||||||
|
|
||||||
if expires.Sub(time.Now().Local()) < 0 {
|
if expires.Sub(time.Now().Local()) < 0 {
|
||||||
|
delete(tokens, token)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
newToken = setToken(userID, token)
|
// Keep a stable token per session and only refresh expiration.
|
||||||
|
v.(map[string]any)["expires"] = time.Now().Local().Add(time.Minute * time.Duration(tokenValidity))
|
||||||
|
newToken = token
|
||||||
err = nil
|
err = nil
|
||||||
|
|
||||||
} else {
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -285,11 +288,15 @@ func GetUserID(token string) (userID string, err error) {
|
|||||||
|
|
||||||
err = createError(002)
|
err = createError(002)
|
||||||
|
|
||||||
|
tokensMu.Lock()
|
||||||
|
defer tokensMu.Unlock()
|
||||||
|
|
||||||
if v, ok := tokens[token]; ok {
|
if v, ok := tokens[token]; ok {
|
||||||
var expires = v.(map[string]any)["expires"].(time.Time)
|
expires := v.(map[string]any)["expires"].(time.Time)
|
||||||
userID = v.(map[string]any)["id"].(string)
|
userID = v.(map[string]any)["id"].(string)
|
||||||
|
|
||||||
if expires.Sub(time.Now().Local()) < 0 {
|
if expires.Sub(time.Now().Local()) < 0 {
|
||||||
|
delete(tokens, token)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -558,7 +565,12 @@ func defaultsForNewUser(username, password string) map[string]any {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func setToken(id, oldToken string) (newToken string) {
|
func setToken(id, oldToken string) (newToken string) {
|
||||||
delete(tokens, oldToken)
|
tokensMu.Lock()
|
||||||
|
defer tokensMu.Unlock()
|
||||||
|
|
||||||
|
if oldToken != "-" {
|
||||||
|
delete(tokens, oldToken)
|
||||||
|
}
|
||||||
|
|
||||||
loopToken:
|
loopToken:
|
||||||
newToken = randomString(tokenLength)
|
newToken = randomString(tokenLength)
|
||||||
|
|||||||
72
src/webUI.go
72
src/webUI.go
File diff suppressed because one or more lines are too long
@@ -29,9 +29,18 @@ function showLogs(bottom:boolean) {
|
|||||||
|
|
||||||
var logs = SERVER["log"]["log"]
|
var logs = SERVER["log"]["log"]
|
||||||
var div = document.getElementById("content_log")
|
var div = document.getElementById("content_log")
|
||||||
|
var wrapper = document.getElementById("box-wrapper") as HTMLElement
|
||||||
|
var shouldStickToBottom:boolean = bottom
|
||||||
|
|
||||||
div.innerHTML = ""
|
div.innerHTML = ""
|
||||||
|
|
||||||
|
if (wrapper != null && shouldStickToBottom == false) {
|
||||||
|
var distanceToBottom:number = wrapper.scrollHeight - wrapper.scrollTop - wrapper.clientHeight
|
||||||
|
if (distanceToBottom < 80) {
|
||||||
|
shouldStickToBottom = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var keys = getObjKeys(logs)
|
var keys = getObjKeys(logs)
|
||||||
|
|
||||||
keys.forEach(logID => {
|
keys.forEach(logID => {
|
||||||
@@ -44,9 +53,8 @@ function showLogs(bottom:boolean) {
|
|||||||
|
|
||||||
setTimeout(function(){
|
setTimeout(function(){
|
||||||
|
|
||||||
if (bottom == true) {
|
if (shouldStickToBottom == true && wrapper != null) {
|
||||||
|
|
||||||
var wrapper = document.getElementById("box-wrapper");
|
|
||||||
wrapper.scrollTop = wrapper.scrollHeight;
|
wrapper.scrollTop = wrapper.scrollHeight;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -871,8 +871,27 @@ function setActiveMenu(menuID:string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var activeItem = document.getElementById(ACTIVE_MENU_ID)
|
var activeItem = document.getElementById(ACTIVE_MENU_ID)
|
||||||
|
var activeMenuKey:string = ""
|
||||||
if (activeItem != null) {
|
if (activeItem != null) {
|
||||||
activeItem.classList.add("menu-active")
|
activeItem.classList.add("menu-active")
|
||||||
|
var menuKeyValue = activeItem.getAttribute("data-menu")
|
||||||
|
if (menuKeyValue != null) {
|
||||||
|
activeMenuKey = menuKeyValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (document.body != null) {
|
||||||
|
if (activeMenuKey.length > 0) {
|
||||||
|
document.body.setAttribute("data-active-menu", activeMenuKey)
|
||||||
|
} else {
|
||||||
|
document.body.removeAttribute("data-active-menu")
|
||||||
|
}
|
||||||
|
|
||||||
|
if (activeMenuKey == "log") {
|
||||||
|
document.body.classList.add("menu-log-focus")
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove("menu-log-focus")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -983,6 +1002,9 @@ function PageReady() {
|
|||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
setInterval(function(){
|
setInterval(function(){
|
||||||
|
if (document.hidden == true) {
|
||||||
|
return
|
||||||
|
}
|
||||||
updateLog()
|
updateLog()
|
||||||
}, 10000);
|
}, 10000);
|
||||||
|
|
||||||
|
|||||||
@@ -110,7 +110,7 @@ class Server {
|
|||||||
}
|
}
|
||||||
finishRequest(errorState, false)
|
finishRequest(errorState, false)
|
||||||
|
|
||||||
if (WS_AVAILABLE == false) {
|
if (WS_AVAILABLE == false && isLogUpdate == false) {
|
||||||
alert("No websocket connection to xTeVe could be established. Check your network configuration.")
|
alert("No websocket connection to xTeVe could be established. Check your network configuration.")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user