MikroWizard Initial commit | MikroFront Welcome to the world :)

This commit is contained in:
sepehr 2024-07-07 14:48:52 +03:30
commit b97aec6b97
203 changed files with 41097 additions and 0 deletions

View file

@ -0,0 +1,20 @@
import { NgModule } from "@angular/core";
import { RouterModule, Routes } from "@angular/router";
import { AccComponent } from "./acc.component";
const routes: Routes = [
{
path: "",
component: AccComponent,
data: {
title: $localize`Accounting Logs`,
},
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
})
export class AccRoutingModule {}

View file

@ -0,0 +1,112 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="11">
Accunting Logs
</c-col>
<c-col xs [lg]="1">
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
class="fa-solid fa-filter mr-1"></i>Filter</button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<c-row>
<div [visible]="filters_visible" cCollapse>
<c-col xs [lg]="12" class="example-form">
<mat-form-field>
<mat-label>Start date</mat-label>
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
[(ngModel)]="filters['start_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>End date</mat-label>
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
[(ngModel)]="filters['end_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Select section</mat-label>
<mat-select placeholder="Event Section" (ngModelChange)="reinitgrid('section',$event)"
[(ngModel)]="filters['section']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let sec of event_section " [value]="sec">
{{sec}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Select action</mat-label>
<mat-select placeholder="Event Section" (ngModelChange)="reinitgrid('action',$event)"
[(ngModel)]="filters['action']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let ac of event_action" [value]="ac">
{{ac}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Config</mat-label>
<input (ngModelChange)="reinitgrid('config',$event)" [(ngModel)]="filters['config']" matInput>
</mat-form-field>
<mat-form-field>
<mat-label>IP</mat-label>
<input (ngModelChange)="reinitgrid('ip',$event)" [(ngModel)]="filters['ip']" matInput>
</mat-form-field>
</c-col>
</div>
</c-row>
<gui-grid [rowDetail]="rowDetail" [source]="source" [columnMenu]="columnMenu" [paging]="paging"
[sorting]="sorting" [infoPanel]="infoPanel" [autoResizeWidth]=true>
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
<ng-template let-value="item.index" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device IP" field="devip">
<ng-template let-value="item.devip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Username" field="username">
<ng-template let-value="item.username" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Action" field="action">
<ng-template let-value="item.action" let-item="item" let-index="index">
<div>{{value}}</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Section" field="section">
<ng-template let-value="item.section" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Date" field="created">
<ng-template let-value="item.created" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Message" field="message" [enabled]="false">
<ng-template let-value="item.message" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>

View file

@ -0,0 +1,86 @@
@use '@angular/material' as mat;
:host {
.legend {
small {
font-size: x-small;
}
}
}
.gui-drawer-content{
background-color: #efefef!important;
}
.log-detail{
padding:30px 10px;
box-sizing:border-box;
}
.log-detail h1{
font-size:2em;
font-weight:bold;
margin:0;
padding:0;
}
.log-detail small{
position:relative;
top:-7px;
padding:0;
font-weight:bold;
font-size:1.1em;
}
.log-detail table {
width: 100%;
border-collapse: collapse!important;
margin: 0;
padding: 0;
background-color: #fff!important;
}
.log-detail th {
text-align: left;
}
.log-detail th,
.log-detail td {
border: 1px solid #dfdfdf!important;
padding: 1rem!important;
}
.log-detail code{
padding:5px!important;
display:block;
background:#1d1f21;
color:#c5c8c6;
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
width:100%;
}
.log-detail .code-title{
background-color:#393e42!important;;
width:100%;
padding:2px 15px;
display:inline-block;
margin-top:10px;
color:#d2d2d2;
border-top-left-radius:3px;
border-top-right-radius:3px;
font-weight:bold;
}
.example-form {
@include mat.button-density(-5);
@include mat.form-field-density(-5);
@include mat.button-toggle-density(-5);
@include mat.datepicker-density(-5);
@include mat.all-component-densities(-5);
@include mat.icon-button-density(-5);
@include mat.icon-density(-5);
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
mat-form-field *{
font-size:13px!important;
}
.mat-mdc-form-field-infix{
width:150px;
}
}

View file

@ -0,0 +1,204 @@
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiRowDetail,
GuiSelectedRow,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { formatInTimeZone } from "date-fns-tz";
@Component({
templateUrl: "acc.component.html",
styleUrls: ["acc.component.scss"],
encapsulation: ViewEncapsulation.None,
})
export class AccComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string;
public filterText: string;
public filters: any = {
devid: false,
ip: "",
command: "",
user: false,
state: "all",
with: "all",
start_time: false,
end_time: false,
};
public filters_visible: boolean = false;
public event_action: any = [];
public event_section: any = [];
constructor(
private data_provider: dataProvider,
private router: Router,
private route: ActivatedRoute,
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public devid: number = 0;
public sorting = {
enabled: true,
multiSorting: true,
};
rowDetail: GuiRowDetail = {
enabled: true,
template: (item) => {
return `
<div class='log-detail'>
<h1>${item.name}</h1>
<small>${item.devip}</small>
<table>
<tr>
<td>User Address</td>
<td>${item.address}</td>
</tr>
<tr>
<td>User Name</td>
<td>${item.username}</td>
</tr>
<tr>
<td>Connection Type</td>
<td>${item.ctype}</td>
</tr>
<tr>
<td>Section</td>
<td>${item.section}</td>
</tr>
<tr>
<td>Exec time</td>
<td>${item.created}</td>
</tr>
</table>
<div class="code-title">Executed Config</div>
<code>
${item.config}
</code>
</div>`;
},
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
reinitgrid(field: string, $event: any) {
if (field == "start") this.filters["start_time"] = $event.target.value;
else if (field == "end") this.filters["end_time"] = $event.target.value;
else if (field == "ip") this.filters["ip"] = $event;
else if (field == "section") this.filters["section"] = $event;
else if (field == "config") this.filters["config"] = $event;
else if (field == "action") this.filters["action"] = $event;
this.initGridTable();
}
ngOnInit(): void {
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
if (this.devid > 0) {
this.filters["devid"] = this.devid;
}
this.initGridTable();
}
OnDestroy(): void {}
onSelectedRows(rows: Array<GuiSelectedRow>): void {
this.rows = rows;
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
}
removefilter(filter: any) {
delete this.filters[filter];
this.initGridTable();
}
toggleCollapse(): void {
this.filters_visible = !this.filters_visible;
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
this.data_provider.get_account_logs(this.filters).then((res) => {
let index = 1;
this.source = res.map((d: any) => {
d.index = index;
if (!_self.event_section.includes(d.section))
_self.event_section.push(d.section);
if (!_self.event_action.includes(d.action))
_self.event_action.push(d.action);
d.created = formatInTimeZone(
d.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
index += 1;
return d;
});
this.loading = false;
});
}
}

View file

@ -0,0 +1,42 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import {
ButtonModule,
CardModule,
FormModule,
GridModule,
CollapseModule,
} from "@coreui/angular";
import { AccRoutingModule } from "./acc-routing.module";
import { AccComponent } from "./acc.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import { MatSelectModule } from "@angular/material/select";
import { FormsModule } from "@angular/forms";
@NgModule({
imports: [
AccRoutingModule,
CardModule,
CommonModule,
GridModule,
FormsModule,
ButtonModule,
FormModule,
ButtonModule,
GuiGridModule,
CollapseModule,
MatFormFieldModule,
MatInputModule,
MatDatepickerModule,
MatSelectModule,
],
declarations: [AccComponent],
})
export class AccModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthComponent } from './auth.component';
const routes: Routes = [
{
path: '',
component: AuthComponent,
data: {
title: $localize`Authentication Logs`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class AuthRoutingModule {
}

View file

@ -0,0 +1,142 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="11">
Authentication Logs
</c-col>
<c-col xs [lg]="1">
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
class="fa-solid fa-filter mr-1"></i>Filter</button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<c-row>
<div [visible]="filters_visible" cCollapse>
<c-col xs [lg]="12" class="example-form">
<mat-form-field>
<mat-label>Start date</mat-label>
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
[(ngModel)]="filters['start_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>End date</mat-label>
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
[(ngModel)]="filters['end_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Connection Type</mat-label>
<mat-select placeholder="Connection Type" (ngModelChange)="reinitgrid('connection_type',$event)"
[(ngModel)]="filters['connection_type']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let con of connection_types " [value]="con">
{{con}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Select action</mat-label>
<mat-select placeholder="State" (ngModelChange)="reinitgrid('state',$event)"
[(ngModel)]="filters['state']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let ac of ['Logged In','Logged Out','Failed']" [value]="ac">
{{ac}}
</mat-option>
</mat-select>
</mat-form-field >
<mat-form-field>
<mat-label>Server</mat-label>
<mat-select placeholder="Server" (ngModelChange)="reinitgrid('server',$event)"
[(ngModel)]="filters['server']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let ac of ['Local','Mikrowizard']" [value]="ac">
{{ac}}
</mat-option>
</mat-select>
</mat-form-field >
<mat-form-field>
<mat-label>Device IP</mat-label>
<input (ngModelChange)="reinitgrid('devip',$event)" [(ngModel)]="filters['devip']" matInput>
</mat-form-field>
<mat-form-field>
<mat-label>IP/MAC</mat-label>
<input (ngModelChange)="reinitgrid('ip',$event)" [(ngModel)]="filters['ip']" matInput>
</mat-form-field>
<mat-form-field>
<mat-label>Username</mat-label>
<input (ngModelChange)="reinitgrid('user',$event)" [(ngModel)]="filters['user']" matInput>
</mat-form-field>
</c-col>
</div>
</c-row>
<gui-grid [source]="source" [paging]="paging" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [autoResizeWidth]=true>
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
<ng-template let-value="item.index" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
<i *ngIf="item.stype=='local'" cTooltip="local user"
style="color: rgb(255, 42, 0); margin-right: 3px;font-size: .7em;" class="fa-solid fa-user-tie"></i>
<i *ngIf="item.stype=='radius'" cTooltip="Update failed"
style="color: rgb(9, 97, 20); margin-right: 3px;font-size: .7em;" class="fa-solid fa-server"></i>
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device IP" field="devip">
<ng-template let-value="item.devip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Username" field="username">
<ng-template let-value="item.username" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="With" field="by">
<ng-template let-value="item.by" let-item="item" let-index="index">
<div>{{value}}</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="IP Address" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Time/Msg" field="duration">
<ng-template let-value="item.duration" let-item="item" let-index="index">
<span *ngIf="item.ltype!='failed'">{{value}}</span>
<span *ngIf="item.ltype=='failed'">{{item.message}}</span>
</ng-template>
</gui-grid-column>
<gui-grid-column header="State" field="ltype" [width]="110">
<ng-template let-value="item.ltype" let-item="item.id" let-index="index">
<c-badge color="success" *ngIf="value=='loggedin'"> Logged In</c-badge>
<c-badge color="warning" *ngIf="value=='loggedout'"> Logged Out</c-badge>
<c-badge color="danger" *ngIf="value=='failed'"> Failed</c-badge>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Date" field="created">
<ng-template let-value="item.created" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>

View file

@ -0,0 +1,36 @@
@use '@angular/material' as mat;
// Plus imports for other components in your app.
// Include the common styles for Angular Material. We include this here so that you only
// have to load a single css file for Angular Material in your app.
// Be sure that you only ever include this mixin once!
// Include theme styles for core and each component used in your app.
// Alternatively, you can import and @include the theme mixins for each component
// that you are using.
.example-form {
@include mat.button-density(-5);
@include mat.form-field-density(-5);
@include mat.button-toggle-density(-5);
@include mat.datepicker-density(-5);
@include mat.all-component-densities(-5);
@include mat.icon-button-density(-5);
@include mat.icon-density(-5);
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
mat-form-field *{
font-size:13px!important;
}
.mat-mdc-form-field-infix{
width:150px;
}
}
:host {
.legend {
small {
font-size: x-small;
}
}
}

View file

@ -0,0 +1,222 @@
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSelectedRow,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { formatInTimeZone } from "date-fns-tz";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "auth.component.html",
styleUrls: ["auth.component.scss"],
encapsulation: ViewEncapsulation.None,
})
export class AuthComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string = "UTC";
public filterText: string;
public devid: number = 0;
public filters: any = {
devid: false,
ip: "",
devip: "",
user: "",
state: "All",
server: "All",
connection_type: "All",
start_time: false,
end_time: false,
};
public filters_visible: boolean = false;
public connection_types: any = [];
constructor(
private data_provider: dataProvider,
private router: Router,
private login_checker: loginChecker,
private route: ActivatedRoute
) {
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public sorting = {
enabled: true,
multiSorting: true,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
reinitgrid(field: string, $event: any) {
if (field == "start") this.filters["start_time"] = $event.target.value;
else if (field == "end") this.filters["end_time"] = $event.target.value;
else if (field == "ip") this.filters["ip"] = $event;
else if (field == "devip") this.filters["devip"] = $event;
else if (field == "user") this.filters["user"] = $event;
else if (field == "connection_type")
this.filters["connection_type"] = $event;
else if (field == "state") this.filters["state"] = $event;
else if (field == "server") this.filters["server"] = $event;
this.initGridTable();
}
secondsToString(seconds: number) {
var years = Math.floor(seconds / 31536000);
var max = 2;
var current = 0;
var str = "";
if (years && current < max) {
str += years + "y ";
current++;
}
var days = Math.floor((seconds %= 31536000) / 86400);
if (days && current < max) {
str += days + "d ";
current++;
}
var hours = Math.floor((seconds %= 86400) / 3600);
if (hours && current < max) {
str += hours + "h ";
current++;
}
var minutes = Math.floor((seconds %= 3600) / 60);
if (minutes && current < max) {
str += minutes + "m ";
current++;
}
var seconds = seconds % 60;
if (seconds && current < max) {
str += seconds + "s ";
current++;
}
return str;
}
ngOnInit(): void {
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
if (this.devid > 0) {
this.filters["devid"] = this.devid;
}
this.initGridTable();
}
onSelectedRows(rows: Array<GuiSelectedRow>): void {
this.rows = rows;
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
}
removefilter(filter: any) {
delete this.filters[filter];
this.initGridTable();
}
toggleCollapse(): void {
this.filters_visible = !this.filters_visible;
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
this.data_provider.get_auth_logs(this.filters).then((res) => {
let index = 1;
this.source = res.map((d: any) => {
d.index = index;
if (!_self.connection_types.includes(d.by))
_self.connection_types.push(d.by);
if (!d.sessionid) {
d.stype = "local";
d.duration = "Local Access";
} else {
d.stype = "radius";
if (d.ended != 0) {
d.duration = _self.secondsToString(d.ended - d.started);
} else {
d.duration = "live";
}
}
d.created = formatInTimeZone(
d.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
index += 1;
return d;
});
this.loading = false;
});
}
}

View file

@ -0,0 +1,41 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import {
ButtonModule,
CardModule,
GridModule,
CollapseModule,
BadgeModule,
} from '@coreui/angular';
import { AuthRoutingModule } from './auth-routing.module';
import { AuthComponent } from './auth.component';
import { GuiGridModule } from '@generic-ui/ngx-grid';
import { faCoffee } from '@fortawesome/free-solid-svg-icons';
import { FormsModule } from '@angular/forms';
import {MatDatepickerModule} from '@angular/material/datepicker';
import {MatInputModule} from '@angular/material/input';
import {MatFormFieldModule} from '@angular/material/form-field';
import {MatSelectModule} from '@angular/material/select';
@NgModule({
imports: [
AuthRoutingModule,
CardModule,
CommonModule,
GridModule,
FormsModule,
ButtonModule,
GuiGridModule,
CollapseModule,
MatFormFieldModule,
MatInputModule,
MatDatepickerModule,
MatSelectModule,
BadgeModule
],
declarations: [AuthComponent]
})
export class AuthModule {
}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { BackupsComponent } from './backups.component';
const routes: Routes = [
{
path: '',
component: BackupsComponent,
data: {
title: $localize`Backups`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class BackupsRoutingModule {
}

View file

@ -0,0 +1,68 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>Backups</c-card-header>
<c-card-body>
<c-badge color="warning" *ngIf="devid!=0">Filtered Result For Device ID {{devid}}</c-badge>
<gui-grid [source]="source" [searching]="searching" [paging]="paging" [columnMenu]="columnMenu"
[sorting]="sorting" [infoPanel]="infoPanel" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [autoResizeWidth]=true>
<gui-grid-column header="#No" type="NUMBER" field="index" width=25 align="CENTER">
<ng-template let-value="item.index" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device Name" field="devname">
<ng-template let-value="item.devname" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device IP" field="devip">
<ng-template let-value="item.devip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="backup Time" field="createdC">
<ng-template let-value="item.createdC" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="File Size" field="filesize">
<ng-template let-value="item.filesize" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="MAC" field="devmac" [enabled]="false">
<ng-template let-value="item.devmac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Action" field="id">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="info" size="sm" (click)="ShowBackup(item.id)" class="mx-1"><i
style="margin: 1px 5px;color:#ffffff;" class="fa-solid fa-eye"></i>Show backup</button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #BakcupModal backdrop="static" [(visible)]="BakcupModalVisible" id="BakcupModal" size="xl">
<c-modal-header>
<h6 cModalTitle>Please Confirm Action </h6>
<button [cModalToggle]="BakcupModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<pre>
<code *ngIf="!loading" language="properties" style="height:70vh" [highlight]="codeForHighlightAuto"
lineNumbers></code></pre>
</c-modal-body>
<c-modal-footer>
<button [cModalToggle]="BakcupModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>

View file

@ -0,0 +1,153 @@
import { Component, OnInit } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSearching,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { formatInTimeZone } from "date-fns-tz";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "backups.component.html",
})
export class BackupsComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string = "UTC";
public filterText: string;
public filters: any = {};
public codeForHighlightAuto: string = "";
constructor(
private data_provider: dataProvider,
private router: Router,
private login_checker: loginChecker,
private route: ActivatedRoute
) {
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public BakcupModalVisible: boolean = false;
public devid: number = 0;
public sorting = {
enabled: true,
multiSorting: true,
};
searching: GuiSearching = {
enabled: true,
placeholder: "Search Devices",
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
this.initGridTable();
}
logger(item: any) {
console.dir(item);
}
ShowBackup(id: number) {
this.BakcupModalVisible = true;
this.loading = true;
this.data_provider.get_backup(id).then((res) => {
this.codeForHighlightAuto = res.content;
this.loading = false;
});
}
initGridTable(): void {
var _self=this;
this.data_provider.get_backups(this.devid, 0, 0, false).then((res) => {
let index = 1;
this.source = res.map((d: any) => {
d.index = index;
d.createdC = formatInTimeZone(
d.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
// d.created = [d.created.split("T")[0],d.created.split("T")[1].split(".")[0]].join(" ")
index += 1;
return d;
});
console.dir(this.source);
this.loading = false;
});
}
}

View file

@ -0,0 +1,36 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { Highlight, HighlightAuto } from "ngx-highlightjs";
import { HighlightLineNumbers } from "ngx-highlightjs/line-numbers";
import {
ButtonModule,
CardModule,
GridModule,
CollapseModule,
BadgeModule,
ModalModule,
} from "@coreui/angular";
import { BackupsRoutingModule } from "./backups-routing.module";
import { BackupsComponent } from "./backups.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
@NgModule({
imports: [
BackupsRoutingModule,
CardModule,
CommonModule,
GridModule,
ButtonModule,
ButtonModule,
GuiGridModule,
CollapseModule,
BadgeModule,
Highlight,
HighlightAuto,
HighlightLineNumbers,
ModalModule,
],
declarations: [BackupsComponent],
})
export class BackupsModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DashboardComponent } from './dashboard.component';
const routes: Routes = [
{
path: '',
component: DashboardComponent,
data: {
title: $localize`Dashboard`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DashboardRoutingModule {
}

View file

@ -0,0 +1,168 @@
<c-row *ngIf="stats">
<c-col xs>
<c-card *ngIf="stats" class="mb-1">
<c-card-header>Past 24 Hour Statics</c-card-header>
<c-card-body>
<c-row>
<c-col md="12" xl="12" xs="12">
<c-row>
<c-col class="mb-sm-1 mb-0">
<c-widget-stat-f [title]="'Failed Logins'" class="mb-1" color="danger" padding
value="{{stats['FailedLogins']}}">
<ng-template cTemplateId="widgetIconTemplate">
<i style="font-size: 2em;" class="fa-solid fa-person-circle-exclamation"></i>
</ng-template>
</c-widget-stat-f>
</c-col>
<c-col class="mb-sm-1 mb-0">
<c-widget-stat-f [title]="'Success Logins'" class="mb-1" color="success" padding
value="{{stats['SuccessfulLogins']}}">
<ng-template cTemplateId="widgetIconTemplate">
<i style="font-size: 2em;" class="fa-solid fa-arrow-right-to-bracket"></i>
</ng-template>
</c-widget-stat-f>
</c-col>
<c-col class="mb-sm-1 mb-0">
<c-widget-stat-f [title]="'Critical Events'" class="mb-1" color="danger" padding
value="{{stats['Critical']}}">
<ng-template cTemplateId="widgetIconTemplate">
<i style="font-size: 2em;" class="fa-solid fa-skull-crossbones"></i>
</ng-template>
</c-widget-stat-f>
</c-col>
<c-col class="mb-sm-1 mb-0">
<c-widget-stat-f [title]="'Warning Events'" class="mb-1" color="warning" padding
value="{{stats['Warning']}}">
<ng-template cTemplateId="widgetIconTemplate">
<i style="font-size: 2em;" class="fa-solid fa-triangle-exclamation"></i>
</ng-template>
</c-widget-stat-f>
</c-col>
<c-col class="mb-sm-1 mb-0">
<c-widget-stat-f [title]="'Info Events'" class="mb-1" color="info" padding value="{{stats['Info']}}">
<ng-template cTemplateId="widgetIconTemplate">
<i style="font-size: 2em;" class="fa-solid fa-circle-info"></i>
</ng-template>
</c-widget-stat-f>
</c-col>
</c-row>
</c-col>
</c-row>
</c-card-body>
<c-card-footer class="pb-0">
<c-col xs>
<c-row>
<c-col md="12" xl="12" xs="12">
<c-row>
<c-col class="mb-0 pb-0">
<div class="border-start border-start-4 border-start-info pt-1 px-3 mb-1">
<div class="text-medium-emphasis small">Total users</div>
<div class="fs-6 fw-semibold">{{stats['Users']}}</div>
</div>
</c-col>
<c-col class="mb-0 pb-0">
<div class="border-start border-start-4 border-start-warning pt-1 px-3 mb-1">
<div class="text-medium-emphasis small">Total Devices</div>
<div class="fs-6 fw-semibold">{{stats['Devices']}}</div>
</div>
</c-col>
<c-col class="mb-0 pb-0">
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
<div class="text-medium-emphasis small">Total Events</div>
<div class="fs-6 fw-semibold">{{stats['Events']}}</div>
</div>
</c-col>
<c-col class="mb-0 pb-0">
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
<div class="text-medium-emphasis small">Total Auth Logs</div>
<div class="fs-6 fw-semibold">{{stats['Auth']}}</div>
</div>
</c-col>
<c-col class="mb-0 pb-0">
<div class="border-start border-start-4 border-start-success pt-1 px-3 mb-1">
<div class="text-medium-emphasis small">Total Acc Logs</div>
<div class="fs-6 fw-semibold">{{stats['Acc']}}</div>
</div>
</c-col>
</c-row>
</c-col>
</c-row>
</c-col>
</c-card-footer>
</c-card>
</c-col>
</c-row>
<c-card class="mb-1">
<c-card-body>
<c-row>
<c-col sm="5">
<h4 class="card-title mb-0" id="traffic">Total Devices Traffic</h4>
</c-col>
<c-col class="d-none d-md-block" sm="7">
<form [formGroup]="trafficRadioGroup">
<c-button-group class="float-end me-3" role="group">
<input class="btn-check" formControlName="trafficRadio" type="radio" value="5m" />
<label (click)="setTrafficPeriod('5m')" cButton cFormCheckLabel color="secondary" variant="outline">5
Minues</label>
<input class="btn-check" formControlName="trafficRadio" type="radio" value="1h" />
<label (click)="setTrafficPeriod('1h')" cButton cFormCheckLabel color="secondary"
variant="outline">Hourly</label>
<input class="btn-check" formControlName="trafficRadio" type="radio" value="daily" />
<label (click)="setTrafficPeriod('daily')" cButton cFormCheckLabel color="secondary"
variant="outline">Daily</label>
<input class="btn-check" formControlName="trafficRadio" type="radio" value="live" />
<label (click)="setTrafficPeriod('live')" cButton cFormCheckLabel color="secondary"
variant="outline">Live</label>
</c-button-group>
</form>
</c-col>
</c-row>
<c-chart [data]="chart_data" [options]="options" [height]="200" type="line">
</c-chart>
</c-card-body>
</c-card>
<c-row>
<c-col xl="6" *ngIf="stats" lg="12" class="h-100">
<c-widget-stat-b [title]="stats['version']" class="mb-1 h-100" value="Version">
<div class="my-1">
<code style="padding: 0!important;">Serial:</code> <small
style="background-color: #ccc;padding: 5px;border-radius: 5px;cursor: pointer;" (click)="copy_this()"
[cdkCopyToClipboard]="stats['serial']">{{ stats['serial'] }}</small>
<span *ngIf="copy_msg" style="color: #fff!important;" class="badge text-bg-success mx-1"><i
class="fa-solid fa-check"></i>Copy</span>
</div>
<div *ngIf="!stats['license']" class="my-1">
<c-badge color="danger">Not Registred</c-badge>
<a class="mx-1" target="_blank" href="http://MikroWizard.com">Learn how to register and get automatic
updates!</a>
</div>
<div *ngIf="stats['license']" class="my-1">
<c-badge color="success">Registred</c-badge>
<c-badge class="mx-1" color="info">License Type : {{stats['license']}}</c-badge>
</div>
</c-widget-stat-b>
</c-col>
<c-col xl="6" lg="12" class="h-100">
<c-card class="mb-1 p-1 h-100" *ngIf="stats">
<c-carousel [dark]="true" [animate]="false" [wrap]="false" [interval]="1000000">
<c-carousel-indicators></c-carousel-indicators>
<c-carousel-inner>
<c-carousel-item style="display: flex;" *ngFor="let slide of stats['blog']; index as i;">
<img [src]="slide.media_content" alt="{{slide.title}}" class="d-block" loading="lazy" style=" float: left;"
height="150px" />
<div style="padding: 20px;">
<h5>{{slide.title}}</h5>
<p style="max-width: 90%;" [innerHTML]="slide.summery"></p>
</div>
</c-carousel-item>
</c-carousel-inner>
<c-carousel-control [routerLink] caption="Previous" direction="prev"></c-carousel-control>
<c-carousel-control [routerLink] caption="Next" direction="next"></c-carousel-control>
</c-carousel>
</c-card>
</c-col>
</c-row>

View file

@ -0,0 +1,217 @@
import { Component, OnInit } 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";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "dashboard.component.html",
})
export class DashboardComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string;
public copy_msg: any = false;
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.tz = res.tz;
const userId = _self.uid;
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public trafficRadioGroup = new UntypedFormGroup({
trafficRadio: new UntypedFormControl("5m"),
});
public chart_data: any = {};
Chartoptions = {
plugins: {
tooltip: {
callbacks: {
label: function (context: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
let label = context.dataset.label || "";
var res = context.parsed.y;
let unitIndex = 0;
// if (res>8) res /=8;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
switch (context.dataset.unit) {
case "rx":
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "tx":
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "rxp":
return "rxp/s :" + context.parsed.y;
break;
case "txp":
return "txp/s :" + context.parsed.y;
break;
default:
return context.parsed.y;
break;
}
},
},
},
legend: {
display: true,
},
},
maintainAspectRatio: true,
scales: {
x: { display: false },
yA: {
display: true,
stacked: true,
position: "left",
type: "linear",
color: "#17522f",
grid: {
color: "rgba(23, 82, 47, 0.3)",
backgroundColor: "transparent",
borderColor: "#f86c6b",
pointHoverBackgroundColor: "#f86c6b",
borderWidth: 1,
borderDash: [8, 5],
},
ticks: {
color: "#17522f",
callback: function (value: any, index: any, ticks: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
var res = value;
let unitIndex = 0;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
return res.toFixed(3) + " " + units[unitIndex];
},
},
scaleLabel: {
display: true,
},
},
yB: {
display: true,
stacked: true,
position: "right",
type: "linear",
grid: {
color: "rgba(23, 82, 47, 0.3)",
backgroundColor: "transparent",
borderColor: "#f86c6b",
pointHoverBackgroundColor: "#f86c6b",
borderWidth: 1,
borderDash: [8, 5],
},
border: {
width: 2,
},
ticks: {
color: "#171951",
callback: function (value: any, index: any, ticks: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
var res = value;
let unitIndex = 0;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
return res.toFixed(3) + " " + units[unitIndex];
},
},
},
},
elements: {
line: {
borderWidth: 1,
tension: 0.4,
},
point: {
radius: 2,
hitRadius: 10,
hoverRadius: 6,
},
},
};
public options: any;
public delta: string = "5m";
public stats: any = false;
ngOnInit(): void {
this.options = this.Chartoptions;
this.initStats();
this.initTrafficChart();
}
initTrafficChart(): void {
var _self = this;
this.data_provider.dashboard_traffic(this.delta).then((res) => {
let labels = res["data"]["labels"].map((d: any) => {
return (d = formatInTimeZone(
d.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss"
));
});
_self.chart_data = { datasets: res["data"]["datasets"], labels: labels };
});
}
initStats() {
var _self = this;
this.data_provider.dashboard_stats(true).then((res) => {
console.dir(res);
_self.stats = res;
});
}
copy_this() {
//show text copy to clipboard for 3 seconds
this.copy_msg = true;
setTimeout(() => {
this.copy_msg = false;
}, 3000);
}
// Traffic Chart
setTrafficPeriod(value: string): void {
this.trafficRadioGroup.setValue({ trafficRadio: value });
this.delta = value;
this.initTrafficChart();
}
}

View file

@ -0,0 +1,43 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ReactiveFormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
GridModule,
WidgetModule,
ProgressModule,
TemplateIdDirective,
BadgeModule,
CarouselModule,
} from "@coreui/angular";
import { ChartjsModule } from "@coreui/angular-chartjs";
import { DashboardRoutingModule } from "./dashboard-routing.module";
import { DashboardComponent } from "./dashboard.component";
import { ClipboardModule } from "@angular/cdk/clipboard";
@NgModule({
imports: [
DashboardRoutingModule,
CardModule,
WidgetModule,
CommonModule,
GridModule,
ProgressModule,
ReactiveFormsModule,
ButtonModule,
TemplateIdDirective,
ButtonModule,
ButtonGroupModule,
ChartjsModule,
CarouselModule,
BadgeModule,
ClipboardModule,
],
declarations: [DashboardComponent],
})
export class DashboardModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DeviceComponent } from './device.component';
const routes: Routes = [
{
path: '',
component: DeviceComponent,
data: {
title: $localize`Device Detail`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DeviceRoutingModule {
}

View file

@ -0,0 +1,167 @@
<c-alert style="margin-bottom: 5px;margin-top: 5px;" *ngIf="!loading && devdata['update_availble']"
(click)="logger(devdata['sensors'])" color="warning">Firmware
Update availble For This Device!</c-alert>
<c-alert style="margin-bottom: 5px;margin-top: 5px;" *ngIf="!loading && devdata['upgrade_availble']"
(click)="logger(devdata['upgrade_availble'])" color="info">Device is updated but needs to upgrade firmware!</c-alert>
<c-row *ngIf="!loading">
<c-col xs>
<c-card class="mb-1">
<c-card-header>
<c-row>
<c-col md="3">
<h3>{{devdata['name'] }}<small style="font-size: 50%;"> ( {{devdata['ip'] }} )</small></h3>
</c-col>
<c-col md="9" class="justify-content-end" style="text-align: end;">
<c-button-group class="mb-2" aria-label="Upate interval" role="group">
<button cButton color="primary" (click)="delta='5m';updateData()" [active]="delta=='5m'">5 minute</button>
<button cButton color="primary" (click)="delta='1h';updateData()" [active]="delta=='1h'">Hourly</button>
<button cButton color="primary" (click)="delta='daily';updateData()"
[active]="delta=='daily'">Daily</button>
<button cButton color="primary" (click)="delta='live';updateData()" [active]="delta=='live'">Live</button>
</c-button-group>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<app-widgets-dropdown *ngIf="!loading" [devicedata]=devsensors></app-widgets-dropdown>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-row>
<c-col xs>
<c-card class="mb-1">
<c-card-body>
<c-row style="flex-direction:row">
<ng-container *ngFor="let item of devdata | keyvalue; index as i">
<!-- <c-col *ngIf="checkitem(item)" class="mb-2" >
<c-card color="dark" textColor="white" class="h-100 ">
<c-card-header style="padding: 5px 0 2px 9px;text-transform: capitalize;">{{item.key}}</c-card-header>
<c-card-body class="bg-gradient" style="padding:2px 0 2px 9px;">
<p cCardText>{{item.value}}</p>
</c-card-body>
</c-card>
</c-col> -->
<c-input-group *ngIf="checkitem(item)" class="mr-0 ml-0 mb-1"
style="padding-right:unset;width: auto;flex: 1 1 auto;flex-flow: nowrap;flex: unset;">
<span
style="padding: 0.175rem 0.35rem;background-color:#4f5d73;text-transform: capitalize;color:#fff;font-size:0.7rem"
cInputGroupText>{{item.key}}</span>
<!-- <input cFormControl disabled style="font-size:0.8rem" [value]="item.value"/> -->
<span _ngcontent-ng-c666080582="" cinputgrouptext=""
style="padding: 0.175rem 0.35rem;color: rgba(44, 56, 74, 0.95);font-size: 0.7rem;background-color: #d8dbe0;border-color: #b1b7c1;"
class="input-group-text">{{ item.value }}</span>
<!-- <span style="background-color:#4f5d73;text-transform: capitalize;color:#fff;font-size:0.8rem" cInputGroupText >{{item.key}}</span> -->
</c-input-group>
</ng-container>
</c-row>
</c-card-body>
</c-card>
</c-col>
</c-row>
<!-- Mikrotik interfaces table -->
<c-row>
<c-col xs>
<c-card class="mb-1">
<c-card-body>
<c-row style="flex-direction:row">
<gui-grid [source]="interfaces" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
[rowSelection]="rowSelection" [autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
{{value}} - {{item['default-name']}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="MAC" field="mac-address">
<ng-template let-value="item['mac-address']" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="rx" field="rx-byte">
<ng-template let-value="item['rx-byte']" let-item="item" let-index="index">
<div>{{convert_bw_human(value,'rx')}}</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="tx" field="tx-byte">
<ng-template let-value="item['tx-byte']" let-item="item" let-index="index">
{{convert_bw_human(value,'tx')}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="l2mtu" field="l2mtu">
<ng-template let-value="item.l2mtu" let-item="item" let-index="index">
curr:{{value}}<br />
max : {{item['max-l2mtu']}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="rx/s" field="rx-bits-per-second" [enabled]="false">
<ng-template let-value="item['rx-bits-per-second']" let-item="item" let-index="index">
{{convert_bw_human(value,'rx')}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="tx/s" field="tx-bits-per-second" [enabled]="false">
<ng-template let-value="item['tx-bits-per-second']" let-item="item" let-index="index">
{{convert_bw_human(value,'tx')}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Created" field="created" [enabled]="false">
<ng-template let-value="item.created" let-item="item.id" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Last Up" field="last-link-up-time">
<ng-template let-value="item['last-link-up-time']" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Created" field="created" [enabled]="false">
<ng-template let-value="item.created" let-item="item.id" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" field="action" width="100" align="center">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="info" size="sm" (click)="show_interface_rate(item['default-name'])"
class="mx-1"><i class="fa-solid fa-chart-line"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-row>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #staticBackdropModal backdrop="static" size="xl" [visible]="InterfaceChartModalVisible"
id="InterfaceChartModal">
<c-modal-header>
<h5 cModalTitle>{{interface_rate['name']}}</h5>
<button [cModalToggle]="staticBackdropModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-chart [data]="interface_rate" [options]="options" type="line">
</c-chart>
</c-modal-body>
<c-modal-footer>
<button [cModalToggle]="staticBackdropModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>

View file

@ -0,0 +1,7 @@
:host {
.legend {
small {
font-size: x-small;
}
}
}

View file

@ -0,0 +1,36 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonModule, DropdownModule, GridModule, WidgetModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { ChartjsModule } from '@coreui/angular-chartjs';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../icons/icon-subset';
import { DeviceComponent } from './device.component';
describe('DeviceComponent', () => {
let component: DeviceComponent;
let fixture: ComponentFixture<DeviceComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DeviceComponent ],
imports: [WidgetModule, DropdownModule, IconModule, ButtonModule, ChartjsModule, GridModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(DeviceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,437 @@
import { Component, OnInit } from "@angular/core";
import { Router, ActivatedRoute } from "@angular/router";
import { dataProvider } from "../../providers/mikrowizard/data";
import { loginChecker } from "../../providers/login_checker";
import {
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { __setFunctionName } from "tslib";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "device.component.html",
styleUrls: ["device.component.scss"],
})
export class DeviceComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string;
constructor(
private data_provider: dataProvider,
private route: ActivatedRoute,
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public devdata: any;
public devsensors: any;
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public InterfaceChartModalVisible: boolean = false;
public rows: any = [];
public Selectedrows: any;
public devid: number = 0;
public data_interval: any;
public delta: string = "5m";
public total_type: string = "bps";
public interface_rate: any = {};
public options: any;
public sorting = {
enabled: true,
multiSorting: true,
};
public interfaces: Array<any> = [];
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
Chartoptions = {
plugins: {
tooltip: {
callbacks: {
label: function (context: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
let label = context.dataset.label || "";
var res = context.parsed.y;
let unitIndex = 0;
// if (res>8) res /=8;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
switch (context.dataset.unit) {
case "rx":
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "tx":
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "rxp":
return "rxp/s :" + context.parsed.y;
break;
case "txp":
return "txp/s :" + context.parsed.y;
break;
default:
return context.parsed.y;
break;
}
},
},
},
legend: {
display: true,
},
},
maintainAspectRatio: true,
scales: {
x: { display: false },
yA: {
display: true,
stacked: true,
position: "left",
type: "linear",
color: "#17522f",
grid: {
color: "rgba(23, 82, 47, 0.3)",
borderDash: [5, 5],
},
ticks: {
color: "#17522f",
callback: function (value: any, index: any, ticks: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
var res = value;
let unitIndex = 0;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
return res.toFixed(3) + " " + units[unitIndex];
},
},
scaleLabel: {
display: true,
},
},
yB: {
display: true,
stacked: true,
position: "right",
type: "linear",
grid: {
color: "rgba(23, 25, 81, 0.3)",
borderDash: [8, 8],
},
border: {
width: 2,
},
ticks: {
color: "#171951",
callback: function (value: any, index: any, ticks: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
var res = value;
let unitIndex = 0;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
return res.toFixed(3) + " " + units[unitIndex];
},
},
},
},
elements: {
line: {
borderWidth: 1,
tension: 0.4,
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 6,
},
},
};
ngOnInit(): void {
this.devid = Number(this.route.snapshot.paramMap.get("id"));
this.options = this.Chartoptions;
this.initDeviceInfo();
}
optionsDefault = {
plugins: {
legend: {
display: false,
},
},
maintainAspectRatio: true,
scales: {
x: {
grid: {
display: false,
drawBorder: false,
},
ticks: {
display: false,
},
},
y: {
display: false,
grid: {
display: false,
},
ticks: {
display: false,
},
},
},
elements: {
line: {
borderWidth: 1,
tension: 0.4,
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 6,
},
},
};
setOptions() {
for (let idx = 0; idx < 5; idx++) {
const options = JSON.parse(JSON.stringify(this.optionsDefault));
switch (idx) {
case 0: {
this.options.push(options);
break;
}
case 1: {
options.scales.y.min = -9;
options.scales.y.max = 39;
this.options.push(options);
break;
}
case 2: {
options.scales.x = { display: false };
options.scales.y = { display: false };
options.elements.line.borderWidth = 2;
options.elements.point.radius = 2;
this.options.push(options);
break;
}
case 3: {
options.scales.x.grid = { display: false, drawTicks: false };
options.scales.x.grid = {
display: false,
drawTicks: false,
drawBorder: false,
};
options.scales.y.min = undefined;
options.scales.y.max = undefined;
options.elements = {};
this.options.push(options);
break;
}
case 4: {
options.plugins = {
tooltip: {
callbacks: {
label: function (context: any) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
let label = context.dataset.label || "";
var res = context.parsed.y;
let unitIndex = 0;
// if (res>8) res /=8;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
switch (context.dataset.unit) {
case "rx":
return "rx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "tx":
return "tx/s :" + res.toFixed(3) + " " + units[unitIndex];
break;
case "rxp":
return "rxp/s :" + context.parsed.y;
break;
case "txp":
return "txp/s :" + context.parsed.y;
break;
default:
return context.parsed.y;
break;
}
},
},
},
legend: {
display: false,
},
};
options.scales = {
x: { display: false },
yA: {
display: false,
stacked: true,
position: "left",
type: "linear",
scaleLabel: {
display: true,
},
},
yB: {
display: false,
stacked: true,
position: "right",
type: "linear",
},
};
options.elements.line.borderWidth = 2;
options.elements.point.radius = 2;
this.options.push(options);
break;
}
}
}
}
logger(item: any) {
console.dir(item);
}
updateData(): void {
var _self = this;
this.data_provider.get_dev_info(this.devid).then((res) => {
_self.devdata = res;
_self.interfaces = res.interfaces;
_self.data_provider
.get_dev_sensors(_self.devid, _self.delta, _self.total_type)
.then((res) => {
_self.devsensors = res;
_self.loading = false;
});
});
}
checkitem(item: any) {
if (item.value && !item.key.match("sensors|id|_availble|interfaces")) {
return true;
} else {
return false;
}
}
convert_bw_human(mynumber: number = 0, unit: string) {
const units = ["bit", "Kib", "Mib", "Gib", "Tib"];
let unitIndex = 0;
while (mynumber >= 1024 && unitIndex < units.length - 1) {
mynumber /= 1024;
unitIndex++;
}
switch (unit) {
case "rx":
return mynumber.toFixed(3) + " " + units[unitIndex];
break;
case "tx":
return mynumber.toFixed(3) + " " + units[unitIndex];
break;
default:
return mynumber;
break;
}
}
show_interface_rate(name: string) {
var _self = this;
_self.InterfaceChartModalVisible = false;
this.data_provider
.get_dev_ifstat(_self.devid, _self.delta, name, _self.total_type)
.then((res) => {
_self.interface_rate = res["data"];
_self.InterfaceChartModalVisible = true;
});
}
initDeviceInfo(): void {
var _self = this;
clearInterval(this.data_interval);
this.updateData();
this.data_interval = setInterval(() => {
this.data_provider.get_dev_info(this.devid).then((res) => {
_self.devdata = res;
_self.interfaces = res.interfaces;
_self.data_provider
.get_dev_sensors(_self.devid, _self.delta, _self.total_type)
.then((res) => {
_self.devsensors = res;
_self.loading = false;
});
});
}, 1000000);
}
}

View file

@ -0,0 +1,42 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
ProgressModule,
NavbarModule,
AlertModule,
ModalModule,
} from "@coreui/angular";
import { ChartjsModule } from "@coreui/angular-chartjs";
import { DeviceRoutingModule } from "./device-routing.module";
import { DeviceComponent } from "./device.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { WidgetsModule } from "../widgets/widgets.module";
@NgModule({
imports: [
DeviceRoutingModule,
CardModule,
AlertModule,
CommonModule,
GridModule,
ProgressModule,
FormModule,
ButtonModule,
ButtonGroupModule,
ChartjsModule,
WidgetsModule,
GuiGridModule,
NavbarModule,
ModalModule,
],
declarations: [DeviceComponent],
})
export class DeviceModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DevLogsComponent } from './devlogs.component';
const routes: Routes = [
{
path: '',
component: DevLogsComponent,
data: {
title: $localize`Device Logs`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DevLogsRoutingModule {
}

View file

@ -0,0 +1,139 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="11">
Device LOGS
</c-col>
<c-col xs [lg]="1">
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
class="fa-solid fa-filter mr-1"></i>Filter</button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<c-row>
<div [visible]="filters_visible" cCollapse>
<c-col xs [lg]="12" class="example-form">
<mat-form-field>
<mat-label>Start date</mat-label>
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
[(ngModel)]="filters['start_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>End date</mat-label>
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
[(ngModel)]="filters['end_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<mat-form-field *ngIf="event_types_filtered.length>0">
<mat-label>Select event type</mat-label>
<mat-select placeholder="Event Type" [multiple]="true" (ngModelChange)="reinitgrid('detail',$event)"
[(ngModel)]="filters['detail']" #multiSelect>
<mat-option>
<ngx-mat-select-search [showToggleAllCheckbox]="true" placeholderLabel="Find type..."
[formControl]="bankMultiFilterCtrl"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let bank of event_types_filtered " [value]="bank">
{{bank}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Select event type</mat-label>
<mat-select placeholder="Event Level" (ngModelChange)="reinitgrid('level',$event)"
[(ngModel)]="filters['level']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let level of ['Critical','Warning','Error','info'] " [value]="level">
{{level}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Status</mat-label>
<mat-select placeholder="Event Status" (ngModelChange)="reinitgrid('status',$event)"
[(ngModel)]="filters['status']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option [value]="true">Fixed</mat-option>
<mat-option [value]="false">Not Fixed</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Comment</mat-label>
<input (ngModelChange)="reinitgrid('comment',$event)" [(ngModel)]="filters['comment']" matInput>
</mat-form-field>
</c-col>
</div>
</c-row>
<gui-grid wid [rowDetail]="rowDetail" [horizontalGrid]="true" [rowHeight]="52" [source]="source"
[columnMenu]="columnMenu" [paging]="paging" [sorting]="sorting" [infoPanel]="infoPanel"
[autoResizeWidth]="true">
<gui-grid-column header="#No" type="NUMBER" field="index" width="1" align="CENTER">
<ng-template let-value="item.index" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="level" width='90' wid field="level">
<ng-template let-value="item.level" let-item="item" let-index="index">
<c-badge style="cursor: pointer; font-weight: normal" color="danger" *ngIf="value == 'Critical'">{{ value
}}</c-badge>
<c-badge style="cursor: pointer; font-weight: normal" color="warning" *ngIf="value == 'Error'">{{ value
}}</c-badge>
<c-badge style="cursor: pointer; font-weight: normal" color="warning" *ngIf="value == 'Warning'">{{ value
}}</c-badge>
<c-badge style="cursor: pointer; font-weight: normal; min-width: 60px;" color="info"
*ngIf="value == 'info'">{{ value }}</c-badge>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Event" width='200' field="detail">
<ng-template let-value="item.detail" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Detail" field="comment">
<ng-template let-value="item.comment" let-item="item" let-index="index">
<div class="gui-dev-info">
{{ value }}
</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Source" width='90' field="src">
<ng-template let-value="item.src" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="status" width='100' field="status" align="CENTER">
<ng-template let-value="item.status" let-item="item" let-index="index">
<c-badge style=" cursor: pointer; font-weight: normal" color="success"
*ngIf="value == true">Fixed</c-badge>
<c-badge style="cursor: pointer; font-weight: normal" color="danger" *ngIf="value != true">Not
Fixed</c-badge>
</ng-template>
</gui-grid-column>
<gui-grid-column header="eventtime" width='200' field="eventtime">
<ng-template let-value="item.eventtime" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Device" width='200' field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
<div class="gui-dev-info">
<span class="gui-dev-info-name">{{ value }}</span>
<span class="gui-dev-info-ip">{{ item.devip }}</span>
</div>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>

View file

@ -0,0 +1,125 @@
@use '@angular/material' as mat;
:host {
.legend {
small {
font-size: x-small;
}
}
}
// .gui-drawer-content{
// background-color: #efefef!important;
// }
.log-detail{
padding:30px 10px;
box-sizing:border-box;
}
.log-detail h1{
font-size:2em;
font-weight:bold;
margin:0;
padding:0;
}
.log-detail small{
position:relative;
top:-7px;
padding:0;
font-weight:bold;
font-size:1.1em;
}
.log-detail table {
width: 100%;
border-collapse: collapse!important;
margin: 5px 0 0 0;
padding: 0;
background-color: #ffffff29 !important;
color: #000;
}
.log-detail th {
text-align: left;
}
.log-detail th,
.log-detail td {
border: 1px solid #ffffff4a!important;
padding: 0.5rem!important;
}
.gui-close-icon-wrapper .gui-close-icon:after,.gui-close-icon-wrapper .gui-close-icon:before {
background-color: #ffffff !important;
}
.log-detail code{
padding:5px!important;
display:block;
background:#1d1f21;
color:#c5c8c6;
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
width:100%;
}
.log-detail .code-title{
background-color:#393e42!important;;
width:100%;
padding:2px 15px;
display:inline-block;
margin-top:10px;
color:#d2d2d2;
border-top-left-radius:3px;
border-top-right-radius:3px;
font-weight:bold;
}
.gui-row-detail{
height:100%;
}
.gui-dev-info {
display: inline-flex;
flex-direction: column;
align-items: stretch;
align-content: center;
justify-content: center;
white-space: normal;
line-height: 17px;
}
.gui-dev-info-name {
font-weight: bold;
}
.gui-dev-info-ip {
color: #525252;
font-style: italic;
font-size: 13px;
overflow: hidden;
}
.gui-row-detail > div{
height:100%;
}
.gui-row-detail .log-detail{
height:100%;
}
.gui-structure{
min-height: 550px;
}
.example-form {
@include mat.button-density(-5);
@include mat.form-field-density(-5);
@include mat.button-toggle-density(-5);
@include mat.datepicker-density(-5);
@include mat.all-component-densities(-5);
@include mat.icon-button-density(-5);
@include mat.icon-density(-5);
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
mat-form-field *{
font-size:13px!important;
}
.mat-mdc-form-field-infix{
width:150px;
}
}

View file

@ -0,0 +1,234 @@
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { FormControl } from "@angular/forms";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiRowDetail,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { formatInTimeZone } from "date-fns-tz";
import { takeUntil } from "rxjs/operators";
import { Subject } from "rxjs";
@Component({
templateUrl: "devlogs.component.html",
styleUrls: ["devlogs.component.scss"],
encapsulation: ViewEncapsulation.None,
})
export class DevLogsComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string = "UTC"
public filterText: string;
public filters: any = {
start_time: false,
end_time: false,
detail: [],
level: false,
comment: "",
status: "all",
};
public event_types: any = [];
public event_types_filtered: any = [];
public filters_visible: boolean = false;
constructor(
private data_provider: dataProvider,
private router: Router,
private route: ActivatedRoute,
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public devid: number = 0;
public sorting = {
enabled: true,
multiSorting: true,
};
public bankMultiFilterCtrl: FormControl = new FormControl<string>("");
protected _onDestroy = new Subject<void>();
public campaignOnestart: any;
public campaignOneend: any;
rowDetail: GuiRowDetail = {
enabled: true,
template: (item) => {
return `
<div class='log-detail' style="color:#fff;background-color:${(() => {
if (item.level == "Critical") return "#e55353";
else if (item.level == "Warning") return "#f9b115";
else item.level == "Info";
return "#3399ff";
})()}">
<h1>Device :</h1>
<table>
<tr>
<td>Device Name</td>
<td>${item.name}</td>
</tr>
<tr>
<td>Device IP</td>
<td>${item.devip}</td>
</tr>
<tr>
<td>Device MAC</td>
<td>${item.mac}</td>
</tr>
</table>
<h1 style="margin-top: 10px;">Alert Detail :
</h1>
<table>
<tr>
<td>Event</td>
<td>${item.detail}</td>
</tr>
<tr>
<td>Event Status</td>
<td><span (click)="logger(${item})" style="display:inline-block;background-color:${
item.status ? "green" : "#db4848"
} ;padding: 4px 10px;border-radius: 5px;line-height: 10px;color: rgba(255, 255, 255, 0.87);">${
item.status ? "Fixed" : "Not Fixed"
}</span></td>
</tr>
<tr>
<td>Event Category</td>
<td>${item.eventtype}</td>
</tr>
<tr>
<td>Exec time</td>
<td>${item.eventtime}</td>
</tr>
<tr>
<td>Detail</td>
<td>${item.comment}</td>
</tr>
<tr>
<td>Source</td>
<td>${item.src}</td>
</tr>
</table>
</div>`;
},
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
var _self = this;
this.devid = Number(this.route.snapshot.paramMap.get("devid"));
if (this.devid > 0) {
this.filters["devid"] = this.devid;
}
this.initGridTable();
this.bankMultiFilterCtrl.valueChanges
.pipe(takeUntil(this._onDestroy))
.subscribe(() => {
let search = this.bankMultiFilterCtrl.value;
if (!search) {
this.event_types_filtered = this.event_types;
}
_self.event_types_filtered = _self.event_types_filtered.filter(
(item: any) => item.toLowerCase().indexOf(search.toLowerCase()) > -1
);
console.dir(_self.event_types_filtered);
});
}
toggleCollapse(): void {
this.filters_visible = !this.filters_visible;
}
logger(item: any) {
console.dir(item);
}
reinitgrid(field: string, $event: any) {
if (field == "start") this.filters["start_time"] = $event.target.value;
else if (field == "end") this.filters["end_time"] = $event.target.value;
else if (field == "detail") this.filters["detail"] = $event;
else if (field == "level") this.filters["level"] = $event;
else if (field == "comment") this.filters["comment"] = $event;
else if (field == "status") this.filters["status"] = $event;
this.initGridTable();
}
initGridTable(): void {
var _self = this;
this.data_provider.get_dev_logs(this.filters).then((res) => {
let index = 1;
this.source = res.map((d: any) => {
d.index = index;
if (d.detail.indexOf("Link Down") >= 0) d.detail = "Link Down";
else if (d.detail.indexOf("Link Up") >= 0) d.detail = "Link Up";
if (!_self.event_types.includes(d.detail))
_self.event_types.push(d.detail);
d.eventtime = formatInTimeZone(
d.eventtime.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
index += 1;
return d;
});
_self.event_types_filtered = _self.event_types;
console.dir(this.source);
this.loading = false;
});
}
}

View file

@ -0,0 +1,47 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { ReactiveFormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
CollapseModule,
BadgeModule,
} from "@coreui/angular";
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
import { DevLogsRoutingModule } from "./devlogs-routing.module";
import { DevLogsComponent } from "./devlogs.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import { FormsModule } from "@angular/forms";
import { MatSelectModule } from "@angular/material/select";
@NgModule({
imports: [
DevLogsRoutingModule,
CardModule,
CommonModule,
GridModule,
ReactiveFormsModule,
FormsModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
CollapseModule,
BadgeModule,
MatInputModule,
MatFormFieldModule,
MatSelectModule,
NgxMatSelectSearchModule,
MatDatepickerModule,
],
declarations: [DevLogsComponent],
})
export class DevLogsModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DevicesComponent } from './devices.component';
const routes: Routes = [
{
path: '',
component: DevicesComponent,
data: {
title: $localize`Device List`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DevicesRoutingModule {
}

View file

@ -0,0 +1,346 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="3">
Devices
</c-col>
<c-col xs [lg]="9">
<h6 style="text-align: right;">
<button cButton color="danger" class="mx-1" size="sm" style="color: #fff;">{{updates.length}} Updatable
</button>
<button cButton color="warning" class="mx-1" size="sm" style="color: #fff;">{{upgrades.length}}
Upgradable</button>
|
<button cButton color="dark" (click)="scanwizard(1,'')" [cModalToggle]="ScannerModal.id" class="mx-1"
size="sm" style="color: #fff;"><i class="fa-solid fa-magnifying-glass"></i> Scanner</button>
</h6>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<c-row>
<c-col [lg]="3">
<c-input-group *ngIf="groups.length>0">
<span cInputGroupText>Group</span>
<select [(ngModel)]="selected_group" (change)="groupselected($event)" cSelect>
<option value="0" [selected]="selected_group == 0">Select a group</option>
<option *ngFor="let g of groups" [value]="g.id" [selected]=" selected_group == g.id ">{{g.name}}
</option>
</select>
</c-input-group>
</c-col>
</c-row>
<gui-grid #grid [rowClass]="rowClass" [source]="source" [searching]="searching" [paging]="paging"
[columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel" [rowSelection]="rowSelection"
(selectedRows)="onSelectedRows($event)" [autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
<img *ngIf="item.status=='updating'" width="20px" src="assets/img/loading.svg" />
<i *ngIf="item.status=='updated'" cTooltip="Tooltip text"
style="color: green; margin-right: 3px;font-size: .7em;" class="fa-solid fa-check"></i>
<i *ngIf="item.status=='failed'" cTooltip="Update failed"
style="color: red; margin-right: 3px;font-size: .7em;" class="fa-solid fa-x"></i>
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="CPU Type" field="arch">
<ng-template let-value="item.arch" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Firmware" field="current_firmware">
<ng-template let-value="item.current_firmware" let-item="item" let-index="index">
<div>{{value}}</div>
<i *ngIf="item.update_availble" cTooltip="Firmware Update availble"
class="fa-solid fa-up-long text-primary mx-1"></i>
<i *ngIf="item.update_availble" cTooltip="Device Firmware not Upgraded"
class="fa-solid fa-microchip text-danger mx-1"></i>
</ng-template>
</gui-grid-column>
<gui-grid-column header="IP Address" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="MAC Address" field="mac">
<ng-template let-value="item.mac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="License" field="license" [enabled]="false">
<ng-template let-value="item.license" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Interface" field="interface" [enabled]="false">
<ng-template let-value="item.interface" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Created" field="created" [enabled]="false">
<ng-template let-value="item.created" let-item="item.id" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Uptime" field="uptime">
<ng-template let-value="item.uptime" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Created" field="created" [enabled]="false">
<ng-template let-value="item.created" let-item="item.id" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column align="center" [cellEditing]="false" [sorting]="false" header="Action">
<ng-template let-value="value" let-item="item">
<button size="sm" shape="rounded-0" variant="outline" cButton color="primary" (click)="show_detail(item)"
style="border: none;padding: 4px 7px;"><i class="fa-regular fa-eye"></i><small> Details</small>
</button>
<button color="primary" shape="rounded-0" variant="ghost" style="padding: 4px 7px;"
[matMenuTriggerFor]="menu" cButton>
<i class="fa-solid fa-bars"></i>
</button>
<mat-menu #menu="matMenu">
<div cListGroup>
<li cListGroupItem [active]="false" color="dark">Actions Menu</li>
<button size="sm" (click)="single_device_action(item,'edit')" style="padding: 4px 7px;"
cListGroupItem><i class="fa-solid fa-pencil"></i><small>
Edit Device</small></button>
<button size="sm" (click)="single_device_action(item,'firmware')" style="padding: 4px 7px;"
cListGroupItem><i class="text-primary fa-solid fa-magnifying-glass"></i><small>
Check Firmware</small></button>
<button size="sm" (click)="single_device_action(item,'update')" style="padding: 4px 7px;"
cListGroupItem><i class="text-primary fa-solid fa-upload"></i><small>
Update Firmware</small></button>
<!-- <button size="sm" (click)="single_device_action(item,'upgrade')" style="padding: 4px 7px;"
cListGroupItem><i class="text-primary fa-solid fa-microchip"></i><small>
Upgrade Firmware</small></button> -->
<button size="sm" (click)="single_device_action(item,'logauth')" style="padding: 4px 7px;"
cListGroupItem><i class="text-primary fa-regular fa-clock"></i><small>
Show Auth Logs</small></button>
<button size="sm" (click)="single_device_action(item,'logacc')" style="padding: 4px 7px;"
cListGroupItem><i class="text-primary fa-solid fa-table-list"></i><small>
Show Acc Logs</small></button>
<button size="sm" (click)="single_device_action(item,'backup')" style="padding: 4px 7px;"
cListGroupItem><i class="text-success fa-solid fa-database"></i><small>
Show Backups</small></button>
<button size="sm" (click)="single_device_action(item,'delete')" style="padding: 4px 7px;"
cListGroupItem><i class="text-danger fa-solid fa-trash"></i><small>
Delete Device</small></button>
</div>
</mat-menu>
</ng-template>
</gui-grid-column>
</gui-grid>
<c-navbar *ngIf="rows.length!= 0" class="bg-light" colorScheme="light" expand="lg">
<c-container [fluid]="true">
<a cNavbarBrand href="javascript:;">
Batch Action :
</a>
<button [cNavbarToggler]="collapseRef"></button>
<div #collapseRef="cCollapse" [navbar]="true" cCollapse>
<c-navbar-nav class="me-auto mb-2 mb-lg-0">
<c-nav-item>
<c-dropdown variant="nav-item" [popper]="false">
<a cDropdownToggle cNavLink>Select</a>
<ul cDropdownMenu dark>
<li><button cDropdownItem (click)="ConfirmAction='checkfirm';ConfirmModalVisible=true">Check
Firmware</button></li>
<li><button cDropdownItem
(click)="ConfirmAction='update';ConfirmModalVisible=true">Update</button></li>
<!-- <li><button cDropdownItem>Upgrade</button></li>
<li><button cDropdownItem>Update and Upgrade</button></li> -->
</ul>
</c-dropdown>
</c-nav-item>
</c-navbar-nav>
</div>
</c-container>
</c-navbar>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #ScannerModal [visible]="scanwizard_modal" (visibleChange)="handleScanwizard_modal($event)" backdrop="static"
id="ScannerModal">
<c-modal-header>
<h5 cModalTitle>Scanner Wizard</h5>
<button [cModalToggle]="ScannerModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<div *ngIf="scanwizard_step==1" class="mb-5" style="text-align: center;">
<h5 class="mb-5">Please select searching method</h5>
<button cButton color="info" (click)="scanwizard(2,'chip')" [disabled]="true" class="mx-1" size="lg"><img width="100px"
src="assets/img/chip.png" /><br />Layer2 Scan</button>
<button cButton color="info" (click)="scanwizard(2,'ip')" class="mx-1" size="lg"><img width="100px"
src="assets/img/tcpip.png" /><br />TCP/IP Scan</button>
</div>
<div *ngIf="scanwizard_step==2 && scan_type=='ip'" class="mb-2" style="text-align: center;">
<h5 class="mb-5">Please Provide needed information</h5>
<c-input-group class="mb-3">
<span cInputGroupText>Start IP</span>
<input aria-label="start" cFormControl [(ngModel)]="ip_scanner['start']" [valid]="checkvalid('start')"
placeholder="192.168.1.1" />
<span cInputGroupText>End IP</span>
<input aria-label="end" cFormControl [(ngModel)]="ip_scanner['end']" [valid]="checkvalid('end')"
placeholder="192.168.1.255" />
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>Username</span>
<input aria-label="start" cFormControl [(ngModel)]="ip_scanner['user']" placeholder="Default username" />
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>Password</span>
<input aria-label="end" cFormControl [(ngModel)]="ip_scanner['password']" placeholder="********" />
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>Port</span>
<input aria-label="end" cFormControl [valid]="checkvalid('port')" [(ngModel)]="ip_scanner['port']"
placeholder="8728" />
</c-input-group>
<button cButton color="info" (click)="scanwizard(3,'ip')" class="mx-1" size="lg">Start Scanning</button>
</div>
<div class="mwand" *ngIf="scanwizard_step==3">
<svg viewBox="0 0 203 148.27">
<g id="wand">
<g class="cls-1">
<path d="M194.63,152.18v-7.76C194.6,147,194.6,149.59,194.63,152.18Z" transform="translate(-10 -31.06)" />
</g>
<rect class="cls-2" x="5.07" y="129.83" width="117.08" height="17.1"
transform="translate(-77.95 30.6) rotate(-35.06)" />
<rect class="cls-3" x="106.38" y="88.26" width="32.89" height="17.1"
transform="translate(-43.33 57.07) rotate(-35.06)" />
<ellipse class="cls-4" cx="136.21" cy="87.42" rx="3.29" ry="8.55"
transform="translate(-35.5 63.06) rotate(-35.06)" />
<ellipse class="cls-2" cx="15.6" cy="172.07" rx="3.29" ry="8.55"
transform="translate(-106.02 9.13) rotate(-35.06)" />
<ellipse class="cls-3" cx="109.5" cy="106.16" rx="3.29" ry="8.55"
transform="translate(-51.12 51.12) rotate(-35.06)" />
<path class="cls-5" d="M138.71,85.25s4.26,6.06,2.68,9L20.15,179.32s-3.27.49-7.53-5.57Z"
transform="translate(-10 -31.06)" />
</g>
<g id="stars">
<g id="star1">
<polygon class="cls-6"
points="142.22 4.88 138.59 13.13 147.13 17.7 137.94 19.78 139.9 28.82 132.07 23.15 125.96 29.86 125.38 20.71 115.81 20.03 122.93 14.3 117.1 6.74 126.55 8.74 128.85 0 133.51 8.22 142.22 4.88" />
<polygon class="cls-7"
points="142.29 4.89 136.56 13.87 144.96 17.35 136.17 18.98 138.3 26.2 131.33 20.74 125.88 29.85 132.06 23.11 139.91 28.82 137.95 19.81 147.12 17.74 138.59 13.11 142.29 4.89" />
</g>
<g id="star2">
<polygon class="cls-6"
points="166.3 14.45 165.13 17.09 167.87 18.55 164.93 19.22 165.55 22.12 163.04 20.3 161.09 22.45 160.9 19.52 157.83 19.3 160.11 17.46 158.25 15.04 161.27 15.68 162.01 12.88 163.51 15.52 166.3 14.45" />
<polygon class="cls-7"
points="166.32 14.45 164.48 17.33 167.18 18.44 164.36 18.96 165.04 21.28 162.81 19.53 161.06 22.45 163.04 20.29 165.56 22.12 164.93 19.23 167.87 18.57 165.13 17.08 166.32 14.45" />
</g>
<g id="star3">
<polygon class="cls-6"
points="202.01 38.12 194.78 46.34 203 54.75 191.61 53.79 190.56 64.97 183.57 55.54 174.05 61.06 176.73 50.27 165.91 45.98 176.24 41.95 172.26 31.08 182.46 36.84 188.33 27.58 190.71 38.8 202.01 38.12" />
<polygon class="cls-7"
points="202.08 38.15 192.17 46.45 200.62 53.55 189.85 52.21 189.67 61.34 183.6 52.48 173.96 61.03 183.58 55.49 190.57 64.97 191.6 53.83 202.97 54.79 194.8 46.31 202.08 38.15" />
</g>
<g id="star4">
<polygon class="cls-6"
points="155.07 63.05 153.01 67.75 157.87 70.35 152.64 71.52 153.75 76.67 149.3 73.44 145.83 77.25 145.5 72.05 140.06 71.67 144.1 68.41 140.79 64.11 146.16 65.25 147.47 60.28 150.13 64.95 155.07 63.05" />
<polygon class="cls-7"
points="155.11 63.06 151.86 68.17 156.63 70.14 151.63 71.07 152.84 75.17 148.88 72.07 145.78 77.25 149.29 73.42 153.76 76.67 152.65 71.54 157.86 70.36 153.01 67.73 155.11 63.06" />
</g>
</g>
</svg>
<h5>{{scanwizard_prompt}}</h5>
</div>
</c-modal-body>
<c-modal-footer>
<small *ngIf="scan_type=='ip'" style="margin: 0 auto;">Empty username and password means system default
configuration</small>
</c-modal-footer>
</c-modal>
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="runConfirmModal">
<c-modal-header>
<h6 cModalTitle>Please Confirm Action </h6>
<button [cModalToggle]="ConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<span *ngIf="ConfirmAction=='checkfirm'">Are you sure that You want to Check firmware of selected devices for
update?</span>
<span *ngIf="ConfirmAction=='update'">Are you sure that You want to <code>update firmware</code> of selected
devices?</span>
<ng-container *ngIf="ConfirmAction=='delete'">
Are you sure that You want to<code>Delete Device {{selected_device.name}} ?</code><br />
<hr>
<p class="text-danger">
All Related Configuration will be deleted/Modified :<br /><br />
* User Permision Related to this Device<br />
* Device Groups including this Device<br />
* All Logs related to this device<br />
</p>
</ng-container>
</c-modal-body>
<c-modal-footer>
<button *ngIf="ConfirmAction=='checkfirm'" (click)="check_firmware()" cButton color="danger">
Yes
</button>
<button *ngIf="ConfirmAction=='update'" (click)="update_firmware()" cButton color="danger">
Yes
</button>
<button *ngIf="ConfirmAction=='delete'" (click)="delete_device()" cButton color="danger">
Yes,Delete Device
</button>
<button cButton [cModalToggle]="ConfirmModal.id" color="info">
Cancel
</button>
</c-modal-footer>
</c-modal>
<c-modal #EditDevModal backdrop="static" [(visible)]="EditDevModalVisible" id="EditDevModal">
<c-modal-header>
<h6 cModalTitle>Editing Device</h6>
<button [cModalToggle]="EditDevModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body *ngIf="EditDevModalVisible">
<c-input-group class="mb-3">
<span cInputGroupText>Username</span>
<input aria-label="start" [(ngModel)]="selected_device['editform']['user_name']" cFormControl
placeholder=" username" />
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>Password</span>
<input aria-label="start" [type]="show_pass ? 'text' : 'password'"
[(ngModel)]="selected_device['editform']['password']" cFormControl placeholder=" username" />
<button cButton (click)="show_pass=!show_pass" color="secondary" variant="outline">
<i *ngIf="show_pass" class="fa-solid fa-eye"></i>
<i *ngIf="!show_pass" class="fa-solid fa-eye-slash"></i>
</button>
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>ip</span>
<input aria-label="start" [(ngModel)]="selected_device['editform']['ip']" cFormControl
placeholder="Default username" />
</c-input-group>
<c-input-group class="mb-3">
<span cInputGroupText>peer ip</span>
<select aria-label="Default select example" cFormControl [(ngModel)]="selected_device['editform']['peer_ip']" cSelect>
<option *ngFor="let o of selected_device['editform']['ips']" [value]="o">{{o}}</option>
</select>
</c-input-group>
</c-modal-body>
<c-modal-footer>
<button cButton (click)="save_device()" color="danger">
Save
</button>
<button cButton [cModalToggle]="EditDevModal.id" color="info">
Cancel
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,460 @@
import {
Component,
OnInit,
OnDestroy,
QueryList,
ViewChild,
ViewChildren,
} from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiGridComponent,
GuiGridApi,
GuiRowClass,
GuiSearching,
GuiSelectedRow,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { ToasterComponent } from "@coreui/angular";
import { AppToastComponent } from "../toast-simple/toast.component";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "devices.component.html",
})
export class DevicesComponent implements OnInit, OnDestroy {
public uid: number;
public uname: string;
constructor(
private data_provider: dataProvider,
private route: ActivatedRoute,
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChild("grid", { static: true }) gridComponent: GuiGridComponent;
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public upgrades: any = [];
public updates: any = [];
public scanwizard_step: number = 1;
public scanwizard_modal: boolean = false;
public ConfirmModalVisible: boolean = false;
public EditDevModalVisible: boolean = false;
public ConfirmAction: string = "checkfirm";
public scan_type: string = "ip";
public scan_timer: any;
public list_update_timer: any;
public scanwizard_prompt: string = "Scanning Network!";
public groups: any = [];
public selected_group: number = 0;
public selected_devices: any = {};
public selected_device: any = {};
public show_pass: boolean = false;
toasterForm = {
autohide: true,
delay: 3000,
position: "fixed",
fade: true,
closeButton: true,
};
rowClass: GuiRowClass = {
class: "row-highlighted",
};
public sorting = {
enabled: true,
multiSorting: true,
};
public ip_scanner: any;
searching: GuiSearching = {
enabled: true,
placeholder: "Search Devices",
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
this.selected_group = Number(this.route.snapshot.paramMap.get("id"));
this.initGridTable();
this.get_groups();
}
show_detail(item: any) {
this.router.navigate(["/device-stats", { id: item.id }]);
}
single_device_action(dev: any, action: string) {
const api: GuiGridApi = this.gridComponent.api;
api.unselectAll();
this.Selectedrows = [dev["id"]];
switch (action) {
case "edit":
this.edit_device_form(dev);
break;
case "firmware":
this.check_firmware();
break;
case "update":
this.update_firmware();
break;
case "upgrade":
this.upgrade_firmware();
break;
case "logauth":
this.router.navigate(["/authlog", { devid: dev.id }]);
break;
case "logacc":
this.router.navigate(["/accountlog", { devid: dev.id }]);
break;
case "backup":
this.router.navigate(["/backups", { devid: dev.id }]);
break;
case "reboot":
this.reboot_devices();
break;
case "delete":
this.ConfirmAction = "delete";
this.ConfirmModalVisible = true;
break;
}
}
edit_device_form(dev: any) {
var _self = this;
this.selected_device = dev;
this.data_provider.get_editform(dev.id).then((res) => {
if ("error" in res) {
if (res.error.indexOf("Unauthorized")) {
_self.show_toast(
"Error",
"You are not authorized to perform this action",
"danger"
);
}
} else {
this.selected_device["editform"] = res;
this.EditDevModalVisible = true;
}
});
}
save_device() {
var _self = this;
this.data_provider
.save_editform(this.selected_device["editform"])
.then((res) => {
_self.show_toast("Success", "Device Saved", "success");
this.initGridTable();
this.EditDevModalVisible = false;
});
}
groupselected(item: any) {
this.selected_group = item.target.value;
if (this.selected_group != 0) {
this.router.navigate([".", { id: this.selected_group }]);
}
this.initGridTable();
}
delete_device() {
var _self = this;
this.ConfirmModalVisible = false;
this.data_provider.delete_devices(this.Selectedrows).then((res) => {
_self.show_toast("Success", "Device Deleted", "success");
this.initGridTable();
});
}
onSelectedRows(rows: Array<GuiSelectedRow>): void {
this.rows = rows;
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
}
checkvalid(type: string): boolean {
var rx =
/^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;
if (type == "start") return rx.test(this.ip_scanner.start);
else if (type == "end") return rx.test(this.ip_scanner.end);
else if (type == "port") {
if (this.ip_scanner.port == "") return true;
return Boolean(Number(this.ip_scanner.port));
} else return false;
}
scanwizard(step: number, type: string) {
var _self = this;
this.data_provider.scan_devs(this.scan_type, {}).then((res) => {
if (res.status == true) {
_self.scanwizard_step = 3;
this.wait_scan();
return;
}
if (step == 1) {
_self.scan_type = "";
_self.ip_scanner = {
start: "",
end: "",
port: "",
user: "",
password: "",
};
}
if (step == 2) {
_self.scan_type = "";
if (type == "ip") {
_self.scan_type = "ip";
} else if (type == "chip") {
_self.scan_type = "mac";
}
}
if (step == 3) {
if (_self.scan_type == "ip") {
if (_self.ip_scanner.start == "" || _self.ip_scanner.end == "") {
return;
}
//test if start and end are valid ip addresses and port is valid
if (
!_self.checkvalid("start") ||
!_self.checkvalid("end") ||
!_self.checkvalid("port")
) {
return;
}
if (_self.ip_scanner.port == "") {
_self.ip_scanner.port = false;
}
if (_self.ip_scanner.user == "") {
_self.ip_scanner.user = false;
}
if (_self.ip_scanner.password == "") {
_self.ip_scanner.password = false;
}
_self.data_provider
.scan_devs(_self.scan_type, _self.ip_scanner)
.then((res) => {
_self.scanwizard_prompt = "Scanning Network!";
_self.wait_scan();
});
} else if (type == "chip") {
_self.data_provider
.scan_devs(_self.scan_type, _self.ip_scanner)
.then((res) => {
// console.dir(res);
});
}
}
_self.scanwizard_step = step;
});
}
wait_scan() {
clearTimeout(this.scan_timer);
var _self = this;
this.scan_timer = setTimeout(function () {
_self.data_provider.scan_devs(_self.scan_type, {}).then((res) => {
if (res.status == false) {
_self.initGridTable();
_self.scanwizard_prompt = "Scanning done! Reloading data";
setTimeout(function () {
_self.scanwizard_modal = false;
}, 3000);
} else {
_self.wait_scan();
}
});
}, 3000);
}
logger(item: any) {
console.dir(item);
}
handleScanwizard_modal(event: any) {
this.scanwizard_modal = event;
}
show_toast(title: string, body: string, color: string) {
const { ...props } = { ...this.toasterForm, color, title, body };
const componentRef = this.viewChildren.first.addToast(
AppToastComponent,
props,
{}
);
componentRef.instance["closeButton"] = props.closeButton;
}
check_firmware() {
var _self = this;
this.data_provider
.check_firmware(this.Selectedrows.toString())
.then((res) => {
_self.show_toast("info", "Checking Firmwares", "light");
_self.ConfirmModalVisible = false;
setTimeout(function () {
if (_self.Selectedrows.length < 1) _self.initGridTable();
}, 1);
});
}
update_firmware() {
var _self = this;
this.data_provider
.update_firmware(this.Selectedrows.toString())
.then((res) => {
_self.show_toast("info", "Updating Firmwares Sent", "light");
_self.initGridTable();
});
}
upgrade_firmware() {
var _self = this;
this.data_provider
.upgrade_firmware(this.Selectedrows.toString())
.then((res) => {
_self.show_toast("info", "Upgrading Firmwares", "light");
_self.initGridTable();
});
}
reboot_devices() {
var _self = this;
this.data_provider
.reboot_devices(this.Selectedrows.toString())
.then((res) => {
_self.show_toast("info", "Reboot sent", "light");
_self.ConfirmModalVisible = !_self.ConfirmModalVisible;
_self.initGridTable();
});
}
get_groups() {
var _self = this;
this.data_provider.get_devgroup_list().then((res) => {
_self.groups = res;
});
}
initGridTable(): void {
var _self = this;
_self.upgrades = [];
_self.updates = [];
clearTimeout(this.list_update_timer);
var data = {
group_id: this.selected_group,
search: false,
page: this.paging.page,
size: this.paging.pageSize,
};
_self.data_provider.get_dev_list(data).then((res) => {
_self.source = res.map((x: any) => {
if (x.upgrade_availble) _self.upgrades.push(x);
if (x.update_availble) _self.updates.push(x);
return x;
});
_self.device_interval();
_self.loading = false;
});
}
device_interval() {
var _self = this;
var data = {
group_id: this.selected_group,
search: false,
page: this.paging.page,
size: this.paging.pageSize,
};
clearTimeout(this.list_update_timer);
_self.list_update_timer = setTimeout(function () {
// _self.data_provider.get_dev_list(data).then(res => {
// _self.source =res.map( (x:any) => {
// if(x.upgrade_availble)
// _self.upgrades.push(x);
// if(x.update_availble)
// _self.updates.push(x);
// return x;
// });
// // _self.device_interval()
// _self.loading = false;
// });
//we don't want to reload table if user is selected devices from list
if (_self.Selectedrows.length < 1) _self.initGridTable();
}, 10000);
}
ngOnDestroy(): void {
clearTimeout(this.scan_timer);
}
}

View file

@ -0,0 +1,50 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
NavModule,
NavbarModule,
CollapseModule,
DropdownModule,
BadgeModule,
ToastModule,
ModalModule,
ListGroupModule,
TooltipModule,
} from "@coreui/angular";
import { MatMenuModule } from "@angular/material/menu";
import { DevicesRoutingModule } from "./devices-routing.module";
import { DevicesComponent } from "./devices.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
@NgModule({
imports: [
DevicesRoutingModule,
CardModule,
NavModule,
CommonModule,
GridModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
NavbarModule,
CollapseModule,
DropdownModule,
BadgeModule,
ModalModule,
ToastModule,
FormsModule,
ListGroupModule,
MatMenuModule,
TooltipModule,
],
declarations: [DevicesComponent],
})
export class DevicesModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DevicesGroupComponent } from './devgroup.component';
const routes: Routes = [
{
path: '',
component: DevicesGroupComponent,
data: {
title: $localize`Device Group`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class DevicesGroupRoutingModule {
}

View file

@ -0,0 +1,178 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="10">
Device Groups
</c-col>
<c-col xs [lg]="2" style="text-align: right;">
<button cButton color="primary" (click)="editAddGroup({},'showadd')"><i
class="fa-solid fa-plus"></i></button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<gui-grid [source]="source" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
[autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Devices" field="array_agg" align="CENTER">
<ng-template let-value="item.array_agg" let-item="item" let-index="index">
<ng-container *ngIf="item.id==1 ; then Default;else NotDefault">
</ng-container>
<ng-template #Default>
<c-badge color="info">All Devices</c-badge>
</ng-template>
<ng-template #NotDefault>
<c-badge color="info" *ngIf="value[0]==null && item.id!=1">0 Members</c-badge>
<c-badge color="info" *ngIf="value[0]!=null">{{value.length}} Members</c-badge>
</ng-template>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Create Time" field="created">
<ng-template let-value="item.created" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button [disabled]="value==1" cButton color="warning" size="sm" (click)="editAddGroup(item,'showedit');"
class="mx-1"><i class="fa-regular fa-pen-to-square"></i></button>
<button [disabled]="value==1" cButton color="info" size="sm" (click)="show_members(item.id);"
class="mx-1"><i class="fa-regular fa-eye"></i></button>
<button [disabled]="value==1" cButton color="danger" size="sm" (click)="show_delete_group(item);"
class="mx-1"><i class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #EditGroupModal backdrop="static" size="lg" [(visible)]="EditGroupModalVisible" id="EditGroupModal">
<c-modal-header>
<h5 cModalTitle> Group Edit</h5>
<button [cModalToggle]="EditGroupModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-input-group class="mb-3">
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="Group Name" [(ngModel)]="currentGroup['name']" />
<label cLabel for="floatingInput">Group Name</label>
</div>
</c-input-group>
<c-input-group class="mb-3">
<h5>Group Members :</h5>
<gui-grid [autoResizeWidth]="true" [searching]="searching" [source]="groupMembers" [columnMenu]="columnMenu"
[sorting]="sorting" [infoPanel]="infoPanel" [rowSelection]="rowSelection"
(selectedRows)="onSelectedRowsMembers($event)" [autoResizeWidth]=true [paging]="paging">
<gui-grid-column header="Member Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="perm Name" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="danger" size="sm" (click)="remove_from_group(item.id)"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
<br />
<button *ngIf="MemberRows.length!= 0" style="margin: 10px 0;" cButton color="danger" size="sm"><i
class="fa-regular fa-trash-can"></i>Delete {{MemberRows.length}} Selected</button>
</c-input-group>
<hr />
<button cButton color="primary" (click)="show_new_member_form()">+ Add new Members</button>
</c-modal-body>
<c-modal-footer>
<button cButton color="primary" (click)="save_group()">save</button>
<button [cModalToggle]="EditGroupModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #NewMemberModal backdrop="static" size="lg" [(visible)]="NewMemberModalVisible" id="NewMemberModal">
<c-modal-header>
<h5 cModalTitle>Members not in Group</h5>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-input-group class="mb-3">
<h5>Members Availble to add:</h5>
<gui-grid [autoResizeWidth]="true" *ngIf="NewMemberModalVisible" [searching]="searching"
[source]="availbleMembers" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
[rowSelection]="rowSelection" (selectedRows)="onSelectedRowsNewMembers($event)" [autoResizeWidth]=true
[paging]="paging">
<gui-grid-column header="Group Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="perm Name" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="perm Name" field="mac">
<ng-template let-value="item.mac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
<br />
</c-input-group>
<hr />
</c-modal-body>
<c-modal-footer>
<button *ngIf="NewMemberRows.length!= 0" (click)="add_new_members()" cButton color="primary">Add {{
NewMemberRows.length }}</button>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="ConfirmModal">
<c-modal-header>
<h5 cModalTitle> Are You Sure?</h5>
<button [cModalToggle]="ConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<ng-container *ngIf="ConfirmAction=='delete'">
<span>
Are you sure that you want to delete <b class="text-danger-emphasis">{{currentGroup['name']}}</b>?
</span>
<br />
<p class="text-danger">
All Related Configuration will be deleted/Modified :<br />
* User Permision Related to this group<br />
* Tasks including this Group<br />
</p>
</ng-container>
</c-modal-body>
<c-modal-footer>
<button cButton color="danger" (click)="delete_group()">Confirm</button>
<button [cModalToggle]="ConfirmModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>

View file

@ -0,0 +1,240 @@
import { Component, OnInit } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSearching,
GuiSelectedRow,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "devgroup.component.html",
})
export class DevicesGroupComponent implements OnInit {
public uid: number;
public uname: string;
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public MemberRows: any = [];
public NewMemberRows: any = [];
public SelectedMemberRows: any;
public SelectedNewMemberRows: any;
public ConfirmModalVisible: boolean = false;
public ConfirmAction: string = "delete";
public EditGroupModalVisible: boolean = false;
public NewMemberModalVisible: boolean = false;
public groupMembers: any = [];
public availbleMembers: any = [];
public currentGroup: any = {
array_agg: [],
created: "",
id: 0,
name: "",
};
public DefaultCurrentGroup: any = {
array_agg: [],
created: "",
id: 0,
name: "",
};
public sorting = {
enabled: true,
multiSorting: true,
};
searching: GuiSearching = {
enabled: true,
placeholder: "Search Devices",
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
this.initGridTable();
}
public show_members(id: number) {
this.router.navigate(["devices", { id: id }]);
}
public show_delete_group(item: any) {
this.currentGroup = item;
this.ConfirmModalVisible = true;
this.ConfirmAction = "delete";
}
public delete_group() {
var _self = this;
this.data_provider.delete_group(this.currentGroup.id).then((res) => {
_self.initGridTable();
_self.ConfirmModalVisible = false;
});
}
onSelectedRowsMembers(rows: Array<GuiSelectedRow>): void {
this.MemberRows = rows;
this.SelectedMemberRows = rows.map((m: GuiSelectedRow) => m.source.id);
}
onSelectedRowsNewMembers(rows: Array<GuiSelectedRow>): void {
this.NewMemberRows = rows;
this.SelectedNewMemberRows = rows.map((m: GuiSelectedRow) => m.source.id);
}
add_new_members() {
var _self = this;
this.currentGroup["array_agg"] = [
...new Set(
this.currentGroup["array_agg"].concat(this.SelectedNewMemberRows)
),
];
this.groupMembers = [
...new Set(
this.groupMembers.concat(
this.NewMemberRows.map((m: GuiSelectedRow) => m.source)
)
),
];
this.NewMemberModalVisible = false;
}
remove_from_group(id: number) {
var _self = this;
this.currentGroup["array_agg"] = this.currentGroup["array_agg"].filter(
(x: any) => x != id
);
this.groupMembers = this.groupMembers.filter((x: any) => x.id != id);
}
save_group() {
var _self = this;
this.data_provider.update_save_group(this.currentGroup).then((res) => {
_self.initGridTable();
_self.EditGroupModalVisible = false;
});
}
editAddGroup(item: any, action: string) {
var _self = this;
if (action == "showadd") {
this.currentGroup = { ...this.DefaultCurrentGroup };
this.groupMembers = [];
this.EditGroupModalVisible = true;
return;
}
this.currentGroup = item;
this.groupMembers = [];
this.data_provider.get_devgroup_members(item.id).then((res) => {
_self.groupMembers = res;
_self.currentGroup = { ...item };
// simple hack to remove null from devices list
_self.currentGroup["array_agg"] = item["array_agg"].filter(
(x: any) => x != null
);
_self.EditGroupModalVisible = true;
});
}
show_new_member_form() {
this.NewMemberModalVisible = true;
var _self = this;
_self.availbleMembers = [];
this.SelectedNewMemberRows = [];
this.NewMemberRows = [];
var data = {
group_id: false,
search: false,
page: false,
size: 10000,
};
_self.data_provider.get_dev_list(data).then((res) => {
_self.availbleMembers = res.filter(
(x: any) => !_self.currentGroup["array_agg"].includes(x.id)
);
_self.NewMemberModalVisible = true;
});
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
this.data_provider.get_devgroup_list().then((res) => {
this.source = res;
this.loading = false;
});
}
}

View file

@ -0,0 +1,35 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
CollapseModule,
ModalModule,
} from "@coreui/angular";
import { DevicesGroupRoutingModule } from "./devgroup-routing.module";
import { DevicesGroupComponent } from "./devgroup.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { BadgeModule } from "@coreui/angular";
import { FormsModule } from "@angular/forms";
@NgModule({
imports: [
DevicesGroupRoutingModule,
CardModule,
CommonModule,
GridModule,
FormsModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
CollapseModule,
ModalModule,
BadgeModule,
],
declarations: [DevicesGroupComponent],
})
export class DevicesGroupModule {}

View file

@ -0,0 +1,16 @@
<div class="fade-in">
<c-card>
<c-card-header>
{{ title }}
<app-docs-link href="https://github.com/coreui/coreui-icons" text="GitHub"></app-docs-link>
</c-card-header>
<c-card-body>
<c-row class="text-center">
<c-col *ngFor="let icon of icons" class="mb-5" md="3" sm="4" xl="2" xs="6">
<svg cIcon [name]="icon[0]" [title]="icon[0]" size="3xl"></svg>
<div>{{ toKebabCase(icon[0]) }}</div>
</c-col>
</c-row>
</c-card-body>
</c-card>
</div>

View file

@ -0,0 +1,46 @@
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { IconSetService } from '@coreui/icons-angular';
import { brandSet, flagSet, freeSet } from '@coreui/icons';
@Component({
templateUrl: 'coreui-icons.component.html',
providers: [IconSetService],
})
export class CoreUIIconsComponent implements OnInit {
public title = 'CoreUI Icons';
public icons!: [string, string[]][];
constructor(
private route: ActivatedRoute, public iconSet: IconSetService
) {
iconSet.icons = { ...freeSet, ...brandSet, ...flagSet };
}
ngOnInit() {
const path = this.route?.routeConfig?.path;
let prefix = 'cil';
if (path === 'coreui-icons') {
this.title = `${this.title} - Free`;
prefix = 'cil';
} else if (path === 'brands') {
this.title = `${this.title} - Brands`;
prefix = 'cib';
} else if (path === 'flags') {
this.title = `${this.title} - Flags`;
prefix = 'cif';
}
this.icons = this.getIconsView(prefix);
}
toKebabCase(str: string) {
return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
}
getIconsView(prefix: string) {
return Object.entries(this.iconSet.icons).filter((icon) => {
return icon[0].startsWith(prefix);
});
}
}

View file

@ -0,0 +1,48 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { CoreUIIconsComponent } from './coreui-icons.component';
const routes: Routes = [
{
path: '',
data: {
title: 'Icons'
},
children: [
{
path: '',
pathMatch: 'full',
redirectTo: 'coreui-icons'
},
{
path: 'coreui-icons',
component: CoreUIIconsComponent,
data: {
title: 'CoreUI Icons'
}
},
{
path: 'brands',
component: CoreUIIconsComponent,
data: {
title: 'Brands'
}
},
{
path: 'flags',
component: CoreUIIconsComponent,
data: {
title: 'Flags'
}
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class IconsRoutingModule {
}

View file

@ -0,0 +1,25 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { CardModule, GridModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { CoreUIIconsComponent } from './coreui-icons.component';
import { IconsRoutingModule } from './icons-routing.module';
import { DocsComponentsModule } from '@docs-components/docs-components.module';
@NgModule({
imports: [
IconsRoutingModule,
CardModule,
GridModule,
IconModule,
CommonModule,
DocsComponentsModule
],
declarations: [
CoreUIIconsComponent
]
})
export class IconsModule {
}

View file

@ -0,0 +1,51 @@
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
<c-container>
<c-row class="justify-content-center">
<c-col md="8">
<c-card-group>
<c-card [ngStyle]="{'width.%': 44}" class="text-white py-5" style="background-color: #303c54;">
<c-card-body class="text-center">
<img style="width: 200px;" src="assets/img/brand/mikrowizard-full.jpg">
</c-card-body>
</c-card>
<c-card class="p-4">
<c-card-body>
<form cForm [formGroup]="loginForm" >
<h1>Login</h1>
<p class="text-medium-emphasis">Sign In to your account</p>
<c-input-group class="mb-3">
<span cInputGroupText>
<svg cIcon name="cilUser"></svg>
</span>
<input autoComplete="username" cFormControl placeholder="Username" formControlName="username" required #username/>
</c-input-group>
<c-input-group class="mb-1">
<span cInputGroupText>
<svg cIcon name="cilLockLocked"></svg>
</span>
<input
autoComplete="current-password"
cFormControl
placeholder="Password"
type="password"
formControlName="password"
required #password
/>
</c-input-group>
<code *ngIf="error_msg"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error_msg}}</small></code>
<c-row>
<c-col mb-3 xs="6">
<button type="submit" cButton (click)="onClickSubmit()" class="px-4" color="primary">
Login
</button>
</c-col>
</c-row>
</form>
</c-card-body>
</c-card>
</c-card-group>
</c-col>
</c-row>
</c-container>
</div>

View file

@ -0,0 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonModule, CardModule, FormModule, GridModule } from '@coreui/angular';
import { LoginComponent } from './login.component';
import { IconModule } from '@coreui/icons-angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ LoginComponent ],
imports: [FormModule, CardModule, GridModule, ButtonModule, IconModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,66 @@
import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { dataProvider } from '../../../providers/mikrowizard/data';
import { loginChecker } from '../../../providers/login_checker';
import { Validators, FormControl, FormGroup} from '@angular/forms';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
export class LoginComponent {
public loginForm: FormGroup;
public forgotForm: FormGroup;
public error_msg: string = "";
public forgot_error_msg: string = "";
public success_msg: string = "";
public submitted = false;
public forgot_page: boolean = false;
public forgot_btn_disable: boolean = false;
constructor(
private router: Router,
private data_provider: dataProvider,
private login_checker: loginChecker,
) {
this.createForm();
};
createForm() {
this.loginForm = new FormGroup({
username: new FormControl(''),
password: new FormControl(''),
ga_code: new FormControl(''),
});
this.forgotForm = new FormGroup({
email: new FormControl(''),
});
}
onClickSubmit(){
var _self = this;
let uname = _self.loginForm.get('username')!.value;
let passwd = _self.loginForm.get('password')!.value;
let ga_code = '';
console.dir(uname);
_self.data_provider.login(uname, passwd, '').then(res => {
if ('uid' in res && res['uid']){
_self.error_msg = "";
_self.login_checker.setStatus(true);
_self.router.navigate(['/'], {replaceUrl: true});
}
else {
if ('reason' in res) {
}
else
_self.error_msg = res.error;
}
}).catch(err => {
_self.error_msg = "Wrong username or password!";
});
// });
}
}

View file

@ -0,0 +1,22 @@
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
<c-container>
<c-row class="justify-content-center">
<c-col md="6">
<div class="clearfix">
<h1 class="float-start display-3 me-4">404</h1>
<h4 class="pt-3">Oops! You're lost.</h4>
<p class="text-medium-emphasis float-start">
The page you are looking for was not found.
</p>
</div>
<c-input-group class="input-prepend">
<span cInputGroupText>
<svg cIcon name="cilMagnifyingGlass"></svg>
</span>
<input cFormControl placeholder="What are you looking for?" type="text" />
<button cButton color="info">Search</button>
</c-input-group>
</c-col>
</c-row>
</c-container>
</div>

View file

@ -0,0 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonModule, FormModule, GridModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { Page404Component } from './page404.component';
describe('Page404Component', () => {
let component: Page404Component;
let fixture: ComponentFixture<Page404Component>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ Page404Component ],
imports: [FormModule, GridModule, ButtonModule, IconModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(Page404Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-page404',
templateUrl: './page404.component.html',
styleUrls: ['./page404.component.scss']
})
export class Page404Component {
constructor() { }
}

View file

@ -0,0 +1,22 @@
<div class="bg-light min-vh-100 d-flex flex-row align-items-center">
<c-container>
<c-row class="justify-content-center">
<c-col md="6">
<span class="clearfix">
<h1 class="float-start display-3 me-4">500</h1>
<h4 class="pt-3">Houston, we have a problem!</h4>
<p class="text-medium-emphasis float-start">
The page you are looking for is temporarily unavailable.
</p>
</span>
<c-input-group class="input-prepend">
<span cInputGroupText>
<svg cIcon name="cilMagnifyingGlass"></svg>
</span>
<input cFormControl placeholder="What are you looking for?" type="text" />
<button cButton color="info">Search</button>
</c-input-group>
</c-col>
</c-row>
</c-container>
</div>

View file

@ -0,0 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonModule, FormModule, GridModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { Page500Component } from './page500.component';
describe('Page500Component', () => {
let component: Page500Component;
let fixture: ComponentFixture<Page500Component>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ Page500Component ],
imports: [GridModule, ButtonModule, FormModule, IconModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(Page500Component);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,12 @@
import { Component } from '@angular/core';
@Component({
selector: 'app-page500',
templateUrl: './page500.component.html',
styleUrls: ['./page500.component.scss']
})
export class Page500Component {
constructor() { }
}

View file

@ -0,0 +1,36 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { Page404Component } from './page404/page404.component';
import { Page500Component } from './page500/page500.component';
import { LoginComponent } from './login/login.component';
const routes: Routes = [
{
path: '404',
component: Page404Component,
data: {
title: 'Page 404'
}
},
{
path: '500',
component: Page500Component,
data: {
title: 'Page 500'
}
},
{
path: 'login',
component: LoginComponent,
data: {
title: 'Login Page'
}
},
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PagesRoutingModule {
}

View file

@ -0,0 +1,32 @@
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { PagesRoutingModule } from './pages-routing.module';
import { LoginComponent } from './login/login.component';
import { Page404Component } from './page404/page404.component';
import { Page500Component } from './page500/page500.component';
import { ButtonModule, CardModule, FormModule, GridModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
@NgModule({
declarations: [
LoginComponent,
Page404Component,
Page500Component
],
imports: [
CommonModule,
PagesRoutingModule,
CardModule,
ButtonModule,
GridModule,
IconModule,
FormModule,
FormsModule,
ReactiveFormsModule
]
})
export class PagesModule {
}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { PermissionsComponent } from './permissions.component';
const routes: Routes = [
{
path: '',
component: PermissionsComponent,
data: {
title: $localize`Permissions`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class PermissionsRoutingModule {
}

View file

@ -0,0 +1,137 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="10">
Permissions
</c-col>
<c-col xs [lg]="2" style="text-align: right;">
<button cButton color="primary" (click)="editAddTask({},'showadd')"><i
class="fa-solid fa-plus"></i></button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<gui-grid [rowHeight]="82" [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu"
[sorting]="sorting" [autoResizeWidth]=true [paging]="paging">
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column width="auto" header="Perms" field="perms">
<ng-template let-value="item.role" let-item="item" let-index="index">
<div style="text-wrap: initial;">
<ng-container *ngFor="let perm of item['perms'] | keyvalue">
<c-badge *ngIf="perm.value" class="m-1" color="success">{{perm.key}}</c-badge>
</ng-container>
</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="warning" size="sm" class="mx-1" (click)="editAddTask(item,'edit');"><i
class="fa-regular fa-pen-to-square"></i></button>
<button cButton color="danger" size="sm" (click)="confirm_delete(item);"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal-header>
<c-modal #EditTaskModal backdrop="static" size="lg" [(visible)]="EditTaskModalVisible" id="EditTaskModal">
<c-modal-header>
<h5 *ngIf="action=='edit'" cModalTitle>Editing Permission {{SelectedPerm['name']}}</h5>
<h5 *ngIf="action=='add'" cModalTitle>Adding new Permission Rule</h5>
<button [cModalToggle]="EditTaskModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="permname" [(ngModel)]="permname" />
<label cLabel for="floatingInput">Name</label>
</div>
<c-row>
<c-col>
<c-form-check *ngFor='let val of ["api","ftp","password","read","romon","sniff","telnet","tikapp","winbox"]'
[switch]="true">
<input cFormCheckInput [(ngModel)]="perms[val] " type="checkbox" />
<label cFormCheckLabel>{{ val}}</label>
</c-form-check>
</c-col>
<c-col>
<c-form-check
*ngFor='let val of ["dude","local","policy","reboot","rest-api","sensitive","ssh","test","web","write"]'
[switch]="true">
<input cFormCheckInput [(ngModel)]="perms[val] " type="checkbox" />
<label cFormCheckLabel>{{ val}}</label>
</c-form-check>
</c-col>
</c-row>
<ng-container *ngIf="SelectedMembers.length>0 && EditTaskModalVisible">
<c-badge class="mx-1" *ngFor="let id of splitids(SelectedPermItems)"
color="dark">{{get_member_by_id(id).name}}</c-badge>
</ng-container>
<!--
<c-input-group class="mb-3">
<cron-editor #cronEditorDemo1 [(ngModel)]="SelectedPerm['cron']" [options]="cronOptions">Cron here...</cron-editor>
</c-input-group>
-->
</c-modal-body>
<c-modal-footer>
<button *ngIf="action=='add'" (click)="submit('add')" cButton color="primary">Add</button>
<button *ngIf="action=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible" id="DeleteConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedPerm['name'] }}</h5>
<button [cModalToggle]="DeleteConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to delete following Permission?
<br />
<br />
<table style="width: 100%;">
<tr>
<td><b>Permission name : </b>{{ SelectedPerm['name'] }}
</tr>
<tr>
<td>
<ng-container *ngFor="let perm of SelectedPerm['perms'] | keyvalue">
<c-badge *ngIf="perm.value" class="m-1" color="success">{{perm.key}}</c-badge>
</ng-container>
</td>
</tr>
<tr>
<td>
<p><code
style="padding: 0!important;"><b>Warning:</b> ALL Given <b>device access</b> related to this permision in Users Section <b>will be deleted</b> for each user</code>
</p>
</td>
</tr>
</table>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete('',true)" cButton color="danger">
Yes,Delete!
</button>
<button [cModalToggle]="DeleteConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,260 @@
import { Component, OnInit, QueryList, ViewChildren } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
} from "@generic-ui/ngx-grid";
import { ToasterComponent } from "@coreui/angular";
import { AppToastComponent } from "../toast-simple/toast.component";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "permissions.component.html",
})
export class PermissionsComponent implements OnInit {
public uid: number;
public uname: string;
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public SelectedPerm: any = {};
public SelectedPermItems: string = "";
public EditTaskModalVisible: boolean = false;
public DeleteConfirmModalVisible: boolean = false;
public Members: any = "";
public SelectedMembers: any = [];
public action: string = "add";
public permid: number = 0;
public permname: string = "";
public perms: { [index: string]: boolean } = {
api: false,
ftp: false,
password: false,
read: false,
romon: false,
sniff: false,
telnet: false,
tikapp: false,
winbox: false,
dude: false,
local: false,
policy: false,
reboot: false,
"rest-api": false,
sensitive: false,
ssh: false,
test: false,
web: false,
write: false,
};
toasterForm = {
autohide: true,
delay: 3000,
position: "fixed",
fade: true,
closeButton: true,
};
public sorting = {
enabled: true,
multiSorting: true,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
show_toast(title: string, body: string, color: string) {
const { ...props } = { ...this.toasterForm, color, title, body };
const componentRef = this.viewChildren.first.addToast(
AppToastComponent,
props,
{}
);
componentRef.instance["closeButton"] = props.closeButton;
}
ngOnInit(): void {
this.initGridTable();
}
submit(action: string) {
var _self = this;
if (action == "add") {
this.data_provider
.create_perm(_self.permname, _self.perms)
.then((res) => {
if (res["status"] == "failed") {
_self.show_toast(
"Error",
res.err,
"danger"
);
return;
} else {
_self.initGridTable();
this.EditTaskModalVisible = false;
}
});
} else {
this.data_provider
.edit_perm(_self.permid, _self.permname, _self.perms)
.then((res) => {
if (res["status"] == "failed") {
_self.show_toast(
"Error",
res.err,
"danger"
);
return;
} else {
_self.initGridTable();
this.EditTaskModalVisible = false;
}
});
}
}
editAddTask(item: any, action: string) {
if (action == "showadd") {
this.permname = item["name"];
this.perms = {
api: false,
ftp: false,
password: false,
read: false,
romon: false,
sniff: false,
telnet: false,
tikapp: false,
winbox: false,
dude: false,
local: false,
policy: false,
reboot: false,
"rest-api": false,
sensitive: false,
ssh: false,
test: false,
web: false,
write: false,
};
this.permid = 0;
this.action = "add";
this.EditTaskModalVisible = true;
return;
}
this.action = "edit";
this.permname = item["name"];
this.perms = item.perms;
this.permid = item["id"];
this.EditTaskModalVisible = true;
}
splitids(ids: string = "") {
return ids.split(",");
}
get_member_by_id(id: string) {
return this.Members.find((x: any) => x.id == id);
}
confirm_delete(item: any = "", del: boolean = false) {
if (!del) {
this.SelectedPerm = { ...item };
this.DeleteConfirmModalVisible = true;
} else {
var _self = this;
this.data_provider.delete_perm(_self.SelectedPerm["id"]).then((res) => {
if (res["status"] == "failed") {
_self.show_toast(
"Error",
res.err,
"danger"
);
return;
}
else{
_self.initGridTable();
_self.DeleteConfirmModalVisible = false;
}
});
}
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
var page = 1;
var pageSize = 10;
var searchstr = "";
this.data_provider.get_perms(page, pageSize, searchstr).then((res) => {
_self.source = res.map((x: any) => {
return x;
});
_self.loading = false;
});
}
}

View file

@ -0,0 +1,43 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
NavModule,
TabsModule,
ModalModule,
BadgeModule,
ToastModule,
} from "@coreui/angular";
import { IconModule } from "@coreui/icons-angular";
import { PermissionsRoutingModule } from "./permissions-routing.module";
import { PermissionsComponent } from "./permissions.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
@NgModule({
imports: [
PermissionsRoutingModule,
CardModule,
NavModule,
IconModule,
TabsModule,
CommonModule,
GridModule,
ToastModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
ModalModule,
FormsModule,
BadgeModule,
],
declarations: [PermissionsComponent],
})
export class PermissionsModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SettingsComponent } from './settings.component';
const routes: Routes = [
{
path: '',
component: SettingsComponent,
data: {
title: $localize`Settings`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SettingsRoutingModule {
}

View file

@ -0,0 +1,227 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>Firmware Manager</c-card-header>
<c-card-body>
<c-input-group class="mb-3">
<h5>Firmware in repository:</h5>
<gui-grid [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [autoResizeWidth]=true [paging]="paging">
<gui-grid-column header="Version" field="version">
<ng-template let-value="item.version" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="arch" field="architecture">
<ng-template let-value="item.architecture" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="sha256" field="sha256">
<ng-template let-value="item.sha256" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
</c-input-group>
<hr />
<table>
<td>
<span>Add new Permission</span>
</td>
<td *ngIf="loading">
<button cButton class="m-1" disabled>
<c-spinner aria-hidden="true" size="sm"></c-spinner>
Fetching Information from mikrotik website...
</button>
</td>
<td *ngIf="!loading">
<mat-form-field>
<mat-select cFormControl [(ngModel)]="firmtodownload" placeholder="Select Version For Download Group"
#singleSelect>
<mat-option>
<ngx-mat-select-search placeholderLabel="Search"
[hideClearSearchButton]="true"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let firm of firms" [value]="firm">
{{firm}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
<td>
<button *ngIf="!loading" cButton color="primary" (click)="ConfirmModalVisible=true">Download to
repository</button>
<!-- <button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="loading=!loading">++</button> -->
</td>
</table>
<hr />
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
V6 Firmware update Behavior
</label>
<select cSelect [(ngModel)]="updateBehavior" id="inputGroupSelect01">
<option>Choose...</option>
<option value="keep">Keep v6 and don't update to v7</option>
<option value="update">install latest</option>
</select>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Choose how Mikrowizard should update old v6 firmwares</c-form-feedback>
</c-input-group>
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Firmware version to install
</label>
<select cSelect [(ngModel)]="firmwaretoinstall" id="inputGroupSelect01">
<option>Choose...</option>
<option *ngFor="let f of available_firmwares" [value]="f">{{f}}</option>
</select>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* The version of firmware to install routers</c-form-feedback>
</c-input-group>
<c-input-group *ngIf="updateBehavior=='keep'" class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Firmware version v6 to install
</label>
<select cSelect [(ngModel)]="firmwaretoinstallv6" id="inputGroupSelect01">
<option>Choose...</option>
<option *ngFor="let f of available_firmwaresv6" [value]="f">{{f}}</option>
</select>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* The version of firmware to install on V6 routers</c-form-feedback>
</c-input-group>
<button cButton color="primary" (click)="saveFirmwareSetting()">Save</button>
</c-card-body>
</c-card>
<c-card class="mb-4">
<c-card-header>System Settings</c-card-header>
<c-card-body *ngIf="!SysConfigloading">
<c-input-group class="mt-3">
<span cInputGroupText>Rad Secret</span>
<input cFormControl id="floatingInput" placeholder="rad_secret"
[(ngModel)]="sysconfigs['rad_secret']['value']" />
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Radius Secret of Mikrowizard Radius Server</c-form-feedback>
</c-input-group>
<c-input-group class="mt-3">
<span cInputGroupText>System URL</span>
<input cFormControl id="floatingInput" placeholder="System URL"
[(ngModel)]="sysconfigs['system_url']['value']" />
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Default system access URl</c-form-feedback>
</c-input-group>
<c-input-group class="mt-3">
<span cInputGroupText>Default IP</span>
<input cFormControl id="floatingInput" placeholder="System URL"
[(ngModel)]="sysconfigs['default_ip']['value']" />
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Default Mikrowizard Access IP</c-form-feedback>
</c-input-group>
<c-input-group class="mt-3">
<span cInputGroupText>System Time Zone</span>
<mat-form-field class="form-control" subscriptSizing="dynamic">
<mat-label>Select event type</mat-label>
<mat-select cFormControl [(ngModel)]="sysconfigs['timezone']['value']"
placeholder="Select Version For Download Group" #singleSelect>
<mat-option>
<ngx-mat-select-search placeholderLabel="Search" [hideClearSearchButton]="true"></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let tz of timezones" [value]="tz.utc[0]">
{{tz.text}}
</mat-option>
</mat-select>
</mat-form-field>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Default TimeZone for the system</c-form-feedback>
</c-input-group>
<c-input-group class="mt-3">
<span cInputGroupText>Default User</span>
<input aria-label="Username" type="password" [(ngModel)]="sysconfigs['default_user']['value']" cFormControl />
<span cInputGroupText>Default password</span>
<input aria-label="Password" type="password" [(ngModel)]="sysconfigs['default_password']['value']"
cFormControl />
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Default username and Password for searching new devices</c-form-feedback>
</c-input-group>
<c-input-group class="mt-3 mb-3">
<span cInputGroupText>License Username</span>
<input aria-label="Username" type="text" [(ngModel)]="sysconfigs['username']['value']" cFormControl />
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* The username that you registred in Mikrowizard.com,Required for License Activation</c-form-feedback>
</c-input-group>
<c-form-check [switch]="true" sizing="xl">
<input cFormCheckInput [(ngModel)]="sysconfigs['force_perms']['value']" type="checkbox" />
<label cFormCheckLabel>Force Perms</label>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Force User Groups under user>groups configuration of each router to match Mikrowizard Permissions and
monitor for any change to prevent/fix the configuration.</c-form-feedback>
</c-form-check>
<c-form-check [switch]="true" sizing="xl">
<input cFormCheckInput [(ngModel)]="sysconfigs['force_radius']['value']" type="checkbox" />
<label cFormCheckLabel>Force Radius</label>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Force Radius config under radius>client and user>aaa setting of each router that added to Mikrowizard and
monitor for any change to prevent/fix the configuration.</c-form-feedback>
</c-form-check>
<c-form-check [switch]="true" sizing="xl">
<input cFormCheckInput [(ngModel)]="sysconfigs['force_syslog']['value']" type="checkbox" />
<label cFormCheckLabel>Force Syslog</label>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Force Syslog config under system>logs setting of each router that added to Mikrowizard and monitor syslog
setting for any change to prevent/fix the configuration.</c-form-feedback>
</c-form-check>
<c-form-check [switch]="true" sizing="xl">
<input cFormCheckInput [(ngModel)]="sysconfigs['safe_install']['value']" type="checkbox" />
<label cFormCheckLabel>Safe Update</label>
<c-form-feedback style="display: block;color: #979797;margin-top: 0;" [valid]="true">
* Download and install reqired firmware before installing the target firmware . for example it will install
latest 7.12 then upgrade to newer version >7.13</c-form-feedback>
</c-form-check>
<button cButton color="primary" (click)="saveSysSetting()">Save</button>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #ConfirmModal backdrop="static" [(visible)]="ConfirmModalVisible" id="runConfirmModal">
<c-modal-header>
<h6 cModalTitle>Downloading RouterOS ver {{firmtodownload}} </h6>
<button [cModalToggle]="ConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to download RouterOS version {{firmtodownload}} to the Repository?
<br />
</c-modal-body>
<c-modal-footer>
<button *ngIf="loading" cButton cButton color="danger" class="m-1" disabled>
<c-spinner aria-hidden="true" size="sm"></c-spinner>
Downloading...
</button>
<button *ngIf="!loading" (click)="start_download()" cButton color="danger">
Yes,Download!
</button>
<button [cModalToggle]="ConfirmModal.id" cButton color="info">
No!,Close
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,10 @@
:host {
.legend {
small {
font-size: x-small;
}
}
}
.mdc-line-ripple.mdc-line-ripple--deactivating.ng-star-inserted {
display: none!important;
}

View file

@ -0,0 +1,259 @@
import {
Component,
OnInit,
QueryList,
ViewChildren,
ViewEncapsulation,
} from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSelectedRow,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { ToasterComponent } from "@coreui/angular";
import { AppToastComponent } from "../toast-simple/toast.component";
import { TimeZones } from "./timezones-data";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "settings.component.html",
styleUrls: ["settings.component.scss"],
encapsulation: ViewEncapsulation.None,
})
export class SettingsComponent implements OnInit {
public uid: number;
public uname: string;
public filterText: string;
public filters: any = {};
public firms: any = {};
public firmtodownload: any = {};
constructor(
private data_provider: dataProvider,
private router: Router,
private TimeZones: TimeZones,
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public SysConfigloading: boolean = true;
public ConfirmModalVisible: boolean = false;
public rows: any = [];
public Selectedrows: any;
public updateBehavior: string = "keep";
public firmwaretoinstall: string = "none";
public firmwaretoinstallv6: string = "none";
public available_firmwares: any = [];
public available_firmwaresv6: any = [];
public sysconfigs: any = [];
toasterForm = {
autohide: true,
delay: 3000,
position: "fixed",
fade: true,
closeButton: true,
};
public sorting = {
enabled: true,
multiSorting: true,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 5,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
public timezones = this.TimeZones.timezones;
ngOnInit(): void {
this.initAvailbleFirms();
this.initFirmsTable();
this.initsettings();
}
start_download() {
var _self = this;
this.loading = true;
this.data_provider
.download_firmware_to_repository(this.firmtodownload)
.then((res) => {
if (res.status == true) {
// show toast that we are already downloading
_self.show_toast(
"Firmware Download",
"Firmware download in progress",
"warning"
);
} else {
// show toast that download started
_self.show_toast(
"Firmware Download",
"Firmware download started",
"success"
);
}
_self.ConfirmModalVisible = !_self.ConfirmModalVisible;
_self.loading = false;
});
}
onSelectedRows(rows: Array<GuiSelectedRow>): void {
this.rows = rows;
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
}
show_toast(title: string, body: string, color: string) {
const { ...props } = { ...this.toasterForm, color, title, body };
const componentRef = this.viewChildren.first.addToast(
AppToastComponent,
props,
{}
);
componentRef.instance["closeButton"] = props.closeButton;
}
saveFirmwareSetting() {
var _self = this;
this.data_provider
.save_firmware_setting(
this.updateBehavior,
this.firmwaretoinstall,
this.firmwaretoinstallv6
)
.then((res) => {
_self.initFirmsTable();
});
}
saveSysSetting() {
var _self = this;
this.data_provider.save_sys_setting(this.sysconfigs).then((res) => {
_self.initsettings();
});
}
initFirmsTable(): void {
var _self = this;
this.data_provider.get_firms(0, 10000, false).then((res) => {
let index = 1;
_self.source = res.firms;
_self.available_firmwares = [
...new Set(
res["firms"].map((x: any) => {
return x.version;
})
),
];
_self.available_firmwaresv6 = [
...new Set(
res["firms"].map((x: any) => {
return x.version;
})
),
].filter((x: any) => x.match(/^6\./g));
_self.firmwaretoinstall = res.firmwaretoinstall;
_self.firmwaretoinstallv6 = res.firmwaretoinstallv6;
});
}
initsettings(): void {
var _self = this;
this.data_provider.get_settings().then((res) => {
_self.sysconfigs = res.sysconfigs;
_self.sysconfigs["default_user"]["value"] = "";
_self.sysconfigs["default_password"]["value"] = "";
_self.timezones = _self.TimeZones.timezones;
_self.sysconfigs["force_syslog"]["value"] = /true/i.test(
_self.sysconfigs["force_syslog"]["value"]
);
_self.sysconfigs["force_radius"]["value"] = /true/i.test(
_self.sysconfigs["force_radius"]["value"]
);
_self.sysconfigs["force_perms"]["value"] = /true/i.test(
_self.sysconfigs["force_perms"]["value"]
);
_self.sysconfigs["safe_install"]["value"] = /true/i.test(
_self.sysconfigs["safe_install"]["value"]
);
_self.SysConfigloading = false;
});
}
initAvailbleFirms(): void {
var _self = this;
this.data_provider.get_downloadable_firms().then((res) => {
let index = 1;
_self.firms = res.versions;
_self.loading = false;
});
}
}

View file

@ -0,0 +1,41 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
SpinnerModule,
ToastModule,
ModalModule,
} from "@coreui/angular";
import { SettingsRoutingModule } from "./settings-routing.module";
import { SettingsComponent } from "./settings.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { FormsModule } from "@angular/forms";
import { MatSelectModule } from "@angular/material/select";
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
@NgModule({
imports: [
SettingsRoutingModule,
CardModule,
CommonModule,
GridModule,
FormsModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
MatSelectModule,
NgxMatSelectSearchModule,
SpinnerModule,
ToastModule,
ModalModule,
],
declarations: [SettingsComponent],
})
export class SettingsModule {}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SnippetsComponent } from './snippets.component';
const routes: Routes = [
{
path: '',
component: SnippetsComponent,
data: {
title: $localize`Snippets`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SnippetsRoutingModule {
}

View file

@ -0,0 +1,130 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="3">
Devices
</c-col>
<c-col xs [lg]="9">
<h6 style="text-align: right;">
<button cButton color="dark" class="mx-1" size="sm" (click)="Edit_Snippet('','showadd')"
style="color: #fff;"><i class="fa-solid fa-plus"></i> </button>
</h6>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<gui-grid [source]="source" [searching]="searching" [paging]="paging" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel"
[rowSelection]="rowSelection" (selectedRows)="onSelectedRows($event)" [autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
<img *ngIf="item.status=='updating'" width="20px" src="assets/img/loading.svg" />
<i *ngIf="item.status=='updated'" style="color: green;margin: 5px;" class="fa-solid fa-check"></i>
<i *ngIf="item.status=='failed'" style="color: red;margin: 5px;" class="fa-solid fa-x"></i>
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Description" field="description">
<ng-template let-value="item.description" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Created" field="created">
<ng-template let-value="item.created" let-item="item" let-index="index">
<div>{{value}}</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="warning" size="sm" (click)="Edit_Snippet(item,'edit')" class="mx-1"><i
class="fa-regular fa-pen-to-square mx-1"></i>Edit</button>
<button cButton color="danger" size="sm" (click)="confirm_delete(item,false)" class="mx-1"><i
class="fa-regular fa-trash-can mx-1"></i>Delete</button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal #EditModal backdrop="static" [(visible)]="EditModalVisible" id="runEditModal">
<c-modal-header>
<h6 *ngIf="ModalAction=='add'" cModalTitle>Add New Snippet</h6>
<h6 *ngIf="ModalAction=='edit'" cModalTitle>Editing snippet {{current_snippet.name}}</h6>
<button [cModalToggle]="EditModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-input-group class="mb-3">
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="Snippet Name" [(ngModel)]="current_snippet['name']" />
<label cLabel for="floatingInput">Name</label>
</div>
</c-input-group>
<c-input-group class="mb-3">
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="Snippet Description" [(ngModel)]="current_snippet['description']" />
<label cLabel for="floatingInput">Description</label>
</div>
</c-input-group>
<c-input-group class="mb-3">
<div [cFormFloating]="true" class="mb-3">
<textarea [style.height.px]="50 + (23 * lineNum)"
cFormControl (ngModelChange)="calcline($event)" id="floatingInput" placeholder="Snippet code" [(ngModel)]="current_snippet['content']" ></textarea>
<label cLabel for="floatingInput">Code</label>
</div>
</c-input-group>
<br />
</c-modal-body>
<c-modal-footer>
<button cButton color="danger" (click)="save_snippet()">save</button>
<button cButton [cModalToggle]="EditModal.id" color="info">Close</button>
</c-modal-footer>
</c-modal>
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible"
id="DeleteConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedSnippet['name'] }}</h5>
<button [cModalToggle]="DeleteConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to delete following Snippet ?
<br/>
<br/>
<table style="width: 100%;">
<tr>
<td><b>Snippet name : </b>{{ SelectedSnippet['name'] }}
</tr>
<tr>
</tr>
<tr>
<td>
<p ><code style="padding: 0!important;"><b>Warning:</b> ALL <b>Tasks</b> related to this snippet Will be <b>modifed or deleted</b> and stop working!</code></p>
</td>
</tr>
</table>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete('',true)" cButton color="danger">
Yes,Delete!
</button>
<button [cModalToggle]="DeleteConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,214 @@
import { Component, OnInit, OnDestroy, Inject, Renderer2, ViewChild, ElementRef, TemplateRef } from '@angular/core';
import { UntypedFormControl, UntypedFormGroup } from '@angular/forms';
import { dataProvider } from '../../providers/mikrowizard/data';
import { Router } from "@angular/router";
import { loginChecker } from '../../providers/login_checker';
import { HttpClient, HttpClientModule, HttpParams } from '@angular/common/http';
import { DOCUMENT } from '@angular/common';
import { GuiCellView,GuiSearching, GuiSelectedRow, GuiInfoPanel, GuiColumn, GuiColumnMenu, GuiDataType, GuiPaging, GuiPagingDisplay, GuiRowColoring, GuiRowSelectionMode, GuiRowSelection, GuiRowSelectionType } from '@generic-ui/ngx-grid';
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: 'snippets.component.html',
})
export class SnippetsComponent implements OnInit, OnDestroy {
public uid: number;
public uname: string;
constructor(
private data_provider: dataProvider,
private router: Router,
private login_checker: loginChecker,
private renderer: Renderer2,
private httpClient: HttpClient,
@Inject(DOCUMENT) _document?: any,
) {
var _self = this;
if (!this.login_checker.isLoggedIn()) {
// setTimeout(function() {
// _self.router.navigate(['login']);
// }, 100);
}
this.data_provider.getSessionInfo().then(res => {
// console.dir("res",res)
_self.uid = res.uid;
_self.uname = res.name;
// console.dir("role",res.role);
const userId = _self.uid;
if (res.role != "admin") {
// console.dir(res.role);
setTimeout(function () {
_self.router.navigate(['/user/dashboard']);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChild('nameSummaryCell')
nameSummaryCell: TemplateRef<any>;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any=[];
public Selectedrows: any;
public EditModalVisible:boolean=false;
public ModalAction:string="checkfirm";
public lineNum:number=0;
public DeleteConfirmModalVisible:boolean = false;
public SelectedSnippet:any={'name':'',};
public current_snippet:any={
"content": "",
"created": "",
"description": "",
"id": 0,
"name": ""
};
public default_snippet:any={
"content": "",
"created": "",
"description": "",
"id": 0,
"name": ""
};
public sorting = {
enabled: true,
multiSorting: true
};
public ip_scanner:any;
searching: GuiSearching = {
enabled: true,
placeholder: 'Search Devices'
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
this.initGridTable();
}
confirm_delete(item: any="",del:boolean=false) {
if (!del){
this.SelectedSnippet={...item};
this.DeleteConfirmModalVisible = true;
console.dir(this.SelectedSnippet);
}
else{
var _self=this;
this.data_provider.delete_snippet(_self.SelectedSnippet['id']).then(res => {
_self.initGridTable();
_self.DeleteConfirmModalVisible = false;
});
}
}
Edit_Snippet(item: any,action:string="showadd") {
if(action=="showadd"){
this.current_snippet={...this.default_snippet};
this.EditModalVisible=true;
this.ModalAction="add";
}
else{
this.current_snippet=item;
this.EditModalVisible=true;
this.lineNum = this.current_snippet['content'].match(/\n/g) .length ;
this.ModalAction="edit";
}
}
calcline($ev:any){
if($ev)
this.lineNum = $ev.match(/\n/g) .length ;
else
this.lineNum = 0;
}
save_snippet(){
this.data_provider.save_snippet(this.current_snippet).then(res =>{
this.EditModalVisible=false;
this.initGridTable();
})
}
onSelectedRows(rows: Array<GuiSelectedRow>): void {
this.rows = rows;
this.Selectedrows = rows.map((m: GuiSelectedRow) => m.source.id);
}
remove(item: any) {
console.dir(item);
}
logger(item: any) {
console.dir(item)
}
initGridTable(): void {
var _self=this;
_self.data_provider.get_snippets("","","",0,1000).then(res => {
_self.source =res.map( (x:any) => {
x.created = [x.created.split("T")[0],x.created.split("T")[1].split(".")[0]].join(" ")
return x;
});
_self.loading = false;
});
}
ngOnDestroy(): void {
}
}

View file

@ -0,0 +1,34 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
ToastModule,
ModalModule,
} from "@coreui/angular";
import { SnippetsRoutingModule } from "./snippets-routing.module";
import { SnippetsComponent } from "./snippets.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
@NgModule({
imports: [
SnippetsRoutingModule,
CardModule,
CommonModule,
GridModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
ModalModule,
ToastModule,
FormsModule,
],
declarations: [SnippetsComponent],
})
export class SnippetsModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { SyslogComponent } from './syslog.component';
const routes: Routes = [
{
path: '',
component: SyslogComponent,
data: {
title: $localize`Mikrowizard System Logs`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class SyslogRoutingModule {
}

View file

@ -0,0 +1,104 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="11">
Devices
</c-col>
<c-col xs [lg]="1">
<button (click)="toggleCollapse()" cButton class="me-1" color="primary"><i
class="fa-solid fa-filter mr-1"></i>Filter</button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<c-row>
<div [visible]="filters_visible" cCollapse>
<c-col xs [lg]="12" class="example-form">
<mat-form-field>
<mat-label>Start date</mat-label>
<input matInput [matDatepicker]="picker1" (dateChange)="reinitgrid('start',$event)"
[(ngModel)]="filters['start_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker1"></mat-datepicker-toggle>
<mat-datepicker #picker1></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>End date</mat-label>
<input matInput [matDatepicker]="picker2" (dateChange)="reinitgrid('end',$event)"
[(ngModel)]="filters['end_time']" />
<mat-datepicker-toggle matIconSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2></mat-datepicker>
</mat-form-field>
<mat-form-field>
<mat-label>Select section</mat-label>
<mat-select placeholder="Event Section" (ngModelChange)="reinitgrid('section',$event)"
[(ngModel)]="filters['section']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let sec of event_section " [value]="sec">
{{sec}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>Select action</mat-label>
<mat-select placeholder="Event action" (ngModelChange)="reinitgrid('action',$event)"
[(ngModel)]="filters['action']" #multiSelect>
<mat-option value="All">All</mat-option>
<mat-option *ngFor="let ac of event_action" [value]="ac">
{{ac}}
</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field>
<mat-label>IP</mat-label>
<input (ngModelChange)="reinitgrid('ip',$event)" [(ngModel)]="filters['ip']" matInput>
</mat-form-field>
</c-col>
</div>
</c-row>
<gui-grid wid [rowDetail]="rowDetail" [horizontalGrid]="true" [rowHeight]="52" [source]="source"
[columnMenu]="columnMenu" [paging]="paging" [sorting]="sorting" [infoPanel]="infoPanel"
[autoResizeWidth]="true">
<gui-grid-column header="#No" type="NUMBER" field="index" width="1" align="CENTER">
<ng-template let-value="item.index" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="username" field="username">
<ng-template let-value="item.username" let-item="item" let-index="index">
<div class="gui-dev-info">
<span class="gui-dev-info-name">{{ value }}</span>
<span class="gui-dev-info-ip">{{ item.first_name }} {{ item.last_name }}</span>
</div>
</ng-template>
</gui-grid-column>
<gui-grid-column header="Section" field="section">
<ng-template let-value="item.section" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="action" field="action">
<ng-template let-value="item.action" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="ip" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Time" field="created">
<ng-template let-value="item.created" let-item="item" let-index="index">
{{ value }}
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>

View file

@ -0,0 +1,128 @@
@use '@angular/material' as mat;
:host {
.legend {
small {
font-size: x-small;
}
}
}
// .gui-drawer-content{
// background-color: #efefef!important;
// }
.log-detail{
padding:30px 10px;
box-sizing:border-box;
}
.log-detail h1{
font-size:2em;
font-weight:bold;
margin:0;
padding:0;
}
.log-detail small{
position:relative;
top:-7px;
padding:0;
font-weight:bold;
font-size:1.1em;
}
.log-detail table {
width: 100%;
border-collapse: collapse!important;
margin: 5px 0 0 0;
padding: 0;
background-color: #ffffff29 !important;
color: #000;
}
.log-detail th {
text-align: left;
}
.log-detail th,
.log-detail td {
border: 1px solid #ffffff4a!important;
padding: 0.3rem!important;
}
.gui-close-icon-wrapper .gui-close-icon:after,.gui-close-icon-wrapper .gui-close-icon:before {
background-color: #ffffff !important;
}
.log-detail code{
padding:5px!important;
display:block;
background:#1d1f21;
color:#c5c8c6;
border-bottom-left-radius:3px;
border-bottom-right-radius:3px;
width:100%;
min-height: unset!important;
height: 100px!important;
overflow-y: scroll!important;
}
.log-detail .code-title{
background-color:#393e42!important;;
width:100%;
padding:2px 15px;
display:inline-block;
margin-top:10px;
color:#d2d2d2;
border-top-left-radius:3px;
border-top-right-radius:3px;
font-weight:bold;
}
.gui-row-detail{
height:100%;
}
.gui-dev-info {
display: inline-flex;
flex-direction: column;
align-items: stretch;
align-content: center;
justify-content: center;
white-space: normal;
line-height: 17px;
}
.gui-dev-info-name {
font-weight: bold;
}
.gui-dev-info-ip {
color: #525252;
font-style: italic;
font-size: 13px;
overflow: hidden;
}
.gui-row-detail > div{
height:100%;
}
.gui-row-detail .log-detail{
height:100%;
}
.gui-structure{
min-height: 550px;
}
.example-form {
@include mat.button-density(-5);
@include mat.form-field-density(-5);
@include mat.button-toggle-density(-5);
@include mat.datepicker-density(-5);
@include mat.all-component-densities(-5);
@include mat.icon-button-density(-5);
@include mat.icon-density(-5);
.mat-mdc-text-field-wrapper:not(.mdc-text-field--outlined) .mat-mdc-floating-label { display: inline; }
mat-form-field *{
font-size:13px!important;
}
.mat-mdc-form-field-infix{
width:150px;
}
}

View file

@ -0,0 +1,204 @@
import { Component, OnInit, ViewEncapsulation } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router, ActivatedRoute } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiRowDetail,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { formatInTimeZone } from "date-fns-tz";
@Component({
templateUrl: "syslog.component.html",
styleUrls: ["syslog.component.scss"],
encapsulation: ViewEncapsulation.None,
})
export class SyslogComponent implements OnInit {
public uid: number;
public uname: string;
public tz: string= "UTC";
public filterText: string;
public filters: any = {
start_time: false,
end_time: false,
section: "All",
action: "All",
ip: "",
};
public event_section: any = [];
public event_action: any = [];
public filters_visible: boolean = false;
constructor(
private data_provider: dataProvider,
private router: Router,
private route: ActivatedRoute,
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.tz = res.tz;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public Selectedrows: any;
public userid: number = 0;
public sorting = {
enabled: true,
multiSorting: true,
};
public campaignOnestart: any;
public campaignOneend: any;
rowDetail: GuiRowDetail = {
enabled: true,
template: (item) => {
return `
<div class='log-detail' style="color:#fff;background-color:#3399ff">
<h2>System Log :</h2>
<table>
<tr>
<td>Section</td>
<td>${item.section}</td>
</tr>
<tr>
<td>Action</td>
<td>${item.action}</td>
</tr>
<tr>
<td>Time</td>
<td>${item.created}</td>
</tr>
</table>
<h2 style="margin-top: 5px;">User Detail :
</h2>
<table>
<tr>
<td>User</td>
<td>${item.username}</td>
</tr>
<tr>
<td>FirstName</td>
<td>${item.first_name}</td>
</tr>
<tr>
<td>LastName</td>
<td>${item.last_name}</td>
</tr>
<tr>
<td>IP</td>
<td>${item.ip}</td>
</tr>
<tr>
<td>Agent</td>
<td><div style="height: 40px;overflow-y: scroll;">${item.agent}</div></td>
</tr>
</table>
<div class="code-title">data</div>
<code>
${item.data}
</code>
</div>`;
},
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
var _self = this;
this.userid = Number(this.route.snapshot.paramMap.get("userid"));
if (this.userid > 0) {
this.filters["userid"] = this.userid;
}
this.initGridTable();
}
toggleCollapse(): void {
this.filters_visible = !this.filters_visible;
}
logger(item: any) {
console.dir(item);
}
reinitgrid(field: string, $event: any) {
if (field == "start") this.filters["start_time"] = $event.target.value;
else if (field == "end") this.filters["end_time"] = $event.target.value;
else if (field == "section") this.filters["section"] = $event;
else if (field == "action") this.filters["action"] = $event;
else if (field == "ip") this.filters["ip"] = $event;
this.initGridTable();
}
initGridTable(): void {
var _self = this;
_self.event_section = [];
_self.event_action = [];
this.data_provider.get_syslog(this.filters).then((res) => {
let index = 1;
this.source = res.map((d: any) => {
d.index = index;
if (!_self.event_section.includes(d.section))
_self.event_section.push(d.section);
if (!_self.event_action.includes(d.action))
_self.event_action.push(d.action);
d.created = formatInTimeZone(
d.created.split(".")[0] + ".000Z",
_self.tz,
"yyyy-MM-dd HH:mm:ss XXX"
);
index += 1;
return d;
});
this.loading = false;
});
}
}

View file

@ -0,0 +1,41 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import {
ButtonModule,
CardModule,
GridModule,
CollapseModule,
DropdownModule,
} from "@coreui/angular";
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
import { SyslogRoutingModule } from "./syslog-routing.module";
import { SyslogComponent } from "./syslog.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { MatDatepickerModule } from "@angular/material/datepicker";
import { MatInputModule } from "@angular/material/input";
import { MatFormFieldModule } from "@angular/material/form-field";
import { FormsModule } from "@angular/forms";
import { MatSelectModule } from "@angular/material/select";
@NgModule({
imports: [
SyslogRoutingModule,
CardModule,
CommonModule,
GridModule,
FormsModule,
ButtonModule,
GuiGridModule,
CollapseModule,
DropdownModule,
MatInputModule,
MatFormFieldModule,
MatSelectModule,
NgxMatSelectSearchModule,
MatDatepickerModule,
],
declarations: [SyslogComponent],
})
export class SyslogModule {}

View file

@ -0,0 +1,11 @@
<svg
class="rounded me-2"
width="20"
height="20"
xmlns="http://www.w3.org/2000/svg"
preserveAspectRatio="xMidYMid slice"
focusable="false"
role="img"
>
<rect width="100%" height="100%" fill="#007aff"></rect>
</svg>

After

Width:  |  Height:  |  Size: 231 B

View file

@ -0,0 +1,14 @@
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'toast-sample-icon',
templateUrl: './toast-sample-icon.component.svg',
})
export class ToastSampleIconComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}

View file

@ -0,0 +1,12 @@
<ng-container>
<c-toast-header [closeButton]="closeButton">
<i *ngIf="color=='danger'" style="color:#e55353" class="fa-solid fa-xmark mx-1"></i>
<i *ngIf="color=='info'" style="color:#3399ff" class="fa-solid fa-exclamation mx-1"></i>
<i *ngIf="color=='warning'" style="color:#f9b115" class="fa-solid fa-triangle-exclamation mx-1"></i>
<strong style="line-height:1;">{{ title }}</strong>
</c-toast-header>
<c-toast-body #toastBody [cToastClose]="toastBody.toast">
<p class="mb-1" style="color:#fff;">{{ body }} </p>
<ng-content />
</c-toast-body>
</ng-container>

View file

@ -0,0 +1,4 @@
:host {
display: block;
overflow: hidden;
}

View file

@ -0,0 +1,34 @@
import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { ButtonModule, ProgressModule, ToastModule } from '@coreui/angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../../icons/icon-subset';
import { AppToastComponent } from './toast.component';
describe('ToastComponent', () => {
let component: AppToastComponent;
let fixture: ComponentFixture<AppToastComponent>;
let iconSetService: IconSetService;
beforeEach(waitForAsync(() => {
TestBed.configureTestingModule({
imports: [NoopAnimationsModule, ToastModule, ProgressModule, ButtonModule, AppToastComponent],
providers: [IconSetService]
})
.compileComponents();
}));
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(AppToastComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,28 @@
import { ChangeDetectorRef, Component, ElementRef, forwardRef, Input, Renderer2 } from '@angular/core';
import { ToastComponent, ToasterService, ToastHeaderComponent, ToastBodyComponent, ToastCloseDirective, ProgressComponent } from '@coreui/angular';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-toast-simple',
templateUrl: './toast.component.html',
styleUrls: ['./toast.component.scss'],
providers: [{ provide: ToastComponent, useExisting: forwardRef(() => AppToastComponent) }],
standalone: true,
imports: [ToastHeaderComponent, ToastBodyComponent, ToastCloseDirective, ProgressComponent,CommonModule]
})
export class AppToastComponent extends ToastComponent {
@Input() closeButton = true;
@Input() title = '';
@Input() body = '';
constructor(
public override hostElement: ElementRef,
public override renderer: Renderer2,
public override toasterService: ToasterService,
public override changeDetectorRef: ChangeDetectorRef
) {
super(hostElement, renderer, toasterService, changeDetectorRef);
}
}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserManagerComponent } from './user_manager.component';
const routes: Routes = [
{
path: '',
component: UserManagerComponent,
data: {
title: $localize`User Managment`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserManagerRoutingModule {
}

View file

@ -0,0 +1,261 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="10">
Users
</c-col>
<c-col xs [lg]="2" style="text-align: right;">
<button cButton color="primary" (click)="editAddUser({},'showadd')"><i
class="fa-solid fa-plus"></i></button>
</c-col>
</c-row>
</c-card-header>
<c-card-body >
<gui-grid [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu" [sorting]="sorting"
[autoResizeWidth]=true [paging]="paging">
<gui-grid-column header="User Name" field="username">
<ng-template let-value="item.username" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="First Name" field="first_name">
<ng-template let-value="item.first_name" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Last Name" field="last_name">
<ng-template let-value="item.last_name" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Role" field="role">
<ng-template let-value="item.role" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="warning" size="sm" (click)="editAddUser(item,'edit');" class="mx-1"><i
class="fa-regular fa-pen-to-square"></i></button>
<button cButton color="danger" size="sm" (click)="confirm_delete(item);"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal-header>
<c-modal #EditTaskModal backdrop="static" size="lg" [(visible)]="EditTaskModalVisible" id="EditTaskModal">
<c-modal-header>
<h5 *ngIf="SelectedUser['action']=='edit'" cModalTitle>Editing User {{SelectedUser['name']}}</h5>
<h5 *ngIf="SelectedUser['action']=='add'" cModalTitle>Adding new User</h5>
<button [cModalToggle]="EditTaskModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="User Name" [(ngModel)]="SelectedUser['username']" />
<label cLabel for="floatingInput">User Name</label>
</div>
<c-input-group class="mb-3">
<span cInputGroupText>First Name</span>
<input cFormControl id="floatingInput" placeholder="First Name" [(ngModel)]="SelectedUser['first_name']" />
<span cInputGroupText>Last Name</span>
<input cFormControl id="floatingInput" placeholder="Last Name" [(ngModel)]="SelectedUser['last_name']" />
</c-input-group>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="Email Address" [(ngModel)]="SelectedUser['email']" />
<label cLabel for="floatingInput">Email Address</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl id="floatingInput" placeholder="Password" [(ngModel)]="SelectedUser['password']" />
<label cLabel for="floatingInput">Password</label>
</div>
<!-- <c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Options
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="SelectedUser['role']" (change)="get_user_perms(SelectedUser['id'])">
<option>Choose...</option>
<option value="admin">admin</option>
<option value="user">Customer</option>
</select>
</c-input-group> -->
<c-input-group>
<h5>MikroWizard permisssions :</h5>
<c-container>
<c-row>
<c-col *ngFor='let perm of adminperms | keyvalue' [md]="6" class="mb-1">
<label cFormCheckLabel style="text-transform: capitalize">{{ perm.key}} :</label>
<c-form-check class="md-6" [switch]="true" style="float: right;">
<c-button-group>
<c-button-group aria-label="Basic example" role="group">
<button cButton color="info" variant="outline" size="sm" [active]="adminperms[perm.key]=='read'"
(click)="setRadioValue(perm.key,'read')">Read</button>
<button cButton color="danger" variant="outline" size="sm" [active]="adminperms[perm.key]=='write'"
(click)="setRadioValue(perm.key,'write')">Write</button>
<button cButton color="success" variant="outline" size="sm" [active]="adminperms[perm.key]=='full'"
(click)="setRadioValue(perm.key,'full')">Full</button>
<button cButton color="dark" variant="outline" size="sm" [active]="adminperms[perm.key]=='none'"
(click)="setRadioValue(perm.key,'none')">None</button>
</c-button-group>
</c-button-group>
</c-form-check>
</c-col>
</c-row>
</c-container>
</c-input-group>
<c-input-group *ngIf="userperms.length>0" class="mb-3">
<h5>Mikrotik permisssions :</h5>
<gui-grid [autoResizeWidth]="true" [source]="userperms" [columnMenu]="columnMenu" [sorting]="sorting"
[autoResizeWidth]=true [paging]="paging" >
<gui-grid-column header="Group Name" field="group_name">
<ng-template let-value="item.group_name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="perm Name" field="perm_name">
<ng-template let-value="item.perm_name" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="danger" size="sm" (click)="confirm_delete_perm(item);"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-input-group>
<hr />
<table >
<td style="width: 30%;">
<span>Add new Permission</span>
</td>
<td>
<mat-form-field>
<mat-select cFormControl [(ngModel)]="devgroup" placeholder="Device Group" #singleSelect>
<mat-option>
<ngx-mat-select-search></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let group of allDevGroups" [value]="group">
{{group.name}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
<td>
<mat-form-field>
<mat-select cFormControl placeholder="Permission" [(ngModel)]="permission" #singleSelect>
<mat-option>
<ngx-mat-select-search></ngx-mat-select-search>
</mat-option>
<mat-option *ngFor="let perm of allPerms" [value]="perm">
{{perm.name}}
</mat-option>
</mat-select>
</mat-form-field>
</td>
<td>
<button *ngIf="SelectedUser['action']=='edit'" cButton color="primary" (click)="add_user_perm()">+</button>
<button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="add_new_user_perm()">+</button>
<!-- <button *ngIf="SelectedUser['action']=='add'" cButton color="primary" (click)="loading=!loading">++</button> -->
</td>
</table>
</c-modal-body>
<c-modal-footer>
<button *ngIf="SelectedUser['action']=='add'" (click)="submit('add')" cButton color="primary">Add</button>
<button *ngIf="SelectedUser['action']=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible" id="DeleteConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedUser['name'] }}</h5>
<button [cModalToggle]="DeleteConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to delete following task ?
<br />
<br />
<table style="width: 100%;">
<tr>
<td><b>User name : </b></td>
<td>{{ SelectedUser['username'] }}</td>
</tr>
<tr>
<td><b>Name : </b></td>
<td>{{ SelectedUser['first_name'] }}</td>
</tr>
<tr>
<td><b>Last Name : </b></td>
<td>{{ SelectedUser['last_name'] }}</td>
</tr>
</table>
<hr>
<p class="text-danger">
All Related data will be deleted :<br />
* User Permision Related to this user<br />
* All Logs related to this user<br />
</p>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete('',true)" cButton color="danger">
Yes,Delete!
</button>
<button [cModalToggle]="DeleteConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #DeletePermConfirmModal backdrop="static" [(visible)]="DeletePermConfirmModalVisible" id="DeletePermConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedUser['name'] }}</h5>
<button [cModalToggle]="DeletePermConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to delete following task ?
<br />
<br />
<table style="width: 100%;">
<tr>
<td><b>Taks name : </b></td>
<td>{{ SelectedUser['name'] }}</td>
</tr>
<tr>
<td><b>Description : </b></td>
<td>{{ SelectedUser['description'] }}</td>
</tr>
<tr>
<td><b>Cron exec : </b></td>
<td>{{ SelectedUser['desc_cron'] }}</td>
</tr>
</table>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete('',true)" cButton color="danger">
Yes,Delete!
</button>
<button [cModalToggle]="DeletePermConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-toaster position="fixed" placement="top-end"></c-toaster>

View file

@ -0,0 +1,296 @@
import { Component, OnInit, QueryList, ViewChildren } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiGridComponent,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { NgxSuperSelectOptions } from "ngx-super-select";
import { AppToastComponent } from "../toast-simple/toast.component";
import { ToasterComponent } from "@coreui/angular";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "user_manager.component.html",
})
export class UserManagerComponent implements OnInit {
public uid: number;
public uname: string;
gridComponent: GuiGridComponent;
toasterForm = {
autohide: true,
delay: 10000,
position: "fixed",
fade: true,
closeButton: true,
};
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
@ViewChildren(ToasterComponent) viewChildren!: QueryList<ToasterComponent>;
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = false;
public rows: any = [];
public SelectedUser: any = {};
public SelectedUserItems: string = "";
public EditTaskModalVisible: boolean = false;
public DeleteConfirmModalVisible: boolean = false;
public Members: any = "";
public devgroup: any = {};
public permission: any = {};
public allDevGroups: any = [];
public allPerms: any = [];
public DeletePermConfirmModalVisible: boolean = false;
public userperms: any = {};
public adminperms: { [index: string]: string };
public defadminperms: { [index: string]: string } = {
device: "none",
device_group: "none",
task: "none",
backup: "none",
snippet: "none",
accounting: "none",
authentication: "none",
users: "none",
permissions: "none",
settings: "none",
system_backup: "none",
};
public sorting = {
enabled: true,
multiSorting: true,
};
options: Partial<NgxSuperSelectOptions> = {
actionsEnabled: false,
displayExpr: "name",
valueExpr: "id",
placeholder: "Members",
searchEnabled: true,
enableDarkMode: false,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
setRadioValue(key: string, value: string): void {
this.adminperms[key] = value;
}
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
ngOnInit(): void {
this.initGridTable();
}
show_toast(title: string, body: string, color: string) {
const { ...props } = { ...this.toasterForm, color, title, body };
const componentRef = this.viewChildren.first.addToast(
AppToastComponent,
props,
{}
);
componentRef.instance["closeButton"] = props.closeButton;
}
submit(action: string) {
var _self = this;
if (action == "add") {
if (_self.SelectedUser["role"] == "admin") {
_self.adminperms = { ..._self.defadminperms };
if (_self.userperms.length > 0) {
_self.SelectedUser["userperms"] = _self.userperms;
} else {
_self.SelectedUser["userperms"] = [];
}
}
_self.SelectedUser["adminperms"] = _self.adminperms;
this.data_provider.create_user(_self.SelectedUser).then((res) => {
if ("id" in res && !("status" in res)) {
_self.initGridTable();
this.EditTaskModalVisible = false;
} else {
//show error
_self.show_toast("Error", res.err, "danger");
}
});
} else {
_self.SelectedUser["adminperms"] = _self.adminperms;
this.data_provider.edit_user(_self.SelectedUser).then((res) => {
_self.initGridTable();
_self.EditTaskModalVisible = false;
});
}
//
}
editAddUser(item: any, action: string) {
var _self = this;
this.data_provider.get_perms(1, 1000, "").then((res) => {
_self.allPerms = res.map((x: any) => {
return { id: x["id"], name: x.name };
});
_self.data_provider.get_devgroup_list().then((res) => {
_self.allDevGroups = res.map((x: any) => {
return { id: x["id"], name: x.name };
});
});
});
if (action == "showadd") {
this.userperms = [];
this.SelectedUser = {
email: "",
first_name: "",
fullname: "",
last_name: "",
role: "admin",
password: "",
action: "add",
};
this.adminperms = { ...this.defadminperms };
this.EditTaskModalVisible = true;
return;
}
this.SelectedUser = { ...item };
if (this.SelectedUser["adminperms"].length > 0) {
this.adminperms = JSON.parse(this.SelectedUser["adminperms"]);
} else this.adminperms = { ...this.defadminperms };
_self.SelectedUser["action"] = "edit";
_self.get_user_perms(_self.SelectedUser["id"]);
_self.EditTaskModalVisible = true;
}
add_user_perm() {
var _self = this;
this.data_provider
.Add_user_perm(
this.SelectedUser["id"],
this.permission["id"],
this.devgroup["id"]
)
.then((res) => {
_self.get_user_perms(_self.SelectedUser["id"]);
_self.permission = 0;
_self.devgroup = 0;
});
}
add_new_user_perm() {
var _self = this;
const userperms = [..._self.userperms];
userperms.push({
group_id: this.devgroup["id"],
group_name: this.devgroup["name"],
perm_id: this.permission["id"],
perm_name: this.permission["name"],
});
this.userperms = userperms;
}
confirm_delete(item: any = "", del: boolean = false) {
if (!del) {
this.SelectedUser = { ...item };
this.DeleteConfirmModalVisible = true;
} else {
var _self = this;
this.data_provider.delete_user(_self.SelectedUser["id"]).then((res) => {
_self.initGridTable();
_self.DeleteConfirmModalVisible = false;
});
}
}
get_user_perms(uid: string) {
if (this.SelectedUser["action"] == "add") return;
var _self = this;
this.data_provider.user_perms(uid).then((res) => {
_self.userperms = res;
});
}
confirm_delete_perm(item: any) {
this.data_provider.Delete_user_perm(item.id).then((res) => {
this.get_user_perms(this.SelectedUser["id"]);
});
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
var page = 1;
var pageSize = 10;
var searchstr = "";
this.data_provider.get_users(page, pageSize, searchstr).then((res) => {
_self.source = res.map((x: any) => {
return x;
});
_self.SelectedUser = {};
_self.loading = false;
});
}
}

View file

@ -0,0 +1,39 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import {
ButtonGroupModule,
ButtonModule,
CardModule,
FormModule,
GridModule,
ModalModule,
ToastModule,
} from "@coreui/angular";
import { MatSelectModule } from "@angular/material/select";
import { NgxMatSelectSearchModule } from "ngx-mat-select-search";
import { UserManagerRoutingModule } from "./user_manager-routing.module";
import { UserManagerComponent } from "./user_manager.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
@NgModule({
imports: [
MatSelectModule,
NgxMatSelectSearchModule,
UserManagerRoutingModule,
CardModule,
CommonModule,
GridModule,
FormModule,
ButtonModule,
ButtonGroupModule,
GuiGridModule,
ModalModule,
FormsModule,
ToastModule,
],
declarations: [UserManagerComponent],
})
export class UserManagerModule {}

View file

@ -0,0 +1,21 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { UserTasksComponent } from './user_tasks.component';
const routes: Routes = [
{
path: '',
component: UserTasksComponent,
data: {
title: $localize`System Tasks`
}
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule]
})
export class UserTasksRoutingModule {
}

View file

@ -0,0 +1,268 @@
<c-row>
<c-col xs>
<c-card class="mb-4">
<c-card-header>
<c-row>
<c-col xs [lg]="10">
Tasks
</c-col>
<c-col xs [lg]="2" style="text-align: right;">
<button cButton color="primary" (click)="editAddTask({},'showadd')"><i class="fa-solid fa-plus"></i></button>
</c-col>
</c-row>
</c-card-header>
<c-card-body>
<gui-grid [autoResizeWidth]="true" [source]="source" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [autoResizeWidth]=true>
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
<i *ngIf="item.task_type=='snippet'" class="fa-solid fa-code"></i><i *ngIf="item.task_type=='backup'"
class="fa-solid fa-database"></i>&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column header="Description" field="description">
<ng-template let-value="item.description" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Members type" field="selection_type">
<ng-template let-value="item.selection_type" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Runtime" field="desc_cron">
<ng-template let-value="item.desc_cron" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="warning" size="sm" (click)="editAddTask(item,'edit');" ><i
class="fa-regular fa-pen-to-square"></i></button>
<button cButton color="info" size="sm" (click)="confirm_run(item);" class="mx-1"><i
class="fa-solid fa-bolt"></i></button>
<button cButton color="danger" size="sm" (click)="confirm_delete(item);"><i
class="fa-regular fa-trash-can"></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
</c-card-body>
</c-card>
</c-col>
</c-row>
<c-modal-header>
<c-modal #EditTaskModal backdrop="static" size="xl" [(visible)]="EditTaskModalVisible" id="EditTaskModal">
<c-modal-header>
<h5 *ngIf="SelectedTask['action']=='edit'" cModalTitle>Editing device {{SelectedTask['name']}}</h5>
<h5 *ngIf="SelectedTask['action']=='add'" cModalTitle>Adding new task</h5>
<button [cModalToggle]="EditTaskModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="SelectedTask['name']" [(ngModel)]="SelectedTask['name']" />
<label cLabel for="floatingInput">Name</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="SelectedTask['description']" [(ngModel)]="SelectedTask['description']" />
<label cLabel for="floatingInput">Description</label>
</div>
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Options
</label>
<select cSelect id="inputGroupSelect01" [(ngModel)]="SelectedTask['task_type']">
<option>Choose...</option>
<option value="backup">Backup</option>
<option value="snippet">Snippet</option>
</select>
</c-input-group>
<c-input-group class="mb-3">
<ngx-super-select *ngIf="SelectedTask['task_type']=='snippet'"
[dataSource]="Snippets"
[options]="options"
(selectionChanged)="onSelectValueChanged($event)"
[selectedItemValues]="[SelectedTask['snippetid']]"
(searchChanged)="onSnippetsValueChanged($event)"
class="styled"
></ngx-super-select>
</c-input-group>
<div [cFormFloating]="true" class="mb-3">
<input cFormControl id="floatingInput" placeholder="SelectedTask['name']" [(ngModel)]="SelectedTask['cron']" />
<label cLabel for="floatingInput">cron</label>
</div>
<c-input-group class="mb-3">
<label cInputGroupText for="inputGroupSelect01">
Member type
</label>
<select cSelect id="inputGroupSelect01" (change)="form_changed()" [(ngModel)]="SelectedTask['selection_type']">
<option value="devices">Devices</option>
<option value="groups">Groups</option>
</select>
</c-input-group>
<h5>Members :</h5>
<gui-grid [autoResizeWidth]="true" [source]="SelectedMembers" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [rowSelection]="rowSelection" [autoResizeWidth]=true [paging]="paging" >
<gui-grid-column header="Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column *ngIf="SelectedTask['selection_type']=='devices'" header="MAC" field="mac">
<ng-template let-value="item.mac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column header="Actions" width="120" field="action">
<ng-template let-value="item.id" let-item="item" let-index="index">
<button cButton color="danger" size="sm" (click)="remove_member(item)"><i
class="fa-regular fa-trash-can" ></i></button>
</ng-template>
</gui-grid-column>
</gui-grid>
<hr />
<button cButton color="primary" (click)="show_new_member_form()" >+ Add new Members</button>
<!--
<c-input-group class="mb-3">
<ngx-super-select
[dataSource]="Members"
[options]="options"
[selectedItemValues]="SelectedMembers"
(selectionChanged)="onMembersValueChanged($event)"
(searchChanged)="onMembersSearchChanged($event)"
class="styled hiden"
>
</ngx-super-select>
</c-input-group> -->
<!-- <ng-container *ngIf="SelectedMembers.length>0 && EditTaskModalVisible">
<c-badge class="mx-1" *ngFor="let id of splitids(SelectedTaskItems)" color="dark">{{get_member_by_id(id).name}}</c-badge>
</ng-container> -->
<!--
<c-input-group class="mb-3">
<cron-editor #cronEditorDemo1 [(ngModel)]="SelectedTask['cron']" [options]="cronOptions">Cron here...</cron-editor>
</c-input-group>
-->
</c-modal-body>
<c-modal-footer>
<button *ngIf="SelectedTask['action']=='add'" (click)="submit('add')" cButton color="primary">Add</button>
<button *ngIf="SelectedTask['action']=='edit'" (click)="submit('edit')" cButton color="primary">save</button>
<button [cModalToggle]="EditTaskModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #NewMemberModal backdrop="static" size="lg" [(visible)]="NewMemberModalVisible" id="NewMemberModal">
<c-modal-header>
<h5 cModalTitle>Editing Group </h5>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<c-input-group class="mb-3">
<h5>Group Members :</h5>
<gui-grid [autoResizeWidth]="true" *ngIf="NewMemberModalVisible" [searching]="searching" [source]="availbleMembers" [columnMenu]="columnMenu" [sorting]="sorting"
[infoPanel]="infoPanel" [rowSelection]="rowSelection" (selectedRows)="onSelectedRowsNewMembers($event)" [autoResizeWidth]=true [paging]="paging" >
<gui-grid-column header="Member Name" field="name">
<ng-template let-value="item.name" let-item="item" let-index="index">
&nbsp; {{value}} </ng-template>
</gui-grid-column>
<gui-grid-column *ngIf="SelectedTask['selection_type']=='devices'" header="IP Address" field="ip">
<ng-template let-value="item.ip" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
<gui-grid-column *ngIf="SelectedTask['selection_type']=='devices'" header="MAC Address" field="mac">
<ng-template let-value="item.mac" let-item="item" let-index="index">
{{value}}
</ng-template>
</gui-grid-column>
</gui-grid>
<br/>
</c-input-group>
<hr />
</c-modal-body>
<c-modal-footer>
<button *ngIf="NewMemberRows.length!= 0" (click)="add_new_members()" cButton color="primary">Add {{ NewMemberRows.length }}</button>
<button (click)="NewMemberModalVisible=!NewMemberModalVisible" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #DeleteConfirmModal backdrop="static" [(visible)]="DeleteConfirmModalVisible"
id="DeleteConfirmModal">
<c-modal-header>
<h5 cModalTitle>Confirm delete {{ SelectedTask['name'] }}</h5>
<button [cModalToggle]="DeleteConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to delete following task ?
<br/>
<br/>
<table style="width: 100%;">
<tr>
<td><b>Taks name : </b></td><td>{{ SelectedTask['name'] }}</td>
</tr>
<tr>
<td><b>Description : </b></td><td>{{ SelectedTask['description'] }}</td>
</tr>
<tr>
<td><b>Cron exec : </b></td><td>{{ SelectedTask['desc_cron'] }}</td>
</tr>
</table>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete('',true)" cButton color="danger">
Yes,Delete!
</button>
<button [cModalToggle]="DeleteConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>
<c-modal #runConfirmModal backdrop="static" [(visible)]="runConfirmModalVisible" id="runConfirmModal">
<c-modal-header>
<h6 cModalTitle>Confirm RUN {{ SelectedTask['name'] }}</h6>
<button [cModalToggle]="runConfirmModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
Are you sure that You want to run following task ?
<br/>
<br/>
<table style="width: 100%;">
<tr>
<td><b>Taks name : </b></td><td>{{ SelectedTask['name'] }}</td>
</tr>
<tr>
<td><b>Description : </b></td><td>{{ SelectedTask['description'] }}</td>
</tr>
<tr>
<td><b>Cron exec : </b></td><td>{{ SelectedTask['desc_cron'] }}</td>
</tr>
</table>
</c-modal-body>
<c-modal-footer>
<button (click)="confirm_delete" cButton color="danger">
Yes,Run!
</button>
<button [cModalToggle]="runConfirmModal.id" cButton color="info">
Close
</button>
</c-modal-footer>
</c-modal>

View file

@ -0,0 +1,306 @@
import { Component, OnInit, OnDestroy } from "@angular/core";
import { dataProvider } from "../../providers/mikrowizard/data";
import { Router } from "@angular/router";
import { loginChecker } from "../../providers/login_checker";
import {
GuiSelectedRow,
GuiSearching,
GuiInfoPanel,
GuiColumn,
GuiColumnMenu,
GuiPaging,
GuiPagingDisplay,
GuiRowSelectionMode,
GuiRowSelection,
GuiRowSelectionType,
} from "@generic-ui/ngx-grid";
import { NgxSuperSelectOptions } from "ngx-super-select";
import { _getFocusedElementPierceShadowDom } from "@angular/cdk/platform";
interface IUser {
name: string;
state: string;
registered: string;
country: string;
usage: number;
period: string;
payment: string;
activity: string;
avatar: string;
status: string;
color: string;
}
@Component({
templateUrl: "user_tasks.component.html",
})
export class UserTasksComponent implements OnInit {
public uid: number;
public uname: string;
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;
const userId = _self.uid;
if (res.role != "admin") {
setTimeout(function () {
_self.router.navigate(["/user/dashboard"]);
}, 100);
}
});
//get datagrid data
function isNotEmpty(value: any): boolean {
return value !== undefined && value !== null && value !== "";
}
}
public source: Array<any> = [];
public columns: Array<GuiColumn> = [];
public loading: boolean = true;
public rows: any = [];
public SelectedTask: any = {};
public SelectedTaskItems: any = "";
public runConfirmModalVisible: boolean = false;
public EditTaskModalVisible: boolean = false;
public DeleteConfirmModalVisible: boolean = false;
public Members: any = "";
public Snippets: any;
public SelectedMembers: any = [];
public NewMemberModalVisible: boolean = false;
public availbleMembers: any = [];
public NewMemberRows: any = [];
public SelectedNewMemberRows: any;
public sorting = {
enabled: true,
multiSorting: true,
};
searching: GuiSearching = {
enabled: true,
placeholder: "Search Devices",
};
options: Partial<NgxSuperSelectOptions> = {
selectionMode: "single",
actionsEnabled: false,
displayExpr: "name",
valueExpr: "id",
placeholder: "Snippet",
searchEnabled: true,
enableDarkMode: false,
};
public paging: GuiPaging = {
enabled: true,
page: 1,
pageSize: 10,
pageSizes: [5, 10, 25, 50],
display: GuiPagingDisplay.ADVANCED,
};
public columnMenu: GuiColumnMenu = {
enabled: true,
sort: true,
columnsManager: true,
};
public infoPanel: GuiInfoPanel = {
enabled: true,
infoDialog: false,
columnsManager: true,
schemaManager: true,
};
public rowSelection: boolean | GuiRowSelection = {
enabled: true,
type: GuiRowSelectionType.CHECKBOX,
mode: GuiRowSelectionMode.MULTIPLE,
};
show_new_member_form() {
this.NewMemberModalVisible = true;
var _self = this;
_self.availbleMembers = [];
this.SelectedNewMemberRows = [];
this.NewMemberRows = [];
var data = {
group_id: false,
search: false,
page: false,
size: 10000,
};
if (this.SelectedTask["selection_type"] == "devices")
_self.data_provider.get_dev_list(data).then((res) => {
_self.availbleMembers = res.filter(
(x: any) => !_self.SelectedTaskItems.includes(x.id)
);
_self.NewMemberModalVisible = true;
});
else
_self.data_provider.get_devgroup_list().then((res) => {
_self.availbleMembers = res.filter(
(x: any) => !_self.SelectedTaskItems.includes(x.id)
);
_self.NewMemberModalVisible = true;
});
}
ngOnInit(): void {
this.initGridTable();
}
submit(action: string) {
var _self = this;
if (action == "add") {
this.data_provider
.Add_task(_self.SelectedTask, _self.SelectedTaskItems)
.then((res) => {
_self.initGridTable();
});
} else {
this.data_provider
.Edit_task(_self.SelectedTask, _self.SelectedTaskItems)
.then((res) => {
_self.initGridTable();
});
}
this.EditTaskModalVisible = false;
}
onSelectedRowsNewMembers(rows: Array<GuiSelectedRow>): void {
this.NewMemberRows = rows;
this.SelectedNewMemberRows = rows.map((m: GuiSelectedRow) => m.source);
}
add_new_members() {
var _self = this;
_self.SelectedMembers = [
...new Set(_self.SelectedMembers.concat(_self.SelectedNewMemberRows)),
];
_self.SelectedTaskItems = _self.SelectedMembers.map((x: any) => {
return x.id;
});
this.NewMemberModalVisible = false;
}
editAddTask(item: any, action: string) {
if (action == "showadd") {
this.SelectedTask = {
id: 0,
action: "add",
taskcron: "* * * * *",
desc_cron: "",
description: "",
members: "",
name: "",
selection_type: "devices",
snippetid: "",
task_type: "backup",
};
this.SelectedMembers = [];
this.SelectedTaskItems = [];
this.EditTaskModalVisible = true;
return;
}
var _self = this;
this.SelectedTask = { ...item };
_self.data_provider.get_snippets("", "", "", 0, 1000).then((res) => {
_self.Snippets = res.map((x: any) => {
return { id: x.id, name: x.name };
});
});
if (action != "select_change") {
this.SelectedTask["action"] = "edit";
this.data_provider.get_task_members(_self.SelectedTask.id).then((res) => {
_self.SelectedMembers = res;
_self.EditTaskModalVisible = true;
_self.SelectedTaskItems = res.map((x: any) => {
return x.id;
});
});
} else {
_self.SelectedMembers = [];
this.SelectedTaskItems = [];
}
}
remove_member(item: any) {
var _self = this;
_self.SelectedMembers = _self.SelectedMembers.filter(
(x: any) => x.id != item.id
);
_self.SelectedTaskItems = _self.SelectedMembers.map((x: any) => {
return x.id;
});
}
onSelectValueChanged($event: any) {
this.SelectedTask["snippetid"] = $event;
}
onSnippetsValueChanged(v: any) {
var _self = this;
if (v == "" || v.length < 3) return;
_self.data_provider.get_snippets(v, "", "", 0, 1000).then((res) => {
_self.Snippets = res.map((x: any) => {
return { id: String(x.id), name: x.name };
});
});
}
get_member_by_id(id: string) {
return this.Members.find((x: any) => x.id == id);
}
confirm_delete(item: any = "", del: boolean = false) {
if (!del) {
this.SelectedTask = { ...item };
this.DeleteConfirmModalVisible = true;
} else {
var _self = this;
this.data_provider.Delete_task(_self.SelectedTask["id"]).then((res) => {
_self.initGridTable();
_self.DeleteConfirmModalVisible = false;
});
}
}
form_changed() {
this.editAddTask(this.SelectedTask, "select_change");
}
confirm_run(item: any) {
this.SelectedTask = { ...item };
this.DeleteConfirmModalVisible = true;
}
runTask() {
console.dir(this.SelectedTask);
}
logger(item: any) {
console.dir(item);
}
initGridTable(): void {
var _self = this;
this.data_provider.get_user_task_list().then((res) => {
_self.source = res.map((x: any) => {
return x;
});
_self.loading = false;
});
}
}

View file

@ -0,0 +1,33 @@
import { NgModule } from "@angular/core";
import { CommonModule } from "@angular/common";
import { FormsModule } from "@angular/forms";
import {
ButtonModule,
CardModule,
FormModule,
GridModule,
ModalModule,
} from "@coreui/angular";
import { UserTasksRoutingModule } from "./user_tasks-routing.module";
import { UserTasksComponent } from "./user_tasks.component";
import { GuiGridModule } from "@generic-ui/ngx-grid";
import { NgxSuperSelectModule} from "ngx-super-select";
@NgModule({
imports: [
UserTasksRoutingModule,
CardModule,
CommonModule,
GridModule,
FormModule,
ButtonModule,
GuiGridModule,
ModalModule,
FormsModule,
NgxSuperSelectModule,
],
declarations: [UserTasksComponent],
})
export class UserTasksModule {}

View file

@ -0,0 +1,22 @@
<c-row>
<c-col *ngFor="let widget of brandData; index as i" sm="6" xl="3">
<c-widget-stat-d
[color]="widget.color ?? ''"
[style]="widget.capBg ?? null"
[values]="widget.values"
class="mb-4"
>
<svg [name]="widget.icon" cIcon class="my-4 text-white" height="52"></svg>
<ng-container *ngIf="withCharts">
<c-chart
#chart="cChart"
[data]="widget.data"
[options]="chartOptions"
class="position-absolute w-100 h-100"
type="line"
>{{ chart.id }}</c-chart
>
</ng-container>
</c-widget-stat-d>
</c-col>
</c-row>

View file

@ -0,0 +1,36 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GridModule, WidgetModule } from '@coreui/angular';
import { ChartjsModule } from '@coreui/angular-chartjs';
import { IconModule } from '@coreui/icons-angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { WidgetsBrandComponent } from './widgets-brand.component';
describe('WidgetsBrandComponent', () => {
let component: WidgetsBrandComponent;
let fixture: ComponentFixture<WidgetsBrandComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ WidgetsBrandComponent ],
imports: [WidgetModule, GridModule, ChartjsModule, IconModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(WidgetsBrandComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,102 @@
import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, Input } from '@angular/core';
@Component({
selector: 'app-widgets-brand',
templateUrl: './widgets-brand.component.html',
styleUrls: ['./widgets-brand.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class WidgetsBrandComponent implements AfterContentInit {
constructor(
private changeDetectorRef: ChangeDetectorRef
) {}
@Input() withCharts?: boolean;
// @ts-ignore
chartOptions = {
elements: {
line: {
tension: 0.4
},
point: {
radius: 0,
hitRadius: 10,
hoverRadius: 4,
hoverBorderWidth: 3
}
},
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
scales: {
x: {
display: false
},
y: {
display: false
}
}
};
labels = ['January', 'February', 'March', 'April', 'May', 'June', 'July'];
datasets = {
borderWidth: 2,
fill: true
};
colors = {
backgroundColor: 'rgba(255,255,255,.1)',
borderColor: 'rgba(255,255,255,.55)',
pointHoverBackgroundColor: '#fff',
pointBackgroundColor: 'rgba(255,255,255,.55)'
};
brandData = [
{
icon: 'cibFacebook',
values: [{ title: 'friends', value: '89K' }, { title: 'feeds', value: '459' }],
capBg: { '--cui-card-cap-bg': '#3b5998' },
labels: [...this.labels],
data: {
labels: [...this.labels],
datasets: [{ ...this.datasets, data: [65, 59, 84, 84, 51, 55, 40], label: 'Facebook', ...this.colors }]
}
},
{
icon: 'cibTwitter',
values: [{ title: 'followers', value: '973k' }, { title: 'tweets', value: '1.792' }],
capBg: { '--cui-card-cap-bg': '#00aced' },
data: {
labels: [...this.labels],
datasets: [{ ...this.datasets, data: [1, 13, 9, 17, 34, 41, 38], label: 'Twitter', ...this.colors }]
}
},
{
icon: 'cib-linkedin',
values: [{ title: 'contacts', value: '500' }, { title: 'feeds', value: '1.292' }],
capBg: { '--cui-card-cap-bg': '#4875b4' },
data: {
labels: [...this.labels],
datasets: [{ ...this.datasets, data: [78, 81, 80, 45, 34, 12, 40], label: 'LinkedIn', ...this.colors }]
}
},
{
icon: 'cilCalendar',
values: [{ title: 'events', value: '12+' }, { title: 'meetings', value: '4' }],
color: 'warning',
data: {
labels: [...this.labels],
datasets: [{ ...this.datasets, data: [35, 23, 56, 22, 97, 23, 64], label: 'Events', ...this.colors }]
}
}
];
capStyle(value: string) {
return !!value ? { '--cui-card-cap-bg': value } : {};
}
ngAfterContentInit(): void {
this.changeDetectorRef.detectChanges();
}
}

View file

@ -0,0 +1,28 @@
<c-row >
<c-col *ngFor="let sensor of devicedata['sensors']; index as i" [sm]="6" [xl]="count_calc(devicedata)" >
<c-widget-stat-a
class="mb-2"
[color]="colors[i]"
[title]="sensor"
>
<ng-template cTemplateId="widgetValueTemplate" ngPreserveWhitespaces>
{{show_number(sensor,devicedata)}}
</ng-template>
<ng-template cTemplateId="widgetChartTemplate">
<c-chart [data]="devicedata[sensor]" [options]="(sensor=='rxp/txp-total') ? options[4] :options[2]" class="mt-3 mx-3" height="70" [type]="(sensor=='rxp/txp-total') ? 'bar' :'line'"></c-chart>
<div [innerHTML]='show_date(devicedata[sensor]["labels"][devicedata[sensor]["datasets"][0]["data"].length-1])' class="fs-6 fw-normal" style="
padding: 5px;
width: 200px;
text-align: center;
font-size: 0.8rem!important;
border-top: 1px solid #d5d5d55e;
display: inline-block;
margin: 0 auto;
"></div>
</ng-template>
</c-widget-stat-a>
</c-col>
</c-row>

View file

@ -0,0 +1,36 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ButtonModule, DropdownModule, GridModule, WidgetModule } from '@coreui/angular';
import { IconModule } from '@coreui/icons-angular';
import { ChartjsModule } from '@coreui/angular-chartjs';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { WidgetsDropdownComponent } from './widgets-dropdown.component';
describe('WidgetsDropdownComponent', () => {
let component: WidgetsDropdownComponent;
let fixture: ComponentFixture<WidgetsDropdownComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ WidgetsDropdownComponent ],
imports: [WidgetModule, DropdownModule, IconModule, ButtonModule, ChartjsModule, GridModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(WidgetsDropdownComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,423 @@
import {
AfterContentInit,
AfterViewInit,
ChangeDetectionStrategy,
ChangeDetectorRef,
Component,
OnInit,
Input,
ViewChild
} from '@angular/core';
import { getStyle } from '@coreui/utils';
import { ChartjsComponent } from '@coreui/angular-chartjs';
import { dataProvider } from '../../../providers/mikrowizard/data';
@Component({
selector: 'app-widgets-dropdown',
templateUrl: './widgets-dropdown.component.html',
styleUrls: ['./widgets-dropdown.component.scss'],
changeDetection: ChangeDetectionStrategy.Default
})
export class WidgetsDropdownComponent implements OnInit, AfterContentInit {
constructor(
private changeDetectorRef: ChangeDetectorRef,
private data_provider: dataProvider,
) {}
data: any[] = [];
options: any[] = [];
@Input() devicedata: any;
labels = [
'January',
'February',
'March',
'April',
'May',
'June',
'July',
'August',
'September',
'October',
'November',
'December',
'January',
'February',
'March',
'April'
];
colors = [
'primary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
'primary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
'primary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
'light',
'dark',
'primary',
'success',
'danger',
'warning',
'info',
'light',
'dark',
'primary',
'success',
'danger',
'warning',
'info',
'light',
'dark'
];
datasets = [
[{
label: 'My First dataset',
backgroundColor: 'transparent',
borderColor: 'rgba(255,255,255,.55)',
pointBackgroundColor: getStyle('--cui-primary'),
pointHoverBorderColor: getStyle('--cui-primary'),
data: [65, 59, 84, 84, 51, 55, 40]
}], [{
label: 'My Second dataset',
backgroundColor: 'transparent',
borderColor: 'rgba(255,255,255,.55)',
pointBackgroundColor: getStyle('--cui-info'),
pointHoverBorderColor: getStyle('--cui-info'),
data: [1, 18, 9, 17, 34, 22, 11]
}], [{
label: 'My Third dataset',
backgroundColor: 'rgba(255,255,255,.2)',
borderColor: 'rgba(255,255,255,.55)',
pointBackgroundColor: getStyle('--cui-warning'),
pointHoverBorderColor: getStyle('--cui-warning'),
data: [78, 81, 80, 45, 34, 12, 40],
fill: true
}], [{
label: 'My Fourth dataset',
backgroundColor: 'rgba(255,255,255,.2)',
borderColor: 'rgba(255,255,255,.55)',
data: [78, 81, 80, 45, 34, 12, 40, 85, 65, 23, 12, 98, 34, 84, 67, 82],
barPercentage: 0.7
}]
];
optionsDefault = {
plugins: {
legend: {
display: false
}
},
maintainAspectRatio: true,
scales: {
x: {
grid: {
display: false,
drawBorder: false
},
ticks: {
display: false
}
},
y: {
display: false,
grid: {
display: false
},
ticks: {
display: false
}
}
},
elements: {
line: {
borderWidth: 1,
tension: 0.4
},
point: {
radius: 4,
hitRadius: 10,
hoverRadius: 6
}
}
};
logger(data: any){
console.dir(data)
}
ngOnInit(): void {
this.setData();
}
ngAfterContentInit(): void {
this.changeDetectorRef.detectChanges();
}
convert_bw_human(mynumber:number=0,unit:string){
const units = ['bit', 'Kib', 'Mib', 'Gib', 'Tib'];
let unitIndex = 0;
while (mynumber >= 1024 && unitIndex < units.length - 1) {
mynumber /= 1024;
unitIndex++;
}
console.dir(mynumber)
switch (unit) {
case 'rx':
return mynumber.toFixed(3) + ' ' + units[unitIndex];
break;
case 'tx':
return mynumber.toFixed(3) + ' ' + units[unitIndex];
break;
default:
return mynumber;
break;
}
}
show_number(sensor:string,data:any){
if(sensor=='rxp/txp-total'){
let mynumber=data[sensor]["datasets"][0]["data"][data[sensor]["datasets"][0]["data"].length-1];
let mynumber1=data[sensor]["datasets"][1]["data"][data[sensor]["datasets"][1]["data"].length-1];
let res1=this.convert_bw_human(mynumber,data[sensor]["datasets"][0]['unit']);
let res2=this.convert_bw_human(mynumber1,data[sensor]["datasets"][1]['unit']);
return res1 + " / " + res2;
}
else{
let mynumber=data[sensor]["datasets"][0]["data"][data[sensor]["datasets"][0]["data"].length-1];
return mynumber
}
}
count_calc(data:any){
if(data.sensors.length > 4)
return 2
else if(data.sensors.length <= 4)
return 3
else
return 3
}
setData() {
for (let idx = 0; idx < 4; idx++) {
this.data[idx] = {
labels: idx < 3 ? this.labels.slice(0, 7) : this.labels,
datasets: this.datasets[idx]
};
}
this.setOptions();
}
show_date(date:string){
if(typeof date === "undefined")
return ""
if(date=='')
return ''
else if(date.split("T").length>1)
return "Last data : " + date.split("T")[0]
else if(date.split("T").length==1)
return "Last data : " + date.split("T").join(' ')
else
return date;
}
setOptions() {
for (let idx = 0; idx < 5; idx++) {
const options = JSON.parse(JSON.stringify(this.optionsDefault));
switch (idx) {
case 0: {
this.options.push(options);
break;
}
case 1: {
options.scales.y.min = -9;
options.scales.y.max = 39;
this.options.push(options);
break;
}
case 2: {
options.scales.x = { display: false };
options.scales.y = { display: false };
options.elements.line.borderWidth = 2;
options.elements.point.radius = 2;
this.options.push(options);
break;
}
case 3: {
options.scales.x.grid = { display: false, drawTicks: false };
options.scales.x.grid = { display: false, drawTicks: false, drawBorder: false };
options.scales.y.min = undefined;
options.scales.y.max = undefined;
options.elements = {};
this.options.push(options);
break;
}
case 4: {
options.plugins={
tooltip: {
callbacks: {
label: function(context:any) {
const units = ['bit', 'Kib', 'Mib', 'Gib', 'Tib'];
let label = context.dataset.label || '';
var res=context.parsed.y
let unitIndex = 0;
// if (res>8) res /=8;
while (res >= 1024 && unitIndex < units.length - 1) {
res /= 1024;
unitIndex++;
}
console.dir(res)
switch (context.dataset.unit) {
case 'rx':
return "rx/s :" + res.toFixed(3) + ' ' + units[unitIndex];
break;
case 'tx':
return "tx/s :" + res.toFixed(3) + ' ' + units[unitIndex];
break;
case 'rxp':
return "rxp/s :" + context.parsed.y;
break;
case 'txp':
return "txp/s :" + context.parsed.y;
break;
default:
return context.parsed.y;
break;
}
}
}
}
,
legend: {
display:false
}
}
options.scales={
'x':{ display: false },
'yA': {
display: false ,
stacked: true,
position: 'left',
type: 'linear',
scaleLabel: {
display: true,
},
},
'yB': {
display: false ,
stacked: true,
position: 'right',
type: 'linear',
}
};
options.elements.line.borderWidth = 2;
options.elements.point.radius = 2;
this.options.push(options);
break;
}
}
}
}
}
@Component({
selector: 'app-chart-sample',
template: '<c-chart type="line" [data]="data" [options]="options" width="300" #chart></c-chart>'
})
export class ChartSample implements AfterViewInit {
constructor() {}
@ViewChild('chart') chartComponent!: ChartjsComponent;
colors = {
label: 'My dataset',
backgroundColor: 'rgba(77,189,116,.2)',
borderColor: '#4dbd74',
pointHoverBackgroundColor: '#fff'
};
labels = ['Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa', 'Su'];
data = {
labels: this.labels,
datasets: [{
data: [65, 59, 84, 84, 51, 55, 40],
...this.colors,
fill: { value: 65 }
}]
};
options = {
maintainAspectRatio: false,
plugins: {
legend: {
display: false
}
},
elements: {
line: {
tension: 0.4
}
}
};
ngAfterViewInit(): void {
setTimeout(() => {
const data = () => {
return {
...this.data,
labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May'],
datasets: [{
...this.data.datasets[0],
data: [42, 88, 42, 66, 77],
fill: { value: 55 }
}, { ...this.data.datasets[0], borderColor: '#ffbd47', data: [88, 42, 66, 77, 42] }]
};
};
const newLabels = ['Jan', 'Feb', 'Mar', 'Apr', 'May'];
const newData = [42, 88, 42, 66, 77];
let { datasets, labels } = { ...this.data };
// @ts-ignore
const before = this.chartComponent?.chart?.data.datasets.length;
console.log('before', before);
// console.log('datasets, labels', datasets, labels)
// @ts-ignore
// this.data = data()
this.data = {
...this.data,
datasets: [{ ...this.data.datasets[0], data: newData }, {
...this.data.datasets[0],
borderColor: '#ffbd47',
data: [88, 42, 66, 77, 42]
}],
labels: newLabels
};
// console.log('datasets, labels', { datasets, labels } = {...this.data})
// @ts-ignore
setTimeout(() => {
const after = this.chartComponent?.chart?.data.datasets.length;
console.log('after', after);
});
}, 5000);
}
}

View file

@ -0,0 +1,56 @@
<c-row>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[0]" [options]="barOptions" class="mx-auto" height="40" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[1]" [options]="barOptions" class="mx-auto" height="40" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[2]" [options]="barOptions" class="mx-auto" height="40" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[3]" [options]="lineOptions" class="mx-auto" height="40" type="line" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[4]" [options]="lineOptions" class="mx-auto" height="40" type="line" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
<c-col xl="2" lg="4" sm="6">
<c-widget-stat-e
[title]="'title'"
[value]="'1,123'"
class="mb-4"
>
<c-chart [data]="data[5]" [options]="lineOptions" class="mx-auto" height="40" type="line" width="80"></c-chart>
</c-widget-stat-e>
</c-col>
</c-row>

View file

@ -0,0 +1,35 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { GridModule, WidgetModule } from '@coreui/angular';
import { ChartjsModule } from '@coreui/angular-chartjs';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { WidgetsEComponent } from './widgets-e.component';
describe('WidgetsEComponent', () => {
let component: WidgetsEComponent;
let fixture: ComponentFixture<WidgetsEComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ WidgetsEComponent ],
imports: [WidgetModule, GridModule, ChartjsModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(WidgetsEComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

Some files were not shown because too many files have changed in this diff Show more