mirror of
https://github.com/MikroWizard/mikrofront.git
synced 2025-12-28 12:59:31 +00:00
MikroWizard Initial commit | MikroFront Welcome to the world :)
This commit is contained in:
commit
b97aec6b97
203 changed files with 41097 additions and 0 deletions
20
src/app/views/acc_log/acc-routing.module.ts
Normal file
20
src/app/views/acc_log/acc-routing.module.ts
Normal 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 {}
|
||||
112
src/app/views/acc_log/acc.component.html
Normal file
112
src/app/views/acc_log/acc.component.html
Normal 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>
|
||||
86
src/app/views/acc_log/acc.component.scss
Normal file
86
src/app/views/acc_log/acc.component.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
204
src/app/views/acc_log/acc.component.ts
Normal file
204
src/app/views/acc_log/acc.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
42
src/app/views/acc_log/acc.module.ts
Normal file
42
src/app/views/acc_log/acc.module.ts
Normal 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 {}
|
||||
21
src/app/views/auth_log/auth-routing.module.ts
Normal file
21
src/app/views/auth_log/auth-routing.module.ts
Normal 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 {
|
||||
}
|
||||
142
src/app/views/auth_log/auth.component.html
Normal file
142
src/app/views/auth_log/auth.component.html
Normal 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>
|
||||
36
src/app/views/auth_log/auth.component.scss
Normal file
36
src/app/views/auth_log/auth.component.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
222
src/app/views/auth_log/auth.component.ts
Normal file
222
src/app/views/auth_log/auth.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
41
src/app/views/auth_log/auth.module.ts
Normal file
41
src/app/views/auth_log/auth.module.ts
Normal 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 {
|
||||
}
|
||||
21
src/app/views/backups/backups-routing.module.ts
Normal file
21
src/app/views/backups/backups-routing.module.ts
Normal 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 {
|
||||
}
|
||||
68
src/app/views/backups/backups.component.html
Normal file
68
src/app/views/backups/backups.component.html
Normal 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>
|
||||
0
src/app/views/backups/backups.component.scss
Normal file
0
src/app/views/backups/backups.component.scss
Normal file
153
src/app/views/backups/backups.component.ts
Normal file
153
src/app/views/backups/backups.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
36
src/app/views/backups/backups.module.ts
Normal file
36
src/app/views/backups/backups.module.ts
Normal 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 {}
|
||||
21
src/app/views/dashboard/dashboard-routing.module.ts
Normal file
21
src/app/views/dashboard/dashboard-routing.module.ts
Normal 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 {
|
||||
}
|
||||
168
src/app/views/dashboard/dashboard.component.html
Normal file
168
src/app/views/dashboard/dashboard.component.html
Normal 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>
|
||||
217
src/app/views/dashboard/dashboard.component.ts
Normal file
217
src/app/views/dashboard/dashboard.component.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
43
src/app/views/dashboard/dashboard.module.ts
Normal file
43
src/app/views/dashboard/dashboard.module.ts
Normal 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 {}
|
||||
21
src/app/views/device_detail/device-routing.module.ts
Normal file
21
src/app/views/device_detail/device-routing.module.ts
Normal 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 {
|
||||
}
|
||||
167
src/app/views/device_detail/device.component.html
Normal file
167
src/app/views/device_detail/device.component.html
Normal 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>
|
||||
7
src/app/views/device_detail/device.component.scss
Normal file
7
src/app/views/device_detail/device.component.scss
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
:host {
|
||||
.legend {
|
||||
small {
|
||||
font-size: x-small;
|
||||
}
|
||||
}
|
||||
}
|
||||
36
src/app/views/device_detail/device.component.spec.ts
Normal file
36
src/app/views/device_detail/device.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
437
src/app/views/device_detail/device.component.ts
Normal file
437
src/app/views/device_detail/device.component.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
42
src/app/views/device_detail/device.module.ts
Normal file
42
src/app/views/device_detail/device.module.ts
Normal 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 {}
|
||||
21
src/app/views/device_logs/devlogs-routing.module.ts
Normal file
21
src/app/views/device_logs/devlogs-routing.module.ts
Normal 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 {
|
||||
}
|
||||
139
src/app/views/device_logs/devlogs.component.html
Normal file
139
src/app/views/device_logs/devlogs.component.html
Normal 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>
|
||||
125
src/app/views/device_logs/devlogs.component.scss
Normal file
125
src/app/views/device_logs/devlogs.component.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
234
src/app/views/device_logs/devlogs.component.ts
Normal file
234
src/app/views/device_logs/devlogs.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
47
src/app/views/device_logs/devlogs.module.ts
Normal file
47
src/app/views/device_logs/devlogs.module.ts
Normal 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 {}
|
||||
21
src/app/views/devices/devices-routing.module.ts
Normal file
21
src/app/views/devices/devices-routing.module.ts
Normal 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 {
|
||||
}
|
||||
346
src/app/views/devices/devices.component.html
Normal file
346
src/app/views/devices/devices.component.html
Normal 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>
|
||||
460
src/app/views/devices/devices.component.ts
Normal file
460
src/app/views/devices/devices.component.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
50
src/app/views/devices/devices.module.ts
Normal file
50
src/app/views/devices/devices.module.ts
Normal 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 {}
|
||||
21
src/app/views/devices_group/devgroup-routing.module.ts
Normal file
21
src/app/views/devices_group/devgroup-routing.module.ts
Normal 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 {
|
||||
}
|
||||
178
src/app/views/devices_group/devgroup.component.html
Normal file
178
src/app/views/devices_group/devgroup.component.html
Normal 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">
|
||||
{{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">
|
||||
{{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>
|
||||
240
src/app/views/devices_group/devgroup.component.ts
Normal file
240
src/app/views/devices_group/devgroup.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
35
src/app/views/devices_group/devgroup.module.ts
Normal file
35
src/app/views/devices_group/devgroup.module.ts
Normal 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 {}
|
||||
16
src/app/views/icons/coreui-icons.component.html
Normal file
16
src/app/views/icons/coreui-icons.component.html
Normal 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>
|
||||
46
src/app/views/icons/coreui-icons.component.ts
Normal file
46
src/app/views/icons/coreui-icons.component.ts
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
48
src/app/views/icons/icons-routing.module.ts
Normal file
48
src/app/views/icons/icons-routing.module.ts
Normal 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 {
|
||||
}
|
||||
25
src/app/views/icons/icons.module.ts
Normal file
25
src/app/views/icons/icons.module.ts
Normal 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 {
|
||||
}
|
||||
51
src/app/views/pages/login/login.component.html
Normal file
51
src/app/views/pages/login/login.component.html
Normal 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>
|
||||
0
src/app/views/pages/login/login.component.scss
Normal file
0
src/app/views/pages/login/login.component.scss
Normal file
35
src/app/views/pages/login/login.component.spec.ts
Normal file
35
src/app/views/pages/login/login.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
66
src/app/views/pages/login/login.component.ts
Normal file
66
src/app/views/pages/login/login.component.ts
Normal 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!";
|
||||
});
|
||||
// });
|
||||
}
|
||||
|
||||
}
|
||||
22
src/app/views/pages/page404/page404.component.html
Normal file
22
src/app/views/pages/page404/page404.component.html
Normal 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>
|
||||
0
src/app/views/pages/page404/page404.component.scss
Normal file
0
src/app/views/pages/page404/page404.component.scss
Normal file
35
src/app/views/pages/page404/page404.component.spec.ts
Normal file
35
src/app/views/pages/page404/page404.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
12
src/app/views/pages/page404/page404.component.ts
Normal file
12
src/app/views/pages/page404/page404.component.ts
Normal 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() { }
|
||||
|
||||
}
|
||||
22
src/app/views/pages/page500/page500.component.html
Normal file
22
src/app/views/pages/page500/page500.component.html
Normal 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>
|
||||
0
src/app/views/pages/page500/page500.component.scss
Normal file
0
src/app/views/pages/page500/page500.component.scss
Normal file
35
src/app/views/pages/page500/page500.component.spec.ts
Normal file
35
src/app/views/pages/page500/page500.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
12
src/app/views/pages/page500/page500.component.ts
Normal file
12
src/app/views/pages/page500/page500.component.ts
Normal 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() { }
|
||||
|
||||
}
|
||||
36
src/app/views/pages/pages-routing.module.ts
Normal file
36
src/app/views/pages/pages-routing.module.ts
Normal 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 {
|
||||
}
|
||||
32
src/app/views/pages/pages.module.ts
Normal file
32
src/app/views/pages/pages.module.ts
Normal 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 {
|
||||
}
|
||||
21
src/app/views/permissions/permissions-routing.module.ts
Normal file
21
src/app/views/permissions/permissions-routing.module.ts
Normal 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 {
|
||||
}
|
||||
137
src/app/views/permissions/permissions.component.html
Normal file
137
src/app/views/permissions/permissions.component.html
Normal 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">
|
||||
{{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>
|
||||
260
src/app/views/permissions/permissions.component.ts
Normal file
260
src/app/views/permissions/permissions.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
43
src/app/views/permissions/permissions.module.ts
Normal file
43
src/app/views/permissions/permissions.module.ts
Normal 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 {}
|
||||
21
src/app/views/settings/settings-routing.module.ts
Normal file
21
src/app/views/settings/settings-routing.module.ts
Normal 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 {
|
||||
}
|
||||
227
src/app/views/settings/settings.component.html
Normal file
227
src/app/views/settings/settings.component.html
Normal 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">
|
||||
{{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>
|
||||
10
src/app/views/settings/settings.component.scss
Normal file
10
src/app/views/settings/settings.component.scss
Normal 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;
|
||||
}
|
||||
259
src/app/views/settings/settings.component.ts
Normal file
259
src/app/views/settings/settings.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
41
src/app/views/settings/settings.module.ts
Normal file
41
src/app/views/settings/settings.module.ts
Normal 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 {}
|
||||
1456
src/app/views/settings/timezones-data.ts
Normal file
1456
src/app/views/settings/timezones-data.ts
Normal file
File diff suppressed because it is too large
Load diff
21
src/app/views/snippets/snippets-routing.module.ts
Normal file
21
src/app/views/snippets/snippets-routing.module.ts
Normal 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 {
|
||||
}
|
||||
130
src/app/views/snippets/snippets.component.html
Normal file
130
src/app/views/snippets/snippets.component.html
Normal 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>
|
||||
|
||||
|
||||
214
src/app/views/snippets/snippets.component.ts
Normal file
214
src/app/views/snippets/snippets.component.ts
Normal 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 {
|
||||
}
|
||||
}
|
||||
34
src/app/views/snippets/snippets.module.ts
Normal file
34
src/app/views/snippets/snippets.module.ts
Normal 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 {}
|
||||
21
src/app/views/syslog/syslog-routing.module.ts
Normal file
21
src/app/views/syslog/syslog-routing.module.ts
Normal 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 {
|
||||
}
|
||||
104
src/app/views/syslog/syslog.component.html
Normal file
104
src/app/views/syslog/syslog.component.html
Normal 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>
|
||||
128
src/app/views/syslog/syslog.component.scss
Normal file
128
src/app/views/syslog/syslog.component.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
204
src/app/views/syslog/syslog.component.ts
Normal file
204
src/app/views/syslog/syslog.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
41
src/app/views/syslog/syslog.module.ts
Normal file
41
src/app/views/syslog/syslog.module.ts
Normal 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 {}
|
||||
11
src/app/views/toast-simple/toast-sample-icon.component.svg
Normal file
11
src/app/views/toast-simple/toast-sample-icon.component.svg
Normal 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 |
14
src/app/views/toast-simple/toast-sample-icon.component.ts
Normal file
14
src/app/views/toast-simple/toast-sample-icon.component.ts
Normal 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 {
|
||||
}
|
||||
|
||||
}
|
||||
12
src/app/views/toast-simple/toast.component.html
Normal file
12
src/app/views/toast-simple/toast.component.html
Normal 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>
|
||||
4
src/app/views/toast-simple/toast.component.scss
Normal file
4
src/app/views/toast-simple/toast.component.scss
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
:host {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
34
src/app/views/toast-simple/toast.component.spec.ts
Normal file
34
src/app/views/toast-simple/toast.component.spec.ts
Normal 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();
|
||||
});
|
||||
});
|
||||
28
src/app/views/toast-simple/toast.component.ts
Normal file
28
src/app/views/toast-simple/toast.component.ts
Normal 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);
|
||||
}
|
||||
}
|
||||
21
src/app/views/user_manager/user_manager-routing.module.ts
Normal file
21
src/app/views/user_manager/user_manager-routing.module.ts
Normal 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 {
|
||||
}
|
||||
261
src/app/views/user_manager/user_manager.component.html
Normal file
261
src/app/views/user_manager/user_manager.component.html
Normal 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">
|
||||
{{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">
|
||||
{{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>
|
||||
296
src/app/views/user_manager/user_manager.component.ts
Normal file
296
src/app/views/user_manager/user_manager.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
39
src/app/views/user_manager/user_manager.module.ts
Normal file
39
src/app/views/user_manager/user_manager.module.ts
Normal 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 {}
|
||||
21
src/app/views/user_tasks/user_tasks-routing.module.ts
Normal file
21
src/app/views/user_tasks/user_tasks-routing.module.ts
Normal 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 {
|
||||
}
|
||||
268
src/app/views/user_tasks/user_tasks.component.html
Normal file
268
src/app/views/user_tasks/user_tasks.component.html
Normal 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> {{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">
|
||||
{{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">
|
||||
{{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>
|
||||
306
src/app/views/user_tasks/user_tasks.component.ts
Normal file
306
src/app/views/user_tasks/user_tasks.component.ts
Normal 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;
|
||||
});
|
||||
}
|
||||
}
|
||||
33
src/app/views/user_tasks/user_tasks.module.ts
Normal file
33
src/app/views/user_tasks/user_tasks.module.ts
Normal 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 {}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
102
src/app/views/widgets/widgets-brand/widgets-brand.component.ts
Normal file
102
src/app/views/widgets/widgets-brand/widgets-brand.component.ts
Normal 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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();
|
||||
});
|
||||
});
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
56
src/app/views/widgets/widgets-e/widgets-e.component.html
Normal file
56
src/app/views/widgets/widgets-e/widgets-e.component.html
Normal 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>
|
||||
0
src/app/views/widgets/widgets-e/widgets-e.component.scss
Normal file
0
src/app/views/widgets/widgets-e/widgets-e.component.scss
Normal file
35
src/app/views/widgets/widgets-e/widgets-e.component.spec.ts
Normal file
35
src/app/views/widgets/widgets-e/widgets-e.component.spec.ts
Normal 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
Loading…
Add table
Add a link
Reference in a new issue