diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index 3b9210e..f2ade54 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -24,6 +24,11 @@ const routes: Routes = [
loadChildren: () =>
import('./views/dashboard/dashboard.module').then((m) => m.DashboardModule)
},
+ {
+ path: 'monitoring',
+ loadChildren: () =>
+ import('./views/monitoring/monitoring.module').then((m) => m.MonitoringModule)
+ },
{
path: 'devices',
loadChildren: () =>
diff --git a/src/app/containers/default-layout/_nav.ts b/src/app/containers/default-layout/_nav.ts
index 7485e78..dbdc8c6 100644
--- a/src/app/containers/default-layout/_nav.ts
+++ b/src/app/containers/default-layout/_nav.ts
@@ -7,6 +7,12 @@ export const navItems: INavData[] = [
iconComponent: { name: 'cil-speedometer' },
},
+ {
+ name: 'Monitoring Wall',
+ url: '/monitoring',
+ icon:'fa-solid fa-tv',
+ attributes: { 'pro':true }
+ },
{
title: true,
name: 'Device Managment'
@@ -153,6 +159,6 @@ export const navItems: INavData[] = [
name: 'Buy Pro',
url: 'https://mikrowizard.com/pricing/',
icon:'fa-solid fa-money-check-dollar',
- attributes: { target: '_blank' }
+ attributes: { 'free':true,target: '_blank' }
}
];
diff --git a/src/app/providers/mikrowizard/data.ts b/src/app/providers/mikrowizard/data.ts
index 2a3eb88..09c7aaf 100644
--- a/src/app/providers/mikrowizard/data.ts
+++ b/src/app/providers/mikrowizard/data.ts
@@ -77,7 +77,30 @@ export class dataProvider {
}
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/stats", data);
}
+ monitoring_devices_events(){
+
+ return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/devs/get", {});
+ }
+ monitoring_events_fix(event_id:number){
+ var data={
+ 'event_id':event_id
+ }
+ return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/fix", data);
+ }
+
+ monitoring_all_events(devid:number){
+ var data={
+ 'devid':devid
+ }
+ return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/get", data);
+ }
+ monitoring_unfixed_events(devid:number){
+ var data={
+ 'devid':devid
+ }
+ return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/eventunfixed/get", data);
+ }
dashboard_traffic(delta:string){
var data={
'delta':delta
@@ -137,7 +160,13 @@ export class dataProvider {
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/sensors", data);
}
-
+ get_dev_radio_sensors(id: number, delta:string="5m"){
+ var data={
+ 'devid':id,
+ 'delta':delta
+ }
+ return this.MikroWizardRPC.sendJsonRequest("/api/dev/radio/sensors", data);
+ }
get_dev_ifstat(id: number,delta:string="5m",iface:string="ether1",type:string="bps") {
var data={
'devid':id,
diff --git a/src/app/views/monitoring/monitoring-routing.module.ts b/src/app/views/monitoring/monitoring-routing.module.ts
new file mode 100644
index 0000000..edcab7f
--- /dev/null
+++ b/src/app/views/monitoring/monitoring-routing.module.ts
@@ -0,0 +1,21 @@
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+
+import { MonitoringComponent } from './monitoring.component';
+
+const routes: Routes = [
+ {
+ path: '',
+ component: MonitoringComponent,
+ data: {
+ title: $localize`Monitoring Wall`
+ }
+ }
+];
+
+@NgModule({
+ imports: [RouterModule.forChild(routes)],
+ exports: [RouterModule]
+})
+export class MonitoringRoutingModule {
+}
diff --git a/src/app/views/monitoring/monitoring.component.html b/src/app/views/monitoring/monitoring.component.html
new file mode 100644
index 0000000..de67415
--- /dev/null
+++ b/src/app/views/monitoring/monitoring.component.html
@@ -0,0 +1,204 @@
+
+
+
+
+ Devices
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Alerts past 24 hours
+ reload
+ {{display}}
+
+
+
+
+
+
+ # |
+ Level |
+ Name |
+ IP |
+ fixed/event time |
+ event |
+ type |
+ source |
+ comment |
+
+
+
+
+
+
+ {{item.index}} |
+
+ {{item.level}}
+ |
+
+ {{item.name}} |
+
+ {{item.devip}} |
+
+ Event {{item.time}}
+ Fixed {{item.fixtime}}
+
+ {{item.time}}
+ |
+
+ {{item.detail}} |
+
+ {{item.eventtype}} |
+
+ {{item.src}} |
+
+ {{item.comment}} |
+
+
+
+
+
+
+
+ All Active Alerts
+
+
+
+
+
+ # |
+ Level |
+ Name |
+ IP |
+ time |
+ event |
+ type |
+ source |
+ comment |
+
+
+
+
+
+ {{item.index}} |
+
+ {{item.level}} |
+
+ {{item.name}} |
+
+ {{item.devip}} |
+
+ {{item.time}} |
+
+ {{item.detail}} |
+
+ {{item.eventtype}} |
+
+ {{item.src}} |
+
+ {{item.comment}} |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ : routers
+ : Bridge
+ : AP Bridge
+ : Station
+ : special Wireless
+
+
\ No newline at end of file
diff --git a/src/app/views/monitoring/monitoring.component.scss b/src/app/views/monitoring/monitoring.component.scss
new file mode 100644
index 0000000..1812540
--- /dev/null
+++ b/src/app/views/monitoring/monitoring.component.scss
@@ -0,0 +1,41 @@
+:host {
+ .legend {
+ small {
+ font-size: x-small;
+ }
+ }
+
+
+
+}
+.mdc-line-ripple.mdc-line-ripple--deactivating.ng-star-inserted {
+ display: none!important;
+}
+
+::ng-deep .main-container{
+ padding:0!important;
+ margin-top:-10px;
+}
+
+::ng-deep .header{
+ margin-bottom: 0.9rem!important;
+}
+
+.contextmenu{
+ position: absolute;
+}
+
+.fixed_time{
+ display:flex;
+ flex-direction: column-reverse;
+ padding: 1px 0px;
+}
+
+.alarms24 tbody th{
+ font-weight:normal!important;
+
+}
+.fixed_time span{
+ font-weight:normal;
+ line-height:110%
+}
diff --git a/src/app/views/monitoring/monitoring.component.ts b/src/app/views/monitoring/monitoring.component.ts
new file mode 100644
index 0000000..8979351
--- /dev/null
+++ b/src/app/views/monitoring/monitoring.component.ts
@@ -0,0 +1,259 @@
+import { Component, OnInit,OnDestroy, ViewChild, ElementRef } from "@angular/core";
+import { UntypedFormControl, UntypedFormGroup } from "@angular/forms";
+import { dataProvider } from "../../providers/mikrowizard/data";
+import { loginChecker } from "../../providers/login_checker";
+import { Router } from "@angular/router";
+import { formatInTimeZone } from "date-fns-tz";
+import { NgScrollbar } from "ngx-scrollbar";
+
+@Component({
+ templateUrl: "monitoring.component.html",
+ styleUrls: ["monitoring.component.scss"],
+})
+export class MonitoringComponent implements OnInit,OnDestroy {
+ public uid: number;
+ public uname: string;
+ public ispro: boolean = false;
+ public tz: string;
+ public copy_msg: any = false;
+ public devices: any = false;
+ public eventsall: any = {};
+ public eventUnfixedsall: any = {};
+ public list_update_timer : any;
+ public timer_interval : any;
+ public ECount: number = 0;
+ public WCount: number = 0;
+ public CCount: number = 0;
+ public display: any;
+ public selected_devid : number =0;
+ public contexItem:any=false;
+ contextmenu : any= false;
+ contextmainmenu: any= false;
+ contextmenuX : any= 0;
+ contextmenuY : any= 0;
+
+ constructor(
+ private data_provider: dataProvider,
+ private router: Router,
+ private login_checker: loginChecker
+ ) {
+ var _self = this;
+ if (!this.login_checker.isLoggedIn()) {
+ setTimeout(function () {
+ _self.router.navigate(["login"]);
+ }, 100);
+ }
+ this.data_provider.getSessionInfo().then((res) => {
+ _self.uid = res.uid;
+ _self.uname = res.name;
+ _self.ispro = res.ISPRO;
+ // This is a pro Feature not availble for free users
+ if (!_self.ispro)
+ setTimeout(function () {
+ _self.router.navigate(["dashboard"]);
+ }, 100);
+ _self.tz = res.tz;
+ const userId = _self.uid;
+ });
+ //get datagrid data
+ function isNotEmpty(value: any): boolean {
+ return value !== undefined && value !== null && value !== "";
+ }
+ }
+ @ViewChild("scrollable") scrollable: NgScrollbar;
+ @ViewChild("scrollable2") scrollable2: NgScrollbar;
+
+ public trafficRadioGroup = new UntypedFormGroup({
+ trafficRadio: new UntypedFormControl("5m"),
+ });
+
+ ngOnInit(): void {
+ this.initEvents();
+ this.initAllalerts();
+ this.initUnfixedalerts();
+ this.update_tables();
+ }
+ set_table_color(item:any,bypass=true){
+ if('status' in item && item.status==true && bypass) {
+ return 'light';
+ }
+ if(item.level=='Critical') return 'danger';
+ else if(item.level=='Warning') return 'warning';
+ else if(item.level=='Error') return 'danger';
+ else return 'danger';
+ }
+ scroll() {
+ this.scrollable.scrollTo({ bottom: 0, duration: 500 });
+ }
+ onrightClick(event:any,item:any,main=false){
+ this.contexItem=item;
+ this.contextmenuX=event.clientX
+ this.contextmenuY=event.clientY
+ if (!main){
+ this.contextmenu=true;
+ this.contextmainmenu=false;
+ }
+ else{
+ this.contextmainmenu=true;
+ this.contextmenu=false;
+ }
+ }
+ //disables the menu
+ disableContextMenu(){
+ this.contexItem=false;
+ this.contextmenu= false;
+ this.contextmainmenu= false;
+ }
+ fix_event(){
+ var _self=this;
+ if (!this.contexItem)
+ return
+ this.data_provider.monitoring_events_fix(this.contexItem.id).then((res) => {
+ if('status' in res && res['status']=='failed')
+ return;
+ _self.reload_data();
+ });
+ }
+ initEvents() {
+ var _self = this;
+ //init radio buttons
+ _self.ECount = 0;
+ _self.WCount = 0;
+ _self.CCount = 0;
+ this.data_provider.monitoring_devices_events().then((res) => {
+ _self.devices = res.map((d: any) => {
+ d.ECount = 0;
+ d.WCount = 0;
+ d.CCount = 0;
+ if (d.data)
+ d.data.forEach((z: any) => {
+ if (z.level == "Error") {
+ d.ECount++;
+ _self.ECount++;
+ } else if (z.level == "Warning") {
+ d.WCount++;
+ _self.WCount++;
+ } else if (z.level == "Critical") {
+ d.CCount++;
+ _self.CCount++;
+ }
+ });
+ return d;
+ });
+ });
+ }
+
+ initAllalerts(){
+ var _self = this;
+ this.data_provider.monitoring_all_events(_self.selected_devid).then((res) => {
+ var index=1;
+ _self.eventsall = res.map((d: any) => {
+ d.time = formatInTimeZone(
+ d.eventtime.split(".")[0] + ".000Z",
+ _self.tz,
+ "yyyy-MM-dd HH:mm:ss"
+ );
+ if(d.fixtime)
+ d.fixtime = formatInTimeZone(
+ d.fixtime.split(".")[0] + ".000Z",
+ _self.tz,
+ "yyyy-MM-dd HH:mm:ss"
+ );
+ d.index = index++;
+ return d
+ });
+ console.dir(res)
+ setTimeout(function() {
+ _self.scrollable.scrollTo({ bottom: 0, duration: 500 });
+ }, 100);
+ });
+ }
+
+
+
+ initUnfixedalerts(){
+ var _self = this;
+ this.data_provider.monitoring_unfixed_events(_self.selected_devid).then((res) => {
+ var index=1;
+ _self.eventUnfixedsall = res.map((d: any) => {
+ d.time = formatInTimeZone(
+ d.eventtime.split(".")[0] + ".000Z",
+ _self.tz,
+ "yyyy-MM-dd HH:mm:ss XXX"
+ );
+ d.index = index++;
+ return d
+ });
+ setTimeout(function() {
+ _self.scrollable2.scrollTo({ bottom: 0, duration: 500 });
+ }, 100);
+ });
+ }
+
+ timer(minute:any) {
+ // let minute = 1;
+ let seconds: number = minute * 60;
+ let textSec: any = "0";
+ let statSec: number = 60;
+ var _self=this;
+ const prefix = minute < 10 ? "0" : "";
+
+ this.timer_interval = setInterval(() => {
+ seconds--;
+ if (statSec != 0) statSec--;
+ else statSec = 59;
+
+ if (statSec < 10) {
+ textSec = "0" + statSec;
+ } else textSec = statSec;
+
+ this.display = `${prefix}${Math.floor(seconds / 60)}:${textSec}`;
+
+ if (seconds == 0) {
+ clearInterval(_self.timer_interval);
+ }
+ }, 1000);
+ }
+ filter_device(item:any){
+ if(item == 0)
+ this.selected_devid=0;
+ else if ('devid' in item)
+ this.selected_devid=item.devid;
+ this.reload_data();
+ }
+ reload_data(){
+ clearTimeout(this.list_update_timer);
+ clearTimeout(this.timer_interval);
+ this.initEvents();
+ this.initAllalerts();
+ this.initUnfixedalerts();
+ this.update_tables();
+ }
+ go_device(){
+ this.router.navigate(["/device-stats", { id: this.contexItem.devid }]);
+ }
+
+ go_logs(){
+ this.router.navigate(["/devlogs", { devid: this.contexItem.devid }]);
+
+ }
+ update_tables(){
+ // update initAllalerts and initUnfixedalerts every 1 minute
+ var _self = this;
+ clearTimeout(this.list_update_timer);
+ clearTimeout(this.timer_interval);
+ this.timer(1)
+ this.list_update_timer = setTimeout(() => {
+ _self.initEvents();
+ _self.initAllalerts();
+ _self.initUnfixedalerts();
+ _self.update_tables();
+ }, 60000);
+
+ }
+
+ ngOnDestroy(){
+ clearTimeout(this.list_update_timer);
+ clearTimeout(this.timer_interval);
+ }
+}
diff --git a/src/app/views/monitoring/monitoring.module.ts b/src/app/views/monitoring/monitoring.module.ts
new file mode 100644
index 0000000..f883871
--- /dev/null
+++ b/src/app/views/monitoring/monitoring.module.ts
@@ -0,0 +1,53 @@
+import { NgModule } from "@angular/core";
+import { CommonModule } from "@angular/common";
+import { ReactiveFormsModule } from "@angular/forms";
+
+import {
+ ButtonGroupModule,
+ ButtonModule,
+ CardModule,
+ GridModule,
+ WidgetModule,
+ ProgressModule,
+ TemplateIdDirective,
+ TooltipModule,
+ BadgeModule,
+ CarouselModule,
+ ListGroupModule,
+ TableModule,
+ UtilitiesModule
+} from "@coreui/angular";
+
+import { ChartjsModule } from "@coreui/angular-chartjs";
+import { NgScrollbarModule } from 'ngx-scrollbar';
+
+import { MonitoringRoutingModule } from "./monitoring-routing.module";
+import { MonitoringComponent } from "./monitoring.component";
+import { ClipboardModule } from "@angular/cdk/clipboard";
+
+@NgModule({
+ imports: [
+ MonitoringRoutingModule,
+ CardModule,
+ WidgetModule,
+ CommonModule,
+ GridModule,
+ ProgressModule,
+ ReactiveFormsModule,
+ ButtonModule,
+ TemplateIdDirective,
+ ButtonModule,
+ ButtonGroupModule,
+ ChartjsModule,
+ CarouselModule,
+ BadgeModule,
+ ClipboardModule,
+ ListGroupModule,
+ NgScrollbarModule,
+ TableModule,
+ TooltipModule,
+ UtilitiesModule
+ ],
+ declarations: [MonitoringComponent],
+})
+export class MonitoringModule {}