mirror of
https://github.com/yggdrasil-network/yggdrasil-go.git
synced 2025-08-25 16:35:07 +03:00
Merge pull request #30 from RiV-chain/ie11
IE11 support, markup fixes, caching fixes
This commit is contained in:
commit
eeae07c59b
19 changed files with 1609 additions and 51 deletions
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
420
contrib/ui/mesh-ui/ui/assets/mesh-ui-es5.js
Normal file
420
contrib/ui/mesh-ui/ui/assets/mesh-ui-es5.js
Normal file
|
@ -0,0 +1,420 @@
|
|||
"use strict";
|
||||
|
||||
var $ = function $(id) {
|
||||
return document.getElementById(id);
|
||||
};
|
||||
var $$ = function $$(clazz) {
|
||||
return document.getElementsByClassName(clazz);
|
||||
};
|
||||
|
||||
function setPingValue(peer, value) {
|
||||
var cellText;
|
||||
var peerCell = $(peer);
|
||||
if (!peerCell) return;
|
||||
var peerTable = $("peer_list");
|
||||
if (value === "-1") {
|
||||
var peerAddress = $("label_" + peer);
|
||||
peerAddress.style.color = "rgba(250,250,250,.5)";
|
||||
} else {
|
||||
|
||||
cellText = document.createTextNode(value);
|
||||
peerCell.appendChild(cellText);
|
||||
|
||||
var peerCellTime = $("time_" + peer);
|
||||
var cellTextTime = document.createTextNode("ms");
|
||||
peerCellTime.appendChild(cellTextTime);
|
||||
}
|
||||
peerCell.parentNode.classList.remove("is-hidden");
|
||||
//sort table
|
||||
moveRowToOrderPos(peerTable, 2, peerCell.parentNode);
|
||||
}
|
||||
|
||||
function cmpTime(a, b) {
|
||||
return a.textContent.trim() === "" ? 1 : a.textContent.trim() // using `.textContent.trim()` for test
|
||||
.localeCompare(b.textContent.trim(), 'en', { numeric: true });
|
||||
}
|
||||
|
||||
function moveRowToOrderPos(table, col, row) {
|
||||
var tb = table.tBodies[0],
|
||||
tr = tb.rows;
|
||||
var i = 0;
|
||||
for (; i < tr.length && cmpTime(row.cells[col], tr[i].cells[col]) >= 0; ++i) {}
|
||||
if (i < tr.length && i != row.rowIndex) {
|
||||
tb.deleteRow(row.rowIndex);
|
||||
tb.insertBefore(row, tr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
function openTab(element, tabName) {
|
||||
// Declare all variables
|
||||
var i, tabContent, tabLinks;
|
||||
|
||||
// Get all elements with class="content" and hide them
|
||||
tabContent = $$("tab here");
|
||||
for (i = 0; i < tabContent.length; i++) {
|
||||
tabContent[i].className = "tab here is-hidden";
|
||||
}
|
||||
|
||||
// Get all elements with class="tab" and remove the class "is-active"
|
||||
tabLinks = $$("tab is-active");
|
||||
for (i = 0; i < tabLinks.length; i++) {
|
||||
tabLinks[i].className = "tab";
|
||||
}
|
||||
|
||||
// Show the current tab, and add an "is-active" class to the button that opened the tab
|
||||
$(tabName).className = "tab here";
|
||||
element.parentElement.className = "tab is-active";
|
||||
//refreshRecordsList();
|
||||
}
|
||||
|
||||
function copy2clipboard(text) {
|
||||
var textArea = document.createElement("textarea");
|
||||
textArea.style.position = 'fixed';
|
||||
textArea.style.top = 0;
|
||||
textArea.style.left = 0;
|
||||
|
||||
// Ensure it has a small width and height. Setting to 1px / 1em
|
||||
// doesn't work as this gives a negative w/h on some browsers.
|
||||
textArea.style.width = '2em';
|
||||
textArea.style.height = '2em';
|
||||
|
||||
// We don't need padding, reducing the size if it does flash render.
|
||||
textArea.style.padding = 0;
|
||||
|
||||
// Clean up any borders.
|
||||
textArea.style.border = 'none';
|
||||
textArea.style.outline = 'none';
|
||||
textArea.style.boxShadow = 'none';
|
||||
|
||||
// Avoid flash of the white box if rendered for any reason.
|
||||
textArea.style.background = 'transparent';
|
||||
textArea.value = text;
|
||||
|
||||
document.body.appendChild(textArea);
|
||||
textArea.focus();
|
||||
textArea.select();
|
||||
try {
|
||||
var successful = document.execCommand('copy');
|
||||
var msg = successful ? 'successful' : 'unsuccessful';
|
||||
console.log('Copying text command was ' + msg);
|
||||
} catch (err) {
|
||||
console.log('Oops, unable to copy');
|
||||
}
|
||||
document.body.removeChild(textArea);
|
||||
showInfo('value copied successfully!');
|
||||
}
|
||||
|
||||
function showInfo(text) {
|
||||
var info = $("notification_info");
|
||||
var message = $("info_text");
|
||||
message.innerHTML = text;
|
||||
|
||||
info.className = "notification is-primary";
|
||||
var button = $("info_close");
|
||||
button.onclick = function () {
|
||||
message.value = "";
|
||||
info.className = "notification is-primary is-hidden";
|
||||
};
|
||||
setTimeout(button.onclick, 2000);
|
||||
}
|
||||
|
||||
function showWindow(text) {
|
||||
var info = $("notification_window");
|
||||
var message = $("info_window");
|
||||
message.innerHTML = text;
|
||||
|
||||
info.classList.remove("is-hidden");
|
||||
var button_info_close = $("info_win_close");
|
||||
button_info_close.onclick = function () {
|
||||
message.value = "";
|
||||
info.classList.add("is-hidden");
|
||||
$("peer_list").remove();
|
||||
};
|
||||
var button_window_close = $("window_close");
|
||||
button_window_close.onclick = function () {
|
||||
message.value = "";
|
||||
info.classList.add("is-hidden");
|
||||
$("peer_list").remove();
|
||||
};
|
||||
var button_window_save = $("window_save");
|
||||
button_window_save.onclick = function () {
|
||||
message.value = "";
|
||||
info.classList.add("is-hidden");
|
||||
//todo save peers
|
||||
var peers = document.querySelectorAll('*[id^="peer-"]');
|
||||
var peer_list = [];
|
||||
for (i = 0; i < peers.length; ++i) {
|
||||
var p = peers[i];
|
||||
if (p.checked) {
|
||||
var peerURL = p.parentElement.parentElement.children[1].innerText;
|
||||
peer_list.push(peerURL);
|
||||
}
|
||||
}
|
||||
fetch('api/peers', {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Riv-Save-Config': 'true'
|
||||
},
|
||||
body: JSON.stringify(peer_list)
|
||||
}).catch(function (error) {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
$("peer_list").remove();
|
||||
};
|
||||
}
|
||||
|
||||
function add_table(peerList) {
|
||||
|
||||
var peers = [];
|
||||
//const countries = Object.keys(peerList);
|
||||
// get the reference for the body
|
||||
var body = document.createElement("div");
|
||||
// creates a <table> element and a <tbody> element
|
||||
var tbl = document.createElement("table");
|
||||
tbl.setAttribute('id', "peer_list");
|
||||
//tbl.setAttribute('cellpadding', '10');
|
||||
var tblBody = document.createElement("tbody");
|
||||
|
||||
// creating all cells
|
||||
for (var c in peerList) {
|
||||
var counter = 1;
|
||||
for (var peer in peerList[c]) {
|
||||
peers.push(peer);
|
||||
// creates a table row
|
||||
var row = document.createElement("tr");
|
||||
row.className = "is-hidden";
|
||||
var imgElement = document.createElement("td");
|
||||
imgElement.className = "big-flag fi fi-" + ui.lookupCountryCodeByAddress(peer);
|
||||
var peerAddress = document.createElement("td");
|
||||
var cellText = document.createTextNode(peer);
|
||||
peerAddress.appendChild(cellText);
|
||||
peerAddress.setAttribute('id', "label_" + peer);
|
||||
var peerPing = document.createElement("td");
|
||||
peerPing.setAttribute('id', peer);
|
||||
var peerPingTime = document.createElement("td");
|
||||
peerPingTime.setAttribute('id', "time_" + peer);
|
||||
var peerSelect = document.createElement("td");
|
||||
var chk = document.createElement('input');
|
||||
chk.setAttribute('type', 'checkbox');
|
||||
chk.setAttribute('id', "peer-" + counter);
|
||||
peerSelect.appendChild(chk);
|
||||
|
||||
row.appendChild(imgElement);
|
||||
row.appendChild(peerAddress);
|
||||
row.appendChild(peerPing);
|
||||
row.appendChild(peerPingTime);
|
||||
row.appendChild(peerSelect);
|
||||
tblBody.appendChild(row);
|
||||
}
|
||||
}
|
||||
// put the <tbody> in the <table>
|
||||
tbl.appendChild(tblBody);
|
||||
// appends <table> into <body>
|
||||
body.appendChild(tbl);
|
||||
// sets the border attribute of tbl to 2;
|
||||
//tbl.setAttribute("border", "0");
|
||||
showWindow(body.innerHTML);
|
||||
return peers;
|
||||
}
|
||||
|
||||
function togglePrivKeyVisibility() {
|
||||
if (this.classList.contains("fa-eye")) {
|
||||
this.classList.remove("fa-eye");
|
||||
this.classList.add("fa-eye-slash");
|
||||
$("priv_key_visible").innerHTML = $("priv_key").innerHTML;
|
||||
} else {
|
||||
this.classList.remove("fa-eye-slash");
|
||||
this.classList.add("fa-eye");
|
||||
$("priv_key_visible").innerHTML = "••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••";
|
||||
}
|
||||
}
|
||||
|
||||
function humanReadableSpeed(speed) {
|
||||
var i = speed == 0 ? 0 : Math.floor(Math.log(speed) / Math.log(1024));
|
||||
return (speed / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bps', 'kBps', 'MBps', 'GBps', 'TBps'][i];
|
||||
}
|
||||
|
||||
var ui = ui || {
|
||||
countries: []
|
||||
};
|
||||
|
||||
ui.getAllPeers = function () {
|
||||
if (!("_allPeersPromise" in ui)) {
|
||||
ui._allPeersPromise = new Promise(function (resolve, reject) {
|
||||
if ("_allPeers" in ui) resolve(ui._allPeers);else fetch('https://map.rivchain.org/rest/peers.json').then(function (response) {
|
||||
return response.json();
|
||||
}).then(function (data) {
|
||||
var _loop = function _loop() {
|
||||
var country = c.slice(0, -3);
|
||||
var filtered = ui.countries.find(function (entry) {
|
||||
return entry.name.toLowerCase() == country;
|
||||
});
|
||||
//let flagFile = filtered ? filtered["flag_4x3"] : "";
|
||||
var flagCode = filtered ? filtered["code"] : "";
|
||||
for (var peer in data[c]) {
|
||||
data[c][peer].countryCode = flagCode;
|
||||
}
|
||||
};
|
||||
|
||||
// add country code to each peer
|
||||
for (var c in data) {
|
||||
_loop();
|
||||
}
|
||||
ui._allPeers = data;
|
||||
resolve(ui._allPeers);
|
||||
}).catch(reject);
|
||||
}).finally(function () {
|
||||
return delete ui._allPeersPromise;
|
||||
});
|
||||
}
|
||||
return ui._allPeersPromise;
|
||||
};
|
||||
|
||||
ui.showAllPeers = function () {
|
||||
return ui.getAllPeers().then(function (peerList) {
|
||||
var peers = add_table(peerList);
|
||||
//start peers test
|
||||
fetch('api/ping', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(peers)
|
||||
}).catch(function (error) {
|
||||
console.error('Error:', error);
|
||||
});
|
||||
}).catch(function (error) {
|
||||
console.error(error);
|
||||
});
|
||||
};
|
||||
|
||||
ui.getConnectedPeers = function () {
|
||||
return fetch('api/peers').then(function (response) {
|
||||
return response.json();
|
||||
});
|
||||
};
|
||||
|
||||
var regexMulticast = /:\/\/\[fe80::/;
|
||||
ui.updateConnectedPeersHandler = function (peers) {
|
||||
$("peers").innerText = "";
|
||||
var regexStrip = /%[^\]]*/gm;
|
||||
var sorted = peers.map(function (peer) {
|
||||
return { "url": peer["remote"], "isMulticast": peer["remote"].match(regexMulticast) };
|
||||
}).sort(function (a, b) {
|
||||
return a.isMulticast > b.isMulticast;
|
||||
});
|
||||
sorted.forEach(function (peer) {
|
||||
var row = $("peers").appendChild(document.createElement('div'));
|
||||
row.className = "overflow-ellipsis";
|
||||
var flag = row.appendChild(document.createElement("span"));
|
||||
if (peer.isMulticast) flag.className = "fa fa-thin fa-share-nodes peer-connected-fl";else flag.className = "fi fi-" + ui.lookupCountryCodeByAddress(peer.url) + " peer-connected-fl";
|
||||
row.append(peer.url.replace(regexStrip, ""));
|
||||
});
|
||||
};
|
||||
|
||||
ui.updateStatus = function (peers) {
|
||||
var status = "st-error";
|
||||
if (peers) {
|
||||
if (peers.length) {
|
||||
var isNonMulticastExists = peers.filter(function (peer) {
|
||||
return !peer["remote"].match(regexMulticast);
|
||||
}).length;
|
||||
status = isNonMulticastExists ? "st-multicast" : "st-connected";
|
||||
} else {
|
||||
status = "st-connecting";
|
||||
}
|
||||
}
|
||||
Array.from($$("status")).forEach(function (node) {
|
||||
return node.classList.add("is-hidden");
|
||||
});
|
||||
$(status).classList.remove("is-hidden");
|
||||
};
|
||||
|
||||
ui.updateSpeed = function (peers) {
|
||||
if (peers) {
|
||||
var rsbytes = { "bytes_recvd": peers.reduce(function (acc, peer) {
|
||||
return acc + peer.bytes_recvd;
|
||||
}, 0),
|
||||
"bytes_sent": peers.reduce(function (acc, peer) {
|
||||
return acc + peer.bytes_sent;
|
||||
}, 0),
|
||||
"timestamp": Date.now() };
|
||||
if ("_rsbytes" in ui) {
|
||||
$("dn_speed").innerText = humanReadableSpeed((rsbytes.bytes_recvd - ui._rsbytes.bytes_recvd) * 1000 / (rsbytes.timestamp - ui._rsbytes.timestamp));
|
||||
$("up_speed").innerText = humanReadableSpeed((rsbytes.bytes_sent - ui._rsbytes.bytes_sent) * 1000 / (rsbytes.timestamp - ui._rsbytes.timestamp));
|
||||
}
|
||||
ui._rsbytes = rsbytes;
|
||||
} else {
|
||||
delete ui._rsbytes;
|
||||
$("dn_speed").innerText = "? Bs";
|
||||
$("up_speed").innerText = "? Bs";
|
||||
}
|
||||
};
|
||||
|
||||
ui.updateConnectedPeers = function () {
|
||||
return ui.getConnectedPeers().then(function (peers) {
|
||||
ui.updateConnectedPeersHandler(peers);
|
||||
ui.updateStatus(peers);
|
||||
ui.updateSpeed(peers);
|
||||
}).catch(function (error) {
|
||||
$("peers").innerText = error.message;
|
||||
ui.updateStatus();
|
||||
ui.updateSpeed();
|
||||
});
|
||||
};
|
||||
|
||||
ui.lookupCountryCodeByAddress = function (address) {
|
||||
for (var c in ui._allPeers) {
|
||||
for (var peer in ui._allPeers[c]) {
|
||||
if (peer == address) return ui._allPeers[c][peer].countryCode;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ui.getSelfInfo = function () {
|
||||
return fetch('api/self').then(function (response) {
|
||||
return response.json();
|
||||
});
|
||||
};
|
||||
|
||||
ui.updateSelfInfo = function () {
|
||||
return ui.getSelfInfo().then(function (info) {
|
||||
$("ipv6").innerText = info.address;
|
||||
$("subnet").innerText = info.subnet;
|
||||
$("pub_key").innerText = info.key;
|
||||
$("priv_key").innerText = info.private_key;
|
||||
$("ipv6").innerText = info.address;
|
||||
$("version").innerText = info.build_version;
|
||||
}).catch(function (error) {
|
||||
$("ipv6").innerText = error.message;
|
||||
});
|
||||
};
|
||||
|
||||
ui.sse = new EventSource('/api/sse');
|
||||
|
||||
function main() {
|
||||
|
||||
window.addEventListener("load", function () {
|
||||
$("showAllPeersBtn").addEventListener("click", ui.showAllPeers);
|
||||
|
||||
ui.getAllPeers().then(function () {
|
||||
return ui.updateConnectedPeers();
|
||||
});
|
||||
setInterval(ui.updateConnectedPeers, 5000);
|
||||
|
||||
ui.updateSelfInfo();
|
||||
//setInterval(ui.updateSelfInfo, 5000);
|
||||
|
||||
ui.sse.addEventListener("ping", function (e) {
|
||||
var data = JSON.parse(e.data);
|
||||
setPingValue(data.peer, data.value);
|
||||
});
|
||||
|
||||
ui.sse.addEventListener("peers", function (e) {
|
||||
ui.updateConnectedPeersHandler(JSON.parse(e.data));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
main();
|
|
@ -68,12 +68,9 @@ img {
|
|||
display: block;
|
||||
}
|
||||
|
||||
html, body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
body {
|
||||
max-width: 690px;
|
||||
min-width: 690px;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
|
@ -86,6 +83,13 @@ td.fi {
|
|||
background-position: 0;
|
||||
}
|
||||
|
||||
footer {
|
||||
position:fixed;
|
||||
bottom:0;
|
||||
max-width: 690px;
|
||||
margin-top: auto;
|
||||
}
|
||||
|
||||
#footer-row td {
|
||||
padding: 10px;
|
||||
white-space: nowrap;
|
||||
|
|
|
@ -229,7 +229,7 @@ function humanReadableSpeed(speed) {
|
|||
return (speed / Math.pow(1024, i)).toFixed(2) * 1 + ' ' + ['Bps', 'kBps', 'MBps', 'GBps', 'TBps'][i];
|
||||
}
|
||||
|
||||
var ui = {
|
||||
var ui = ui || {
|
||||
countries: []
|
||||
};
|
||||
|
||||
|
@ -372,10 +372,6 @@ ui.sse = new EventSource('/api/sse');
|
|||
|
||||
function main() {
|
||||
|
||||
fetch('country.json')
|
||||
.then((response) => response.json())
|
||||
.then((data) => { ui.countries = data });
|
||||
|
||||
window.addEventListener("load", () => {
|
||||
$("showAllPeersBtn").addEventListener("click", ui.showAllPeers);
|
||||
|
||||
|
|
798
contrib/ui/mesh-ui/ui/assets/polyfills.js
Normal file
798
contrib/ui/mesh-ui/ui/assets/polyfills.js
Normal file
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,6 @@
|
|||
[
|
||||
var ui = ui || {};
|
||||
|
||||
ui.countries = [
|
||||
{
|
||||
"capital": "Georgetown",
|
||||
"code": "ac",
|
||||
|
|
|
@ -11,11 +11,27 @@
|
|||
<link rel="stylesheet" href="assets/bulmaswatch.min.css" type="text/css">
|
||||
<link rel="stylesheet" href="assets/flag-icons.css" type="text/css">
|
||||
<link rel="stylesheet" href="assets/mesh-ui.css" type="text/css">
|
||||
<script type="application/javascript" src="assets/mesh-ui.js"></script>
|
||||
<script type="application/javascript" src="country.json"></script>
|
||||
<!--script type="application/javascript" src="assets/mesh-ui.js"></script-->
|
||||
<script>
|
||||
var script = document.createElement('script');
|
||||
//load polyfills + EC5 for IE or usual for rest
|
||||
if (window.document.documentMode) {
|
||||
script.src = "assets/polyfills.js";
|
||||
script.onload = function () {
|
||||
var ec5 = document.createElement('script');
|
||||
ec5.src = "assets/mesh-ui-es5.js";
|
||||
document.head.appendChild(ec5);
|
||||
};
|
||||
} else {
|
||||
script.src = "assets/mesh-ui.js";
|
||||
}
|
||||
document.head.appendChild(script);
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="container hero is-fullheight">
|
||||
<body class="hero is-fullheight">
|
||||
<div>
|
||||
<div class="box is-hidden" id="notification_window">
|
||||
<div style="z-index: 9;" class="notification is-primary">
|
||||
<button class="delete" id="info_win_close"></button>
|
||||
|
@ -53,7 +69,7 @@
|
|||
preserveAspectRatio="xMidYMid meet" viewBox="0 0 42 42">
|
||||
<path
|
||||
d="M18.5 35.5l-8 2c-.48.04-1 .52-1 1v1c0 .5.47 1 1 1h20c.43 0 1-.41 1-1v-1c-.02-.52-.55-.98-1-1l-8-2h-4zm19-1c2.59 0 3-.529 3-3v-26c0-2.391-.55-3-3-3h-34c-2.43 0-3 .54-3 3v26c0 2.51.529 3 3 3h34zm-2-27v22h-30v-22h30z"
|
||||
fill="white" />
|
||||
fill="white" ></path>
|
||||
</svg>
|
||||
</span>
|
||||
<span>My Node</span>
|
||||
|
@ -67,8 +83,8 @@
|
|||
style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);"
|
||||
preserveAspectRatio="xMidYMid meet" viewBox="0 0 32 32">
|
||||
<g fill="none" stroke="white" stroke-linecap="round" stroke-linejoin="round" stroke-width="2">
|
||||
<path d="M5 15v15h22V15zm4 0C9 9 9 5 16 5s7 4 7 10m-7 5v3" />
|
||||
<circle cx="16" cy="24" r="1" />
|
||||
<path d="M5 15v15h22V15zm4 0C9 9 9 5 16 5s7 4 7 10m-7 5v3" ></path>
|
||||
<circle cx="16" cy="24" r="1" ></circle>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
|
@ -82,10 +98,10 @@
|
|||
focusable="false" width="1em" height="1em"
|
||||
style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);"
|
||||
preserveAspectRatio="xMidYMid meet" viewBox="0 0 48 48">
|
||||
<path fill="#2196F3" d="M37 40H11l-6 6V12c0-3.3 2.7-6 6-6h26c3.3 0 6 2.7 6 6v22c0 3.3-2.7 6-6 6z" />
|
||||
<path fill="#2196F3" d="M37 40H11l-6 6V12c0-3.3 2.7-6 6-6h26c3.3 0 6 2.7 6 6v22c0 3.3-2.7 6-6 6z" ></path>
|
||||
<g fill="#fff">
|
||||
<path d="M22 20h4v11h-4z" />
|
||||
<circle cx="24" cy="15" r="2" />
|
||||
<path d="M22 20h4v11h-4z" ></path>
|
||||
<circle cx="24" cy="15" r="2" ></circle>
|
||||
</g>
|
||||
</svg>
|
||||
</span>
|
||||
|
@ -165,7 +181,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<footer class="is-flex-align-items-flex-end" style="margin-top: auto">
|
||||
</div>
|
||||
<footer>
|
||||
<hr style="margin: 0px;background-color: #5d656d;">
|
||||
<table class="content"><tr id="footer-row">
|
||||
<td id="version">v123456</td>
|
||||
|
@ -181,6 +198,4 @@
|
|||
</tr></table>
|
||||
</footer>
|
||||
|
||||
</div>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"os"
|
||||
|
||||
"github.com/RiV-chain/RiV-mesh/src/defaults"
|
||||
"github.com/webview/webview"
|
||||
"github.com/jchv/go-webview-selector"
|
||||
|
||||
"github.com/docopt/docopt-go"
|
||||
)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue