summaryrefslogtreecommitdiff
path: root/app.js
diff options
context:
space:
mode:
authorMarin Ivanov <[email protected]>2024-08-21 00:04:40 +0300
committerMarin Ivanov <[email protected]>2024-08-21 00:04:40 +0300
commit57bebd16ff7e89bfe5e9089ac4c0a21733675f22 (patch)
tree4a3ebefba3e584d956f704f04d9d37e7f8fc87eb /app.js
parent869c09a0ed7e7c1fa6a4376cf9acf06e7fecc874 (diff)
config and setting fields
Diffstat (limited to 'app.js')
-rw-r--r--app.js160
1 files changed, 94 insertions, 66 deletions
diff --git a/app.js b/app.js
index ddbb66b..a74104c 100644
--- a/app.js
+++ b/app.js
@@ -1,5 +1,7 @@
(() => {
- let isLoading = 0;
+ state = {};
+ isLoading = 0;
+
const loading = (val) => {
isLoading = val;
loader.$cls(isLoading ? "" : "hidden");
@@ -7,44 +9,56 @@
loader.$click(() => loading(0));
let error = null;
- function errClose() {
- error = null;
- app.reload();
- }
- let data = {};
- function onerror(err) {
- error = err;
- console.error(err);
+ setError = (err) => {
+ error = String(err);
app.reload();
}
- function parsedata(r) {
- return Object.fromEntries(r.split("\n").map(x=>x.trim()).filter(x=>x).map(x=>x.split('=')));
+ function errClose() {
}
- function cmd(url, body) {
- return fetch(url, {method:body?'POST':'GET', body})
- .then(r => {
- if (!r.ok){
- throw new Error(r.statusText);
- }
- return r.text();
- })
- .then(r => parsedata(r));
- };
- function loadconfig() {
+ window.onerror = (message, source, lineNumber, colno, err) => {
+ setError(message);
+ };
+ window.onunhandledrejection = (event) => {
+ setError(event.reason);
+ };
+ let parseini = (data) => Object.fromEntries(data.split("\n").map(x=>x.trim()).filter(x=>x).map(x=>x.split("=")));
+ let buildini = (data, prefix="") => entries(data).map(([k,v])=>`${prefix}${k}=${v}\n`).join();
+ let resptext = r => {
+ if (!r.ok){
+ throw new Error(r.statusText);
+ }
+ return r.text();
+ };
+ getconfig = () => fetch("/cgi-bin/getconfig").then(resptext).then(x => parseini(x));
+ cmd = (body) => fetch("/cgi-bin/cmd",{method:"POST",body}).then(resptext);
+ setconfig = (data, prefix) => {
loading(1);
- cmd("/cgi-bin/getconfig")
+ cmd(buildini(data, prefix)+"save\n")
+ .finally(() => loading(0))
+ };
+ loadconfig = () => {
+ loading(1);
+ getconfig("/cgi-bin/getconfig")
.then(x => {
- data = x;
+ state = {...state, ...x};
app.reload();
})
- .catch(onerror)
- .then(() => loading(0))
- }
- function saveconfig(groups) {
- cmd("/cgi-bin/setconfig", data)
- .catch(onerror)
- .then(loadconfig)
+ .finally(() => loading(0));
}
+ reboot = (data, prefix) => {
+ var ok = 0;
+ loading(1);
+ cmd("reboot\n")
+ .then(() => {
+ ok = 1;
+ })
+ .finally(() => {
+ setTimeout(() => {
+ loading(0);
+ app.reload();
+ }, ok?10000:0);
+ })
+ };
function CErr(text) {
var el = div(
@@ -72,52 +86,64 @@
return routes[r]();
}
}
+
+ function CSettingInput(f) {
+ var inp = input("text")
+ .$attr("id","form__"+f.id)
+ .$attr("name",f.id)
+ .$attr("required",!!f.required)
+ .$value(state[f.id]??null)
+ .$change2state(state, f.id);
+ if (f.pattern) {
+ inp.$attr("pattern", f.pattern??null);
+ }
+ if (f.invalidmsg) {
+ inp.oninvalid = () => inp.setCustomValidity(f.invalidmsg);
+ }
+ inp.$attr("placeholder", f.hint??"");
+ return tr(
+ td(labelfor(inp.id, f.title)).$cls("title"),
+ td(inp),
+ );
+ }
+
+ function CSettings(section) {
+ let s = config.sections[section];
+ let form_ = form(
+ table(...s.fields.map(x => CSettingInput(x))).$cls("settings"),
+ input("submit").$value("Save")
+ );
+ form_.onsubmit = (e) => {e.preventDefault(); setconfig({});}
+ return div(
+ h1(s.title),
+ form_,
+ )
+ }
+
const navbar = CNav([
["#", "Home"],
- ["#/network", "Network"],
- ["#/config", "Configuration"],
- ["#/tools", "Tools"],
+ ...entries(config.sections).map(([id, x]) => [`#/${id}`, x.title]),
]);
const router = CRouter({
"/": () => div(
- h2("Lorem Ipsum"),
- p("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. "),
- p("Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."),
- ),
- "/network": () => div(
- h1("Network settings"),
+ h1("Information"),
table(
- tr(
- td("IP"),
- td(input("text").$value(data["cfg.ip"])),
- ),
- tr(
- td("MAC"),
- td(
- input("text").$value(data["cfg.mac"])
- .$change2state(data, "cfg.mac")
- ),
- )
- ).$cls("network"),
- input("button").$value("Save").$click(saveconfig)
+ tr(td("Device:").$cls("title"), td(config.device)),
+ tr(td("Software Version:").$cls("title"), td(config.swVersion)),
+ tr(td("Hardware Version:").$cls("title"), td(config.hwVersion)),
+ ),
+ h1("Controls"),
+ p(
+ button("Reboot").$click(reboot),
+ ).$cls("center"),
),
- "/config": () => {
- return div();
- },
- "/waiting": () => {
- loading(1);
- setTimeout(() => {
- loading(0);
- }, 3000);
- return div("");
- },
+ ...Object.fromEntries(entries(config.sections).map(([id, _]) => [`/${id}`, () => CSettings(id)])),
"": () => div(
h1("Not Found"),
p("The requested page is not available.")
),
});
-
- mount(app, (h) => {
+ CApp = (h) => {
loading(isLoading);
return [
div(error && CErr(String(error))),
@@ -126,6 +152,8 @@
section(router(h))
),
];
- });
+ };
+
+ mount(app, CApp);
loadconfig();
})()