diff --git a/bower.json b/bower.json index 346c394..f8bc401 100644 --- a/bower.json +++ b/bower.json @@ -16,6 +16,10 @@ "tests" ], "dependencies": { - "material-design-lite": "^1.1.3" + "material-design-lite": "^1.1.3", + "dialog-polyfill": "^0.4.3", + "Leaflet.label": "~0.2.1", + "leaflet": "~0.7.3", + "moment": "~2.9.0" } } diff --git a/config.json.example b/config.json.example index 5db130e..8e730e6 100644 --- a/config.json.example +++ b/config.json.example @@ -2,6 +2,20 @@ "api":"http://localhost:8080/api", "reload":60000, "map":"http://localhost:8080/meshviewer", + "editmap":{ + "view":[53.0702,8.815], + "zoom":16, + "geojson":"/data/meshviewer.geojson", + "tiles":{ + "url":"https://otile{s}-s.mqcdn.com/tiles/1.0.0/osm/{z}/{x}/{y}.jpg", + "option":{ + "subdomains": "1234", + "type": "osm", + "attribution": "Tiles © MapQuest, Data CC-BY-SA OpenStreetMap", + "maxZoom": 18 + } + } + }, "statistics":{ "one":"http://ffhb.h.sum7.de:8080/dashboard-solo/file/Short.json?panelId=1&fullscreen&var-interval_group=60s&theme=light&from=1466165052000&var-title={{NODEID}}&var-node={{NODEID}}", "all":"http://ffhb.h.sum7.de:8080/dashboard-solo/file/Short.json?panelId=1&fullscreen&var-interval_group=60s&theme=light&from=1466165052000&var-title=All" diff --git a/css/styles.css b/css/styles.css index 4ddc34b..896f60d 100644 --- a/css/styles.css +++ b/css/styles.css @@ -9,7 +9,7 @@ html, body { border-radius: 24px; }*/ -container > iframe{ +#container > iframe{ border: 0 solid #000; margin: 0; padding: 0; @@ -32,3 +32,10 @@ container > iframe{ padding:20px 0 0; margin:0px; } + +#dialog-editNode{ + min-width:75%; +} +#dialog-editNode-map{ + height:300px; +} diff --git a/index.html b/index.html index f84741b..dae89a2 100644 --- a/index.html +++ b/index.html @@ -20,10 +20,13 @@ - - - - + + + + + + +
@@ -40,15 +43,17 @@
+
+
-
+ Event Manager -
+
+ +

Loading...

+
+

Loading...

+
+
+
+ + +
+
+ + + + + + diff --git a/js/editModel.js b/js/editModel.js new file mode 100644 index 0000000..1d9ce2b --- /dev/null +++ b/js/editModel.js @@ -0,0 +1,92 @@ +var dialogEditNode = document.getElementById("dialog-editNode") +dialogEditNodeClose = document.querySelector('#dialog-editNode .close') +dialogEditNodeSave = document.querySelector('#dialog-editNode .save') +dialogEditNodeTitle = document.querySelector('#dialog-editNode .mdl-dialog__title') +dialogEditNodeContent = document.querySelector('#dialog-editNode .mdl-dialog__content') + +dialogEditNodeMap = L.map('dialog-editNode-map').setView([51.505, -0.09], 13); +var dialogEditNodeMapCurrent + +function createModel(){ + if (! dialogEditNode.showModal) { + dialogPolyfill.registerDialog(dialogEditNode); + } + + //MAP Part + dialogEditNodeMap.setView(internal.config.editmap.view,internal.config.editmap.zoom) + L.tileLayer(internal.config.editmap.tiles.url,internal.config.editmap.tiles.option).addTo(dialogEditNodeMap) + send('GET',internal.config.editmap.geojson).then(function(data){ + L.geoJson(data,{ + pointToLayer: function (feature, latlng){ + /* + feature.properties.radius = 10 + feature.properties.color = feature.properties["marker-color"] + feature.properties.fillColor = feature.properties["marker-color"] + feature.properties.fillOpacity = 0.5 + */ + m = L.marker(latlng,{ + radius: 8, + fillColor: "#ff7800", + color: "#000", + weight: 1, + opacity: 1, + fillOpacity: 0.8 +}) + m.bindLabel(feature.properties.name) + return m + } + }).addTo(dialogEditNodeMap) + }) + dialogEditNodeMapCurrent = L.circle(internal.config.editmap.view, 500,{ + radius: 500, + color: 'red', + fillColor: '#f03', + fillOpacity: 0.5, + draggable: true + }).addTo(dialogEditNodeMap) + + + + + dialogEditNodeClose.addEventListener('click',function(){ + dialogEditNode.close() + }) + dialogEditNodeSave.addEventListener('click',function(e){ + nodeid = dialogEditNodeContent.querySelector('input[name="nodeid"]').value + if(internal.aliases[nodeid] == undefined){ + internal.aliases[nodeid] = {} + } + if(internal.aliases[nodeid].location == undefined){ + internal.aliases[nodeid].location = {} + } + pos = dialogEditNodeMapCurrent.getLatLng() + internal.aliases[nodeid].location.latitude = pos[0] + internal.aliases[nodeid].location.longitude = pos[1] + internal.aliases[nodeid].hostname = dialogEditNodeContent.querySelector('input[name="hostname"]').value + console.log("save",internal.aliases[nodeid],dialogEditNodeMapCurrent.getLatLng()) + send('POST',internal.config.api+'/aliases/alias/'+nodeid,internal.aliases[nodeid]).then(function(){ + dialogEditNode.close() + }) + }) +} + +function editModel(key){ + dialogEditNodeTitle.innerHTML = 'Edit Node: '+key + fill = '' + + '
' + + '' + + '' + +'
' + dialogEditNodeContent.innerHTML = fill + if(internal.nodes[key].nodeinfo.location != undefined){ + pos = [internal.nodes[key].nodeinfo.location.latitude, internal.nodes[key].nodeinfo.location.longitude] + dialogEditNodeMapCurrent.setLatLng(pos) + dialogEditNodeMap.setView(pos) + }else{ + dialogEditNodeMapCurrent.setLatLng(internal.config.editmap.view) + dialogEditNodeMap.setView(internal.config.editmap.view) + } + dialogEditNodeMapCurrent.bindLabel("Move Node: "+key) + + dialogEditNode.showModal() +} diff --git a/js/global.js b/js/global.js index fbb95c8..c0025cc 100644 --- a/js/global.js +++ b/js/global.js @@ -1,10 +1,11 @@ var toast = document.getElementById("toast") function notify(key){ + console.log("new node:",key) toast.MaterialSnackbar.showSnackbar({ message:"New Nodes with nodeid '"+key+"'!", actionHandler: function(event) { - console.log(event) + editModel(key) }, actionText: 'Edit', timeout: 3000 @@ -14,3 +15,11 @@ function notify(key){ var refreshButton = document.getElementById("refresh") refreshButton.addEventListener('click', refreshData) + + +var lastload = document.getElementById("lastLoad") +function updateTimes(){ + lastload.innerHTML = moment(internal.lastload).fromNow() +} +updateTimes(); +setInterval(updateTimes, 1000); diff --git a/js/init.js b/js/init.js index a4419f9..ee6a60d 100644 --- a/js/init.js +++ b/js/init.js @@ -1,11 +1,15 @@ send('GET',"config.json").then(function(config){ internal.config = config - if(localStorageTest()){ + createModel() + localStorage.removeItem("nodes") + localStorage.removeItem("aliases") + if(false && localStorageTest()){ internal.nodes = JSON.parse(localStorage.getItem("nodes")) internal.aliases = JSON.parse(localStorage.getItem("aliases")) if(!internal.nodes){ send('GET',internal.config.api+"/nodes").then(function(data){ internal.nodes = data + internal.lastload = new Date() }) } if(!internal.aliases){ @@ -13,12 +17,12 @@ send('GET',"config.json").then(function(config){ internal.aliases = data }) } + }else{ + refreshData() } - menuAliases.setAttribute("data-badge",Object.keys(internal.aliases).length) - menuNodes.setAttribute("data-badge",Object.keys(internal.nodes).length) + updateBange() setInterval(function () { refreshData() - route() }, config.reload); route() }) diff --git a/js/lib.js b/js/lib.js index 8203a18..775493c 100644 --- a/js/lib.js +++ b/js/lib.js @@ -33,3 +33,17 @@ function localStorageTest() { return false } } + + +function sshUrl(nodeid){ + if(internal.nodes[nodeid]){ + node = internal.nodes[nodeid] + ip ='z-' + for(var i=0;i node.nodeinfo.network.addresses[i][0]) + ip = node.nodeinfo.network.addresses[i] + } + return 'SSH' + } + return '' +} diff --git a/js/route/aliases.js b/js/route/aliases.js index fd5c125..2d6df7a 100644 --- a/js/route/aliases.js +++ b/js/route/aliases.js @@ -1,32 +1,33 @@ function routeAliases(){ - fill = '' + fill = '
' + '' + '' + '' + + '' + + '' + + '' + '' - + '' - + '' + + '' + '' + '' + '' Object.keys(internal.aliases).map(function(key){ fill += '' - + '' - + '' - + '' - + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + + '' + '' }) fill += '
HostnameFreqChannelPowerLocation2.4 Ghz5 GhzSSH
' + + '' + internal.aliases[key].hostname + '
' + ''+key+'' + '
place' - + 'Ch: '+((internal.aliases[key].freq24 !== undefined)?internal.aliases[key].freq24.channel:'-') - + '
' - + 'Tx: '+((internal.aliases[key].freq24 !== undefined)?internal.aliases[key].freq24.txpower:'-') - + '
' - + 'Ch: '+((internal.aliases[key].freq5 !== undefined)?internal.aliases[key].freq5.channel:'-') - + '
' - + 'TX: '+((internal.aliases[key].freq5 !== undefined)?internal.aliases[key].freq5.txpower:'-') - + '
2.4 Ghz'+((internal.aliases[key].freq24 !== undefined)?internal.aliases[key].freq24.channel:'-')+ ''+((internal.aliases[key].freq24 !== undefined)?internal.aliases[key].freq24.txpower:'-')+ ''+((internal.aliases[key].location)?'place':'')+''+sshUrl(key)+'
5Ghz'+((internal.aliases[key].freq5 !== undefined)?internal.aliases[key].freq5.channel:'-')+ ''+((internal.aliases[key].freq5 !== undefined)?internal.aliases[key].freq5.txpower:'-')+ '
' diff --git a/js/route/nodes.js b/js/route/nodes.js index ff568f6..b33c9ed 100644 --- a/js/route/nodes.js +++ b/js/route/nodes.js @@ -3,16 +3,17 @@ function routeNodesPrivEvent(nodeid,attr,attr2){ return function (e){ var input = e.which || e.keyCode; if (input === 13) { // 13 is enter + value = e.target.value || e.srcElement.value || '' if(internal.aliases[nodeid] == undefined){ internal.aliases[nodeid] = {} } if(attr2 == undefined){ - internal.aliases[nodeid][attr] = e.srcElement.value + internal.aliases[nodeid][attr] = value }else{ if(internal.aliases[nodeid][attr] == undefined){ internal.aliases[nodeid][attr] = {} } - internal.aliases[nodeid][attr][attr2] = e.srcElement.value + internal.aliases[nodeid][attr][attr2] = value } send('POST',internal.config.api+'/aliases/alias/'+nodeid,internal.aliases[nodeid]) } @@ -32,7 +33,7 @@ function routeNodes(){ + 'Clients' + 'Ch' + 'Tx' - + 'Ort' + + 'Edit' + 'SSH' + '' + '' @@ -40,8 +41,10 @@ function routeNodes(){ Object.keys(internal.nodes).map(function(key){ fill += '' + '' - + 'camera' - + '' + + '
' + + moment(internal.nodes[key].lastseen).fromNow(true) + +'' + + '' + '
' + '' + '' @@ -56,8 +59,8 @@ function routeNodes(){ + '' + '' + '' - + 'place' - + 'SSH' + + 'edit' + + ''+sshUrl(key)+'' + '' + '' + '5Ghz' @@ -79,7 +82,9 @@ function routeNodes(){ document.getElementById("freq24_ch_"+key).addEventListener('keypress', routeNodesPrivEvent(key,'freq24','channel')) document.getElementById("freq24_tx_"+key).addEventListener('keypress', routeNodesPrivEvent(key,'freq24','txpower')) document.getElementById("freq5_ch_"+key).addEventListener('keypress', routeNodesPrivEvent(key,'freq5','channel')) - document.getElementById("freq5_tx_"+key).addEventListener('keypress', routeNodesPrivEvent(key,'freq5','txpower')) + document.getElementById("edit_"+key).addEventListener('click', function(){ + editModel(key) + }) }) } diff --git a/js/store.js b/js/store.js index 237c9c4..3fcdb73 100644 --- a/js/store.js +++ b/js/store.js @@ -1,7 +1,8 @@ var internal = { config:{}, nodes:{}, - aliases:{} + aliases:{}, + lastload:0 } //var toast = document.querySelector('#toast'); var container = document.getElementById("container") @@ -9,20 +10,31 @@ var menuNodes = document.getElementById("menu_nodes") var menuAliases = document.getElementById("menu_aliases") + +function updateBange(){ + if(internal.nodes && Object.keys(internal.nodes)) + menuNodes.setAttribute("data-badge",Object.keys(internal.nodes).length) + if(internal.aliases && Object.keys(internal.aliases)) + menuAliases.setAttribute("data-badge",Object.keys(internal.aliases).length) +} + function refreshData(){ + console.log("load new files") send('GET',internal.config.api+"/aliases").then(function(data){ internal.aliases = data - menuAliases.setAttribute("data-badge",Object.keys(internal.aliases).length) + updateBange() + localStorage.setItem("aliases",JSON.stringify(internal.aliases)) }) - send('GET',internal.config.api+"/nodes").then(function(data){ + return send('GET',internal.config.api+"/nodes").then(function(data){ Object.keys(data).map(function(key){ - if(typeof internal.nodes[key]=='undefined'){ - notify(key) + if(internal.nodes[key]== undefined){ + notify(key,data[key]) } internal.nodes[key] = data[key] }) - menuNodes.setAttribute("data-badge",Object.keys(internal.nodes).length) + updateBange() + internal.lastload = new Date() + localStorage.setItem("nodes",JSON.stringify(internal.nodes)) + route() }) - localStorage.setItem("nodes",JSON.stringify(internal.nodes)) - localStorage.setItem("aliases",JSON.stringify(internal.aliases)) }