tabbed view in UI, config categories

This commit is contained in:
andreas 2021-11-06 17:56:57 +01:00
parent 62151f9c3c
commit 5ec4dbcecf
2 changed files with 191 additions and 74 deletions

View File

@ -5,7 +5,8 @@
"type": "string",
"default": "ESP32NMEA2K",
"check": "checkSystemName",
"description": "system name, used for the access point and for services"
"description": "system name, used for the access point and for services",
"category":"system"
},
{
"name":"talkerId",
@ -13,7 +14,16 @@
"type":"list",
"default":"GP",
"list":["AB","AD","AG","AP","AI","AN","AR","AS","AT","AX","BI","BN","CA","CD","CR","CS","CT","CV","CX","DF","DU","DP","EC","EI","EP","ER","FD","FE","FR","FS","GA","GB","GI","GL","GN","GP","GQ","HC","HE","HF","HN","HD","HS","II","IN","JA","JB","JC","JD","JE","JF","JG","JH","LC","NL","NV","RA","RB","RC","RI","SA","SC","SD","SG","SN","SS","TC","TI","UP","VD","VM","VW","VA","VS","VT","VR","WD","WI","WL","YX","ZA","ZC","ZQ","ZV"],
"description":"the talkerId used in generated NMEA0183 records"
"description":"the talkerId used in generated NMEA0183 records",
"category":"system"
},
{
"name": "stopApTime",
"type": "number",
"default": "0",
"check": "checkStopApTime",
"description": "stop the access point after that many minutes if not used",
"category":"system"
},
{
"name": "usbBaud",
@ -21,42 +31,48 @@
"type": "list",
"default": "115200",
"description": "baud rate for the USB port",
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800]
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
"category":"usb port"
},
{
"name": "sendUsb",
"label": "NMEA to USB",
"type": "boolean",
"default": "true",
"description": "send out NMEA data on the USB port"
"description": "send out NMEA data on the USB port",
"category":"usb port"
},
{
"name": "receiveUsb",
"label": "NMEA from USB",
"type": "boolean",
"default": "true",
"description": "receive NMEA data on the USB port"
"description": "receive NMEA data on the USB port",
"category":"usb port"
},
{
"name": "usbToN2k",
"label": "USB to NMEA2000",
"type": "boolean",
"default": "true",
"description": "convert NMEA0183 from the USB port to NMEA2000"
"description": "convert NMEA0183 from the USB port to NMEA2000",
"category":"usb port"
},
{
"name": "usbReadFilter",
"label": "USB read Filter",
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
"description": "filter for NMEA0183 data when reading from USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"category":"usb port"
},
{
"name": "usbWriteFilter",
"label": "USB write Filter",
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
"description": "filter for NMEA0183 data when writing to USB\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"category":"usb port"
},
{
"name": "serialDirection",
@ -65,7 +81,8 @@
"default": "receive",
"list": ["send","receive","off"],
"description": "use the serial port to send or receive data",
"capabilities":{"serialmode":["UNI"]}
"capabilities":{"serialmode":["UNI"]},
"category":"serial port"
},
{
"name": "serialBaud",
@ -74,7 +91,8 @@
"default": "115200",
"description": "baud rate for the serial port",
"list": [1200,2400,4800,9600,14400,19200,28800,38400,57600,115200,230400,460800],
"capabilities":{"serialmode":["RX","TX","UNI","BI"]}
"capabilities":{"serialmode":["RX","TX","UNI","BI"]},
"category":"serial port"
},
{
"name": "sendSerial",
@ -82,7 +100,8 @@
"type": "boolean",
"default": "true",
"description": "send out NMEA data on the serial port",
"capabilities":{"serialmode":["TX","BI"]}
"capabilities":{"serialmode":["TX","BI"]},
"category":"serial port"
},
{
"name": "receiveSerial",
@ -90,7 +109,8 @@
"type": "boolean",
"default": "true",
"description": "receive NMEA data on the serial port",
"capabilities":{"serialmode":["RX","BI"]}
"capabilities":{"serialmode":["RX","BI"]},
"category":"serial port"
},
{
"name": "serialToN2k",
@ -98,7 +118,8 @@
"type": "boolean",
"default": "true",
"description": "convert NMEA0183 from the serial port to NMEA2000",
"capabilities":{"serialmode":["RX","BI","UNI"]}
"capabilities":{"serialmode":["RX","BI","UNI"]},
"category":"serial port"
},
{
"name": "serialReadFilter",
@ -106,7 +127,8 @@
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when reading from serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"capabilities":{"serialmode":["RX","BI","UNI"]}
"capabilities":{"serialmode":["RX","BI","UNI"]},
"category":"serial port"
},
{
"name": "serialWriteFilter",
@ -114,14 +136,16 @@
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when writing to serial\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"capabilities":{"serialmode":["TX","BI","UNI"]}
"capabilities":{"serialmode":["TX","BI","UNI"]},
"category":"serial port"
},
{
"name": "serverPort",
"label": "TCP port",
"type": "number",
"default": "2222",
"description": "the TCP port we listen on"
"description": "the TCP port we listen on",
"category":"TCP port"
},
{
"name": "maxClients",
@ -129,63 +153,72 @@
"type": "number",
"default": "10",
"check":"checkMaxClients",
"description": "the number of clients we allow to connect to us"
"description": "the number of clients we allow to connect to us",
"category":"TCP port"
},
{
"name": "sendTCP",
"label": "NMEA to TCP",
"type": "boolean",
"default": "true",
"description": "send out NMEA data to connected TCP clients"
"description": "send out NMEA data to connected TCP clients",
"category":"TCP port"
},
{
"name": "readTCP",
"label": "NMEA from TCP",
"type": "boolean",
"default": "true",
"description": "receive NMEA data from connected TCP clients"
"description": "receive NMEA data from connected TCP clients",
"category":"TCP port"
},
{
"name": "tcpToN2k",
"label": "TCP to NMEA2000",
"type": "boolean",
"default": "true",
"description": "convert NMEA0183 from TCP clients to NMEA2000"
"description": "convert NMEA0183 from TCP clients to NMEA2000",
"category":"TCP port"
},
{
"name": "tcpReadFilter",
"label": "TCP read Filter",
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
"description": "filter for NMEA0183 data when reading from TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"category":"TCP port"
},
{
"name": "tcpWriteFilter",
"label": "TCP write Filter",
"type": "filter",
"default": "",
"description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB"
"description": "filter for NMEA0183 data when writing to TCP\nselect aison|aisoff, set a whitelist or a blacklist with NMEA sentences like RMC,RMB",
"category":"TCP port"
},
{
"name": "sendSeasmart",
"label": "Seasmart to TCP",
"type": "boolean",
"default": "false",
"description": "send NMEA2000 as seasmart to connected TCP clients"
"description": "send NMEA2000 as seasmart to connected TCP clients",
"category":"TCP port"
},
{
"name": "wifiClient",
"label": "wifi client",
"type": "boolean",
"default": "false",
"description": "connect to an external WIFI network"
"description": "connect to an external WIFI network",
"category":"wifi client"
},
{
"name": "wifiPass",
"label": "wifi client password",
"type": "password",
"default": "",
"description": "the password for an external WIFI network"
"description": "the password for an external WIFI network",
"category":"wifi client"
},
{
"name": "wifiSSID",
@ -193,14 +226,8 @@
"type": "string",
"default": "",
"check": "checkSSID",
"description": "the SSID for an external WIFI network"
},
{
"name": "stopApTime",
"type": "number",
"default": "0",
"check": "checkStopApTime",
"description": "stop the access point after that many minutes if not used"
"description": "the SSID for an external WIFI network",
"category":"wifi client"
}

View File

@ -8,6 +8,13 @@
let self=this;
let lastUpdate=(new Date()).getTime();
let reloadConfig=false;
function addEl(type,clazz,parent,text){
let el=document.createElement(type);
el.classList.add(clazz);
if (text) el.textContent=text;
if (parent)parent.appendChild(el);
return el;
}
function alertRestart(){
reloadConfig=true;
alert("Board reset triggered, reconnect WLAN if necessary");
@ -265,12 +272,29 @@
.then(function (capabilities) {
getJson("config.json")
.then(function (defs) {
let category;
let categoryEl;
let frame = document.querySelector('.configFormRows');
if (!frame) throw Error("no config form");
frame.innerHTML = '';
configDefinitions = defs;
defs.forEach(function (item) {
if (!item.type) return;
if (item.category != category || ! categoryEl){
let categoryFrame=addEl('div','category',frame);
let categoryTitle=addEl('div','title',categoryFrame);
let categoryButton=addEl('button','categoryButton',categoryTitle,'v');
addEl('span','label',categoryTitle,item.category);
categoryEl=addEl('div','content',categoryFrame);
categoryEl.classList.add('hidden');
let currentEl=categoryEl;
categoryTitle.addEventListener('click',function(ev){
let rs=currentEl.classList.toggle('hidden');
if (rs) categoryButton.textContent="v";
else categoryButton.textContent="^";
})
category=item.category;
}
if (item.capabilities !== undefined){
for (let capability in item.capabilities){
let values=item.capabilities[capability];
@ -282,16 +306,10 @@
if (! found) return;
}
}
let row = document.createElement('div');
row.classList.add('row');
let row = addEl('div','row',categoryEl);
let label = item.label || item.name;
let labelEl = document.createElement('span');
labelEl.classList.add('label');
labelEl.textContent = label;
row.appendChild(labelEl);
let valueFrame=document.createElement("div");
valueFrame.classList.add("value");
row.appendChild(valueFrame);
addEl('span','label',row,label);
let valueFrame=addEl('div','value',row);
let valueEl = createInput(item,valueFrame);
if (!valueEl) return;
valueEl.setAttribute('data-default', item.default);
@ -300,27 +318,18 @@
checkChange(el,row);
})
if (item.check) valueEl.setAttribute('data-check', item.check);
let btContainer=document.createElement("div");
btContainer.classList.add("buttonContainer");
row.appendChild(btContainer);
let bt = document.createElement('button');
bt.classList.add('defaultButton');
let btContainer=addEl('div','buttonContainer',row);
let bt = addEl('button','defaultButton',btContainer,'X');
bt.setAttribute('data-default', item.default);
bt.addEventListener('click', function (ev) {
valueEl.value = valueEl.getAttribute('data-default');
let changeEvent=new Event('change');
valueEl.dispatchEvent(changeEvent);
})
bt.textContent = "X";
btContainer.appendChild(bt);
bt = document.createElement('button');
bt.classList.add('infoButton');
bt = addEl('button','infoButton',btContainer,'?');
bt.addEventListener('click', function (ev) {
showOverlay(item.description);
});
bt.textContent = "?";
btContainer.appendChild(bt);
frame.appendChild(row);
})
resetForm();
})
@ -339,6 +348,22 @@
showOverlay(text,true);
});
}
function handleTab(el){
let activeName=el.getAttribute('data-page');
if (! activeName) return;
let activeTab=document.getElementById(activeName);
if (!activeTab) return;
let all=document.querySelectorAll('.tabPage');
for (let i=0;i<all.length;i++){
all[i].classList.add('hidden');
}
let tabs=document.querySelectorAll('.tab');
for (let i=0;i<all.length;i++){
tabs[i].classList.remove('active');
}
el.classList.add('active');
activeTab.classList.remove('hidden');
}
window.setInterval(update,1000);
window.addEventListener('load',function(){
let buttons=document.querySelectorAll('button');
@ -350,17 +375,31 @@
cd.addEventListener('change',function(ev){
showCanDetails(ev.target.checked);
});
let tabs=document.querySelectorAll('.tab');
for (let i=0;i<tabs.length;i++){
tabs[i].addEventListener('click',function(ev){
handleTab(ev.target);
});
}
loadConfigDefinitions();
});
</script>
<style type="text/css">
.configForm {
margin-top: 1em;
margin-bottom: 1em;
padding-top: 0.5em;
padding-bottom: 0.5em;
border: 1px solid grey;
max-width: 40em;
}
.configForm .buttons {
margin-top: 0.5em;
}
.configForm .content>div:nth-child(even) {
background-color: rgb(211 211 211 / 43%);
}
#statusPage .even {
background-color: rgb(211 211 211 / 43%);
}
.category .title .label {
opacity: 1;
margin-left: 1em;
}
.changed input{
color: green
@ -373,11 +412,13 @@ span.label {
display: inline-block;
opacity: 0.6;
}
.value {
width: 19em;
.configForm .value {
width: 21em;
display: flex;
flex-direction: row;
margin-bottom: 0.2em;
}
span#connected {
display: inline-block;
background-color: red;
@ -389,11 +430,16 @@ span#connected.ok{
background-color: #13ac13;
}
.row {
margin: 0.5em;
padding: 0.5em;
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
input,select {
border: 1px solid #808080a1;
font-size: 0.9em;
padding: 0.2em;
}
.filter {
display: inline-block;
}
@ -404,6 +450,16 @@ button.infoButton {
margin-left: 1em;
vertical-align: bottom;
}
.category .title {
padding-left: 0.5em;
background-color: lightgray;
padding-top: 0.3em;
padding-bottom: 0.5em;
border-bottom: 1px solid darkgray;
}
.hidden{
display: none !important;
}
#canDetails{
display:none;
}
@ -420,9 +476,7 @@ button.infoButton {
background-color: #80808070;
display: flex;
}
.overlayContainer.hidden{
display: none;
}
div#overlay {
margin: auto;
background-color: white;
@ -443,21 +497,56 @@ div#overlayContent.text{
flex-direction: row;
justify-content: end;
}
#tabs {
display: flex;
border-bottom: 1px solid grey;
margin-bottom: 0.5em;
}
#tabs .tab {
background-color: lightgray;
padding: 0.5em;
border-left: 1px;
border-right: 1px;
border-top: 1px;
border-bottom: 1px;
border-color: grey;
border-style: solid;
opacity: 0.6;
}
#tabs .tab.active{
opacity: 1;
}
.buttons button{
padding: 0.5em;
}
button#reset{
padding: 0.5em;
}
h1{
margin-bottom: 0;
}
</style>
</head>
<body>
<div class="main">
<h1>NMEA 2000 Gateway </h1>
<div class="row">
<span class="label">connected</span>
<span class="value" id="connected"></span>
</div>
<div id="tabs">
<div class="tab active" data-page="statusPage">Status</div>
<div class="tab" data-page="configPage">Config</div>
</div>
<div id="statusPage" class="tabPage">
<div class="row">
<span class="label">VERSION</span>
<span class="value" id="version">---</span>
<button class="infoButton" id="converterInfo">?</button>
</div>
<div class="row">
<span class="label">connected</span>
<span class="value" id="connected"></span>
</div>
<div class="row">
<div class="row even">
<span class="label">Access Point IP</span>
<span class="value" id="apIp">---</span>
</div>
@ -465,19 +554,19 @@ div#overlayContent.text{
<span class="label"># NMEA2000 messages</span>
<span class="value" id="numcan">---</span>
</div>
<div class="row">
<div class="row even">
<span class="label">NMEA2000 details</span>
<input type="checkbox" id="showCanDetails"></span>
</div>
<div class="row" id="canDetails">
<div class="row even" id="canDetails">
</div>
<div class="row">
<span class="label"># TCP clients</span>
<span class="value" id="numClients">---</span>
</div>
<div class="row">
<div class="row even">
<span class="label">wifi client connected</span>
<span class="value" id="wifiConnected">---</span>
</div>
@ -486,7 +575,8 @@ div#overlayContent.text{
<span class="value" id="clientIP">---</span>
</div>
<button id="reset" >Reset</button>
<div class="configForm">
</div>
<div class="configForm tabPage hidden" id="configPage" >
<div class="configFormRows">
</div>