diff --git a/.gitignore b/.gitignore
index 25983d20..ddfb310f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,7 +4,6 @@ yarn-error.log
*.swp
includes/config.php
rootCA.pem
-vendor
.env
locale/**/*.mo
app/net_activity
diff --git a/app/js/vendor/bandwidthcharts.js b/app/js/vendor/bandwidthcharts.js
new file mode 100644
index 00000000..2bc63d72
--- /dev/null
+++ b/app/js/vendor/bandwidthcharts.js
@@ -0,0 +1,147 @@
+(function($, _t) {
+ "use strict";
+
+ /**
+ * Create a Chart.js barchart.
+ */
+ function CreateChart(ctx, labels) {
+ var barchart = new Chart(ctx,{
+ type: 'line',
+ options: {
+ responsive: true,
+ scales: {
+ xAxes: [{
+ scaleLabel: {
+ display: true,
+ labelString: 'date',
+ },
+ ticks: {
+ maxRotation: 90,
+ minRotation: 80
+ }
+ }],
+ yAxes: [{
+ id: 'y-axis-1',
+ type: 'linear',
+ display: true,
+ position: 'left',
+ ticks: {
+ beginAtZero: true
+ }
+ }]
+ }
+ },
+ data: {
+ labels: labels,
+ datasets: []
+ }
+ });
+
+ return barchart;
+ }
+
+ /**
+ * Create a jquery bootstrap datatable.
+ */
+ function CreateDataTable(placeholder, timeunits) {
+ $("#"+placeholder).append('
');
+ }
+
+ /**
+ * Figure out which tab is selected and remove all existing charts and then
+ * construct the proper barchart.
+ */
+ function ShowBandwidthChartHandler(e) {
+ // Remove all chartjs charts
+ $('#divChartBandwidthhourly').empty();
+ $('#divChartBandwidthdaily').empty();
+ $('#divChartBandwidthmonthly').empty();
+ // Remove all datatables
+ $('#divTableBandwidthhourly').empty();
+ $('#divTableBandwidthdaily').empty();
+ $('#divTableBandwidthmonthly').empty();
+ // Construct ajax uri for getting the proper data.
+ var timeunit = $('ul#tabbarBandwidth li.nav-item a.nav-link.active').attr('href').substr(1);
+ var uri = 'ajax/bandwidth/get_bandwidth.php?';
+ uri += 'inet=';
+ uri += encodeURIComponent($('#cbxInterface'+timeunit+' option:selected').text());
+ uri += '&tu=';
+ uri += encodeURIComponent(timeunit.substr(0, 1));
+ var datasizeunits = 'mb';
+ uri += '&dsu='+encodeURIComponent(datasizeunits);
+ // Init. datatable html
+ var datatable = CreateDataTable('divTableBandwidth'+timeunit, timeunit);
+ // Get data for chart
+ $.ajax({
+ url: uri,
+ dataType: 'json',
+ beforeSend: function() {
+ $('#divLoaderBandwidth'+timeunit).show();
+ }
+ }).done(function(jsondata) {
+ $('#divLoaderBandwidth'+timeunit).hide();
+ // Map json values to label array
+ var labels = jsondata.map(function(e) {
+ return e.date;
+ });
+ // Init. chart with label series
+ var barchart = CreateChart('divChartBandwidth'+timeunit, labels);
+ var dataRx = jsondata.map(function(e) {
+ return e.rx;
+ });
+ var dataTx = jsondata.map(function(e) {
+ return e.tx;
+ });
+
+ addData(barchart, dataRx, dataTx, datasizeunits);
+ $('#tableBandwidth'+timeunit).DataTable({
+ 'searching': false,
+ 'paging': false,
+ 'data': jsondata,
+ 'order': [[ 0, 'ASC' ]],
+ 'columns': [
+ { 'data': 'date' },
+ { 'data': 'rx', "title": _t['receive']+' '+datasizeunits.toUpperCase() },
+ { 'data': 'tx', "title": _t['send']+' '+datasizeunits.toUpperCase() }]
+ });
+ }).fail(function(xhr, textStatus) {
+ if (window.console) {
+ console.error('server error');
+ } else {
+ alert("server error");
+ }
+ });
+ }
+ /**
+ * Add data array to datasets of current chart.
+ */
+ function addData(chart, dataRx, dataTx, datasizeunits) {
+ chart.data.datasets.push({
+ label: 'Receive'+' '+datasizeunits.toUpperCase(),
+ yAxisID: 'y-axis-1',
+ borderColor: 'rgba(75, 192, 192, 1)',
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
+ data: dataRx
+ });
+ chart.data.datasets.push({
+ label: 'Send'+' '+datasizeunits.toUpperCase(),
+ yAxisID: 'y-axis-1',
+ borderColor: 'rgba(192, 192, 192, 1)',
+ backgroundColor: 'rgba(192, 192, 192, 0.2)',
+ data: dataTx
+ });
+ chart.update();
+ }
+
+ $(document).ready(function() {
+ $('#tabbarBandwidth a[data-toggle="tab"]').on('shown.bs.tab', ShowBandwidthChartHandler);
+ $('#cbxInterfacehourly').on('change', ShowBandwidthChartHandler);
+ $('#cbxInterfacedaily').on('change', ShowBandwidthChartHandler);
+ $('#cbxInterfacemonthly').on('change', ShowBandwidthChartHandler);
+ ShowBandwidthChartHandler();
+ });
+
+})(jQuery, t);
+
diff --git a/app/js/vendor/dashboardchart.js b/app/js/vendor/dashboardchart.js
new file mode 100644
index 00000000..e9b039fa
--- /dev/null
+++ b/app/js/vendor/dashboardchart.js
@@ -0,0 +1,106 @@
+(function($, _t) {
+ "use strict";
+
+ /**
+ * Create a Chart.js barchart.
+ */
+ function CreateChart(ctx, labels) {
+ var barchart = new Chart(ctx,{
+ type: 'line',
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ scales: {
+ xAxes: [{
+ scaleLabel: {
+ display: true
+ },
+ ticks: {
+ maxRotation: 0,
+ minRotation: 0
+ }
+ }],
+ yAxes: [{
+ id: 'y-axis-1',
+ type: 'linear',
+ display: true,
+ position: 'left',
+ ticks: {
+ beginAtZero: true
+ }
+ }]
+ }
+ },
+ data: {
+ labels: labels,
+ datasets: []
+ }
+ });
+ return barchart;
+ }
+
+ function ShowBandwidthChartHandler(e) {
+ // Remove hourly chartjs chart
+ $('#divDBChartBandwidthhourly').empty();
+ // Construct ajax uri for getting the proper data
+ var timeunit = 'hourly';
+ var uri = 'ajax/bandwidth/get_bandwidth.php?';
+ uri += 'inet=';
+ uri += encodeURIComponent($('#divInterface').text());
+ uri += '&tu=';
+ uri += encodeURIComponent(timeunit.substr(0, 1));
+ var datasizeunits = 'mb';
+ uri += '&dsu='+encodeURIComponent(datasizeunits);
+ // Get data for chart
+ $.ajax({
+ url: uri,
+ dataType: 'json',
+ beforeSend: function() {}
+ }).done(function(jsondata) {
+ // Map json values to label array
+ var labels = jsondata.map(function(e) {
+ return e.date;
+ });
+ // Init. chart with label series
+ var barchart = CreateChart('divDBChartBandwidth'+timeunit, labels);
+ var dataRx = jsondata.map(function(e) {
+ return e.rx;
+ });
+ var dataTx = jsondata.map(function(e) {
+ return e.tx;
+ });
+ addData(barchart, dataTx, dataRx, datasizeunits);
+ }).fail(function(xhr, textStatus) {
+ if (window.console) {
+ console.error('server error');
+ } else {
+ alert("server error");
+ }
+ });
+ }
+ /**
+ * Add data array to datasets of current chart.
+ */
+ function addData(chart, dataTx, dataRx, datasizeunits) {
+ chart.data.datasets.push({
+ label: 'Send'+' '+datasizeunits.toUpperCase(),
+ yAxisID: 'y-axis-1',
+ borderColor: 'rgba(75, 192, 192, 1)',
+ backgroundColor: 'rgba(75, 192, 192, 0.2)',
+ data: dataTx
+ });
+ chart.data.datasets.push({
+ label: 'Receive'+' '+datasizeunits.toUpperCase(),
+ yAxisID: 'y-axis-1',
+ borderColor: 'rgba(192, 192, 192, 1)',
+ backgroundColor: 'rgba(192, 192, 192, 0.2)',
+ data: dataRx
+ });
+ chart.update();
+ }
+ $(document).ready(function() {
+ ShowBandwidthChartHandler();
+ });
+
+})(jQuery, t);
+
diff --git a/app/js/vendor/huebee.js b/app/js/vendor/huebee.js
new file mode 100644
index 00000000..486d28b2
--- /dev/null
+++ b/app/js/vendor/huebee.js
@@ -0,0 +1,22 @@
+// Initialize Huebee color picker
+var elem = document.querySelector('.color-input');
+var hueb = new Huebee( elem, {
+ notation: 'hex',
+ saturations: 2,
+ customColors: [ '#d8224c', '#dd4814', '#ea0', '#19f', '#333' ],
+ className: 'light-picker',
+ hue0: 210
+});
+
+// Set custom color if defined
+var color = getCookie('color');
+if (color == null || color == '') {
+ color = '#2b8080';
+}
+hueb.setColor(color);
+
+// Change event
+hueb.on( 'change', function( color, hue, sat, lum ) {
+ setCookie('color',color,90);
+})
+
diff --git a/app/js/vendor/speedtestUI.js b/app/js/vendor/speedtestUI.js
new file mode 100644
index 00000000..e97b7c09
--- /dev/null
+++ b/app/js/vendor/speedtestUI.js
@@ -0,0 +1,189 @@
+function I(i){return document.getElementById(i);}
+
+const origin=window.location.origin;
+const host=window.location.host;
+var SPEEDTEST_SERVERS=[
+ {
+ "name":"RaspAP Speedtest server (US)",
+ "server":"https://speedtest.raspap.com/",
+ "dlURL":"backend/garbage.php",
+ "ulURL":"backend/empty.php",
+ "pingURL":"backend/empty.php",
+ "getIpURL":"backend/getIP.php"
+ },
+ {
+ "name":"RaspAP ("+host+")",
+ "server":origin,
+ "dlURL":"dist/speedtest/backend/garbage.php",
+ "ulURL":"dist/speedtest/backend/empty.php",
+ "pingURL":"dist/speedtest/backend/empty.php",
+ "getIpURL":"dist/speedtest/backend/getIP.php"
+ }
+];
+
+//INITIALIZE SPEEDTEST
+var s=new Speedtest(); //create speedtest object
+s.setParameter("telemetry_level","basic"); //enable telemetry
+
+//SERVER AUTO SELECTION
+function initServers(){
+ var noServersAvailable=function(){
+ I("message").innerHTML="No servers available";
+ }
+ var runServerSelect=function(){
+ s.selectServer(function(server){
+ if(server!=null){ //at least 1 server is available
+ I("loading").className="hidden"; //hide loading message
+ //populate server list for manual selection
+ for(var i=0;i