tabbed view in UI, config categories
This commit is contained in:
parent
62151f9c3c
commit
5ec4dbcecf
|
@ -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"
|
||||
}
|
||||
|
||||
|
||||
|
|
172
web/index.html
172
web/index.html
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue