mirror of https://github.com/aredn/aredn.git
Improve admin and mesh page refresh (#1509)
* Improve page refresh when browser tab is redisplayed * Improve mesh search query persitance * Improve portable theme messaging
This commit is contained in:
parent
60be6b812a
commit
84824e81c2
|
@ -69,7 +69,7 @@
|
|||
{{_R("selection")}}
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id="main-container">
|
||||
<div id="main-container" hx-get="u-{{request.page}}" hx-trigger="visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
{{_R(request.page)}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -105,7 +105,7 @@
|
|||
{{_R("selection")}}
|
||||
</div>
|
||||
<div id="main">
|
||||
<div id="main-container">
|
||||
<div id="main-container" hx-get="u-{{request.page}}" hx-trigger="visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
{{_R(request.page)}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -178,7 +178,7 @@ if (request.env.REQUEST_METHOD === "DELETE") {
|
|||
<div id="select-theme" class="cols">
|
||||
<div>
|
||||
<div class="o">Theme</div>
|
||||
<div class="m">Display theme and colors</div>
|
||||
<div class="m">Display theme and colors<p></div>
|
||||
</div>
|
||||
<div style="flex:0">
|
||||
{%
|
||||
|
@ -355,7 +355,7 @@ if (request.env.REQUEST_METHOD === "DELETE") {
|
|||
htmx.find("#portable-theme").style.display = "";
|
||||
}
|
||||
else if (j.portableTheme === true) {
|
||||
htmx.find("#select-theme .m").innerHTML = "Display theme and colors seen by others. You see your portable theme.";
|
||||
htmx.find("#select-theme .m").innerHTML = "Display theme and colors seen by others. You see your portable theme when possible.";
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -426,7 +426,7 @@ const po = getPackageOptions();
|
|||
});
|
||||
});
|
||||
htmx.on("#dialog-done", "click", _ => {
|
||||
htmx.ajax("GET", "/a/packages", {
|
||||
htmx.ajax("GET", "/a/u-packages", {
|
||||
swap: "none"
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,35 @@
|
|||
{%
|
||||
/*
|
||||
* Part of AREDN® -- Used for creating Amateur Radio Emergency Data Networks
|
||||
* Copyright (C) 2024 Tim Wilkinson
|
||||
* See Contributors file for additional contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms:
|
||||
*
|
||||
* Additional use restrictions exist on the AREDN® trademark and logo.
|
||||
* See AREDNLicense.txt for more info.
|
||||
*
|
||||
* Attributions to the AREDN® Project must be retained in the source code.
|
||||
* If importing this code into a new or existing project attribution
|
||||
* to the AREDN® project must be added to the source code.
|
||||
*
|
||||
* You must not misrepresent the origin of the material contained within.
|
||||
*
|
||||
* Modified versions must be modified to attribute to the original source
|
||||
* and be marked in reasonable ways as differentiate it from the original
|
||||
* version
|
||||
*/
|
||||
%}
|
||||
{{_R("mesh")}}
|
|
@ -32,6 +32,6 @@
|
|||
* version
|
||||
*/
|
||||
%}
|
||||
div id="packages" hx-swap-oob="innerHTML">
|
||||
<div id="packages" hx-swap-oob="innerHTML">
|
||||
{{_R("packages", "oob")}}
|
||||
</div>
|
|
@ -0,0 +1,35 @@
|
|||
{%
|
||||
/*
|
||||
* Part of AREDN® -- Used for creating Amateur Radio Emergency Data Networks
|
||||
* Copyright (C) 2024 Tim Wilkinson
|
||||
* See Contributors file for additional contributors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation version 3 of the License.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* Additional Terms:
|
||||
*
|
||||
* Additional use restrictions exist on the AREDN® trademark and logo.
|
||||
* See AREDNLicense.txt for more info.
|
||||
*
|
||||
* Attributions to the AREDN® Project must be retained in the source code.
|
||||
* If importing this code into a new or existing project attribution
|
||||
* to the AREDN® project must be added to the source code.
|
||||
*
|
||||
* You must not misrepresent the origin of the material contained within.
|
||||
*
|
||||
* Modified versions must be modified to attribute to the original source
|
||||
* and be marked in reasonable ways as differentiate it from the original
|
||||
* version
|
||||
*/
|
||||
%}
|
||||
{{_R("status")}}
|
|
@ -41,7 +41,7 @@
|
|||
else if (request.args.commit) {
|
||||
pwchanged = configuration.isPasswordChanged();
|
||||
configuration.commitChanges();
|
||||
print(`<div id="main-container" hx-swap-oob="true">${_R(request.page)}</div>`);
|
||||
print(`<div id="main-container" hx-get="u-${request.page}" hx-trigger="visibilitychange[document.visibilityState === 'visible'] from:document" hx-swap-oob="true">${_R(request.page)}</div>`);
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
|
|
@ -47,7 +47,7 @@
|
|||
</div>
|
||||
{% } %}
|
||||
</div>
|
||||
<div id="health" hx-get="health" hx-trigger="every 30s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div id="health" hx-get="u-health" hx-trigger="every 30s [document.visibilityState === 'visible']">
|
||||
{{_R("health")}}
|
||||
</div>
|
||||
{{_R("firmware")}}
|
||||
|
|
|
@ -49,8 +49,15 @@
|
|||
For example, typing "cam" in the box will filter out everything except names containsing "cam" ... which are probably cameras.
|
||||
</p>
|
||||
</div>
|
||||
<div id="meshpage"></div>
|
||||
</div>
|
||||
<script>
|
||||
if (location.search) {
|
||||
const q = location.search.match(/^\?q=(.+)/);
|
||||
if (q) {
|
||||
document.querySelector("input[type=search]").value = q[1];
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{% if (!config.resourcehash) { %}
|
||||
<script src="/a/js/meshpage.js"></script>
|
||||
{% } else { %}
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div id="c2">
|
||||
<div hx-get="messages" hx-trigger="every 300s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div hx-get="u-messages" hx-trigger="every 300s [document.visibilityState === 'visible']">
|
||||
{% if (messages.haveMessages() || (auth.isAdmin && messages.haveToDos())) { %}
|
||||
<div id="messages">
|
||||
{{_R("messages")}}
|
||||
|
@ -58,7 +58,7 @@
|
|||
</div>
|
||||
<div id="local-and-neighbor-devices">
|
||||
<hr>
|
||||
<div hx-get="local-and-neighbor-devices" hx-trigger="every 60s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div hx-get="u-local-and-neighbor-devices" hx-trigger="every 60s [document.visibilityState === 'visible']">
|
||||
{{_R("local-and-neighbor-devices")}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -69,13 +69,13 @@
|
|||
</div>
|
||||
<div id="mesh-summary">
|
||||
<hr>
|
||||
<div hx-get="mesh-summary" hx-trigger="every 120s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div hx-get="u-mesh-summary" hx-trigger="every 120s [document.visibilityState === 'visible']">
|
||||
{{_R("mesh-summary")}}
|
||||
</div>
|
||||
</div>
|
||||
<div id="dhcp">
|
||||
<hr>
|
||||
<div hx-get="dhcp" hx-trigger="every 120s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div hx-get="u-dhcp" hx-trigger="every 120s [document.visibilityState === 'visible']">
|
||||
{{_R("dhcp")}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -88,7 +88,7 @@
|
|||
{% if (fs.access("/usr/bin/wg") || fs.access("/usr/sbin/vtund")) { %}
|
||||
<div id="tunnels">
|
||||
<hr>
|
||||
<div hx-get="tunnels" hx-trigger="every 120s [document.visibilityState === 'visible'], visibilitychange[document.visibilityState === 'visible'] from:document">
|
||||
<div hx-get="u-tunnels" hx-trigger="every 120s [document.visibilityState === 'visible']">
|
||||
{{_R("tunnels")}}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -2,41 +2,55 @@ function render()
|
|||
{
|
||||
|
||||
const search = document.querySelector("#meshfilter input");
|
||||
const page = document.getElementById("meshpage");
|
||||
const help = document.getElementById("meshpage-help");
|
||||
const etx = mesh.etx;
|
||||
const hosts = mesh.hosts;
|
||||
const services = mesh.services;
|
||||
let page = document.getElementById("meshpage");
|
||||
if (!page) {
|
||||
page = document.createElement("div");
|
||||
page.id = "meshpage";
|
||||
document.getElementById("main").appendChild(page);
|
||||
}
|
||||
|
||||
let filtering;
|
||||
let cfilter;
|
||||
function filter()
|
||||
{
|
||||
clearTimeout(filtering);
|
||||
filtering = setTimeout(function() {
|
||||
const filter = search.value.toLowerCase();
|
||||
if (filter === cfilter) {
|
||||
return;
|
||||
}
|
||||
cfilter = filter;
|
||||
const filtered = document.querySelectorAll(".valid");
|
||||
for (let i = 0; i < filtered.length; i++) {
|
||||
filtered[i].classList.remove("valid");
|
||||
}
|
||||
if (filter === "") {
|
||||
page.classList.remove("filtering");
|
||||
filtering = setTimeout(doFilter, 200);
|
||||
}
|
||||
function doFilter() {
|
||||
const filter = search.value.toLowerCase();
|
||||
if (filter === cfilter) {
|
||||
return;
|
||||
}
|
||||
cfilter = filter;
|
||||
if (history) {
|
||||
if (search.value) {
|
||||
history.replaceState(null, "", `${location.origin}${location.pathname}?q=${search.value}`);
|
||||
}
|
||||
else {
|
||||
page.classList.add("filtering");
|
||||
const targets = document.querySelectorAll("[data-search]");
|
||||
for (let i = 0; i < targets.length; i++) {
|
||||
const target = targets[i];
|
||||
if (target.dataset.search.indexOf(filter) !== -1) {
|
||||
target.classList.add("valid");
|
||||
}
|
||||
history.replaceState(null, "", `${location.origin}${location.pathname}`);
|
||||
}
|
||||
}
|
||||
const filtered = document.querySelectorAll(".valid");
|
||||
for (let i = 0; i < filtered.length; i++) {
|
||||
filtered[i].classList.remove("valid");
|
||||
}
|
||||
if (filter === "") {
|
||||
page.classList.remove("filtering");
|
||||
}
|
||||
else {
|
||||
page.classList.add("filtering");
|
||||
const targets = document.querySelectorAll("[data-search]");
|
||||
for (let i = 0; i < targets.length; i++) {
|
||||
const target = targets[i];
|
||||
if (target.dataset.search.indexOf(filter) !== -1) {
|
||||
target.classList.add("valid");
|
||||
}
|
||||
}
|
||||
}, 200);
|
||||
}
|
||||
}
|
||||
search.addEventListener("keyup", filter);
|
||||
search.addEventListener("click", filter);
|
||||
|
@ -110,11 +124,12 @@ for (let i = 0; i < etx.length; i++) {
|
|||
}
|
||||
page.innerHTML = data + "</div>";
|
||||
|
||||
document.querySelector("input[type=search]").focus();
|
||||
doFilter();
|
||||
|
||||
help.addEventListener("click", () => {
|
||||
document.querySelector(".meshpage-help").classList.toggle("visible");
|
||||
});
|
||||
|
||||
document.querySelector("input[type=search]").focus();
|
||||
|
||||
}
|
||||
render();
|
||||
|
|
Loading…
Reference in New Issue