From a77d219baf49ee49bf9a9e26a1776631b47c0325 Mon Sep 17 00:00:00 2001 From: Rob Emery Date: Tue, 20 Oct 2026 12:09:57 +0100 Subject: [PATCH] Moving the mgmt switch into the bottom section so it applies when the user clicks apply on the specific vlan. In order for this to work when the user is simultaneously changing the vlan that their machine is connected through and the mgmt vlan id, we need to be able to send a batch of commands through to the switch atomically so the switch can process all of them and the momentary disconnection of the machine doesn't matter --- html/app.js | 78 +++++++++++++------------------------------------ html/index.html | 3 ++ 2 files changed, 23 insertions(+), 58 deletions(-) diff --git a/html/app.js b/html/app.js index 52d1ddfa..c40e2d09 100644 --- a/html/app.js +++ b/html/app.js @@ -46,7 +46,7 @@ st_rxb:"RX bad",st_details:"Details",st_counters:"MIB counters",st_nonzero:"non- st_autoref:"auto-refresh",st_counter:"Counter",st_value:"Value",st_fail:"failed to load counters", v_title:"VLANs",v_vid:"VLAN ID",v_members:"Members",v_tagged:"Tagged",v_untagged:"Untagged",v_pvid_on:"PVID on", v_empty:"No VLANs configured.",v_mgmt:"Management VLAN",v_mgmt_none:"untagged",v_editor:"VLAN editor", -v_optional:"optional",v_setmgmt_q:"Set {n} as the management ID?",v_setmgmt_t:"Make this the management VLAN", +v_optional:"optional",v_setmgmt_q:"Set {n} as the management ID?",v_setmgmt_t:"Management VLAN", v_member:"Member",v_pvid:"PVID",v_add:"Add a new VLAN", v_mgmt_c:"WARNING: You must be able to access this VLAN to continue to manage the switch.", v_legend:"U = untagged member, T = tagged member, - = not a member. PVID is automatically assigned based on the untagged membership.", v_accept:"Accept",v_ing_all:"All",v_del_t:"Delete VLAN",v_rename:"Rename",v_rename_t:"Rename VLAN", @@ -840,7 +840,6 @@ function postCmds(list){ list.forEach(function(c){p=p.then(function(){return postCmd(c,true)})}); return p.then(function(){toast(t("t_cmds",{n:list.length}),"ok")}); } - function toast(msg,cls){ var el=h("div",{class:"toast "+(cls||""),text:msg}); $("toasts").appendChild(el); @@ -1519,7 +1518,7 @@ function vlanRefresh() { class: "ctl pri", text: t("v_rename_t"), onclick: function(){ if(!validVlanName($("nvlrename").value)) return; - postCmd(vlan2str(v.id, $("nvlrename").value,mySplit(l.dataset.t),mySplit(l.dataset.u))).then(function(){closeModal();vlanRefresh()}); + postCmd(vlan2str(v.id,$("nvlrename").value,mySplit(l.dataset.t),mySplit(l.dataset.u))).then(function(){closeModal();vlanRefresh()}); } })]); }, @@ -1533,24 +1532,9 @@ function vlanRefresh() { title: t("v_del_t"), style: "margin-left: 5px;", onclick: function() { - confirmModal(t("v_del_q", { - n: v.id - }), t("v_del_d"), function() { + confirmModal(t("v_del_q", { n: v.id }), t("v_del_d"), function() { postCmd("vlan " + v.id + " d").then(vlanRefresh).catch(function() {}); }); - }, - })); - act.appendChild(h("button", { - class: "ctl", - text: "\u2605", - style: "margin-left: 5px;", - title: t("v_setmgmt_t"), - onclick: function() { - confirmModal(t("v_setmgmt_q", { - n: v.id - }), t("v_mgmt_c"), function() { - postCmd("vlan " + v.id + " mgmt").then(vlanRefresh); - }); } })); } @@ -1571,27 +1555,20 @@ function buildVlanEdit() { rP.insertCell().textContent = t("v_pvid"); for (var p = 1; p <= S.n; p++)(function(p) { hd.insertCell().innerHTML = '' + p + ''; - var seg = h("span", { - class: "seg", - id: "vm" + p - }); + var seg = h("span", { class: "seg", id: "vm" + p }); ["-", "U", "T"].forEach(function(s, ix) { seg.appendChild(h("button", { text: s, "data-v": ix, onclick: function() { - seg.querySelectorAll("button").forEach(function(b) { - b.classList.remove("on") - }); + seg.querySelectorAll("button").forEach(function(b) { b.classList.remove("on") }); this.classList.add("on"); } })); }); seg.children[0].classList.add("on"); rM.insertCell().appendChild(seg); - rP.insertCell().appendChild(h("span", { - id: "vp" + p - })); + rP.insertCell().appendChild(h("span", { id: "vp" + p })); })(p); } @@ -1600,9 +1577,7 @@ function segVal(p) { } function segSet(p, v) { - $("vm" + p).querySelectorAll("button").forEach(function(b, i) { - b.classList.toggle("on", i === v) - }); + $("vm" + p).querySelectorAll("button").forEach(function(b, i) { b.classList.toggle("on", i === v) }); } function vlanLoad(vid) { @@ -1623,17 +1598,12 @@ function vlanLoad(vid) { segSet(p, (mem >> bit) & 1 ? (((unt >> bit) & 1) ? 1 : 2) : 0); $("vp" + p).innerText = (!!((pv >> bit) & 1))?"Y":"N"; } - toast(t("v_loaded", { - n: vid - }), "ok"); - }).catch(function() { - toast(t("v_notfound", { - n: vid - }), "err") - }); + $("vmgmtpromote").checked = ($("vmgmtcur").dataset.id == vid); + toast(t("v_loaded", {n: vid}), "ok"); + }).catch(function() {toast(t("v_notfound", {n: vid}), "err")}); } -function vlan2str(i, n, t, u) { +function vlan2str(i, n, t, u){ return ("vlan " + i + (n ? " " + n : "") + " " + t.map((x)=>x+"t").concat(u).join(" ")).trim(); } function pvidcmd(i, p){ @@ -1650,11 +1620,7 @@ function vlanApply() { toast(t("v_vid_err"), "err"); return; } - var top_cmds = [], - tail_cmds = [], - thisVlanInStructure={id:vid, tagged:[], untagged:[]}, - vlansPerPort=[]; - + var top_cmds = [], tail_cmds = [], vlansPerPort=[], thisVlanInStructure={id:vid, tagged:[], untagged:[]}; for (var p = 1; p <= S.n; p++) { var v = segVal(p); vlansPerPort[p]={t:[],u:[]}; @@ -1674,11 +1640,9 @@ function vlanApply() { var rowData = vlanRow.firstChild.firstChild.dataset, rowUntagged = mySplit(rowData.u), rowTagged = mySplit(rowData.t); - if(rowData.id == vid) continue; + if(rowData.id == vid) continue; for(const newVlanPort of thisVlanInStructure.untagged) { - if(rowUntagged.includes(""+newVlanPort)){ - rowUntagged.splice(rowUntagged.indexOf(""+newVlanPort),1); - } + if(rowUntagged.includes(""+newVlanPort)) rowUntagged.splice(rowUntagged.indexOf(""+newVlanPort),1); } for(const rut of rowUntagged) { vlansPerPort[rut].u.push(rowData.id); @@ -1690,21 +1654,19 @@ function vlanApply() { } tail_cmds.push(vlan2str(vid, vname, thisVlanInStructure.tagged, thisVlanInStructure.untagged)); - //park all ports with only tagged membership - for (p in vlansPerPort){ + for (p in vlansPerPort){/*park all ports with only tagged membership*/ if (vlansPerPort[p].u.length == 0 && vlansPerPort[p].t.length > 0) { tail_cmds.push(pvidcmd(0, p)); } } - for(const up of thisVlanInStructure.untagged){ tail_cmds.push(pvidcmd(vid,up)); } - - var cmds = top_cmds.concat(tail_cmds); - console.log(cmds); - - postCmds(cmds).then(vlanRefresh).catch(function() {}).then(function() { + if($("vmgmtpromote").checked){/*must be the last command*/ + tail_cmds.push("vlan " + vid + " mgmt"); + } + var cmd = top_cmds.concat(tail_cmds); + postCmd(cmd.join("\n"),true).then(function(){toast(t("t_cmds",{n:cmd.length}),"ok")}).then(vlanRefresh).catch(function() {}).then(function() { vlanLoad(vid) }); } diff --git a/html/index.html b/html/index.html index 010ffd95..a64a0b0e 100644 --- a/html/index.html +++ b/html/index.html @@ -294,6 +294,9 @@ button.danger{background:var(--bad);color:#fff;border-color:transparent}

VLAN editor

+

U = untagged member, T = tagged member, - = not a member. PVID assigns this VLAN to untagged ingress traffic.