MikroWizard Initial commit | MikroFront Welcome to the world :)

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

View file

@ -0,0 +1,135 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { DefaultLayoutComponent } from './containers';
import { Page404Component } from './views/pages/page404/page404.component';
import { Page500Component } from './views/pages/page500/page500.component';
import { LoginComponent } from './views/pages/login/login.component';
const routes: Routes = [
{
path: '',
redirectTo: 'dashboard',
pathMatch: 'full'
},
{
path: '',
component: DefaultLayoutComponent,
data: {
title: 'Home'
},
children: [
{
path: 'dashboard',
loadChildren: () =>
import('./views/dashboard/dashboard.module').then((m) => m.DashboardModule)
},
{
path: 'devices',
loadChildren: () =>
import('./views/devices/devices.module').then((m) => m.DevicesModule)
},
{
path: 'device-stats',
loadChildren: () =>
import('./views/device_detail/device.module').then((m) => m.DeviceModule)
},
{
path: 'deviceGroup',
loadChildren: () =>
import('./views/devices_group/devgroup.module').then((m) => m.DevicesGroupModule)
},
{
path: 'authlog',
loadChildren: () =>
import('./views/auth_log/auth.module').then((m) => m.AuthModule)
},
{
path: 'devlogs',
loadChildren: () =>
import('./views/device_logs/devlogs.module').then((m) => m.DevLogsModule)
},
{
path: 'syslog',
loadChildren: () =>
import('./views/syslog/syslog.module').then((m) => m.SyslogModule)
},
{
path: 'backups',
loadChildren: () =>
import('./views/backups/backups.module').then((m) => m.BackupsModule)
},
{
path: 'settings',
loadChildren: () =>
import('./views/settings/settings.module').then((m) => m.SettingsModule)
},
{
path: 'accountlog',
loadChildren: () =>
import('./views/acc_log/acc.module').then((m) => m.AccModule)
},
{
path: 'user_tasks',
loadChildren: () =>
import('./views/user_tasks/user_tasks.module').then((m) => m.UserTasksModule)
},
{
path: 'snippets',
loadChildren: () =>
import('./views/snippets/snippets.module').then((m) => m.SnippetsModule)
},
{
path: 'user_manager',
loadChildren: () =>
import('./views/user_manager/user_manager.module').then((m) => m.UserManagerModule)
},
{
path: 'permissions',
loadChildren: () =>
import('./views/permissions/permissions.module').then((m) => m.PermissionsModule)
},
{
path: 'pages',
loadChildren: () =>
import('./views/pages/pages.module').then((m) => m.PagesModule)
},
]
},
{
path: '404',
component: Page404Component,
data: {
title: 'Page 404'
}
},
{
path: '500',
component: Page500Component,
data: {
title: 'Page 500'
}
},
{
path: 'login',
component: LoginComponent,
data: {
title: 'Login Page'
}
},
{path: '**', redirectTo: 'dashboard'}
];
@NgModule({
imports: [
RouterModule.forRoot(routes, {
scrollPositionRestoration: 'top',
anchorScrolling: 'enabled',
initialNavigation: 'enabledBlocking'
// relativeLinkResolution: 'legacy'
})
],
exports: [RouterModule]
})
export class AppRoutingModule {
}

View file

@ -0,0 +1,28 @@
import { TestBed } from '@angular/core/testing';
import { RouterTestingModule } from '@angular/router/testing';
import { AppComponent } from './app.component';
describe('AppComponent', () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [
RouterTestingModule
],
declarations: [
AppComponent
],
}).compileComponents();
});
it('should create the app', () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app).toBeTruthy();
});
it(`should have as title 'CoreUI Free Angular Admin Template'`, () => {
const fixture = TestBed.createComponent(AppComponent);
const app = fixture.componentInstance;
expect(app.title).toEqual('CoreUI Free Angular Admin Template');
});
});

33
src/app/app.component.ts Normal file
View file

@ -0,0 +1,33 @@
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from '@angular/router';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from './icons/icon-subset';
import { Title } from '@angular/platform-browser';
@Component({
selector: 'app-root',
template: '<router-outlet></router-outlet>',
})
export class AppComponent implements OnInit {
title = 'MikroWizard , Mikrotik router managent system';
constructor(
private router: Router,
private titleService: Title,
private iconSetService: IconSetService
) {
titleService.setTitle(this.title);
// iconSet singleton
iconSetService.icons = { ...iconSubset };
}
ngOnInit(): void {
console.log(this.router.url);
this.router.events.subscribe((evt) => {
if (!(evt instanceof NavigationEnd)) {
return;
}
});
}
}

116
src/app/app.module.ts Normal file
View file

@ -0,0 +1,116 @@
import { NgModule ,APP_INITIALIZER} from '@angular/core';
import { HashLocationStrategy, LocationStrategy, PathLocationStrategy } from '@angular/common';
import { BrowserModule, Title } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { ReactiveFormsModule,FormsModule } from '@angular/forms';
import { NgScrollbarModule } from 'ngx-scrollbar';
import { HttpClientModule } from '@angular/common/http';
// Import routing module
import { AppRoutingModule } from './app-routing.module';
import { provideDateFnsAdapter } from 'ngx-material-date-fns-adapter';
// Import app component
import { AppComponent } from './app.component';
// Import containers
import { DefaultFooterComponent, DefaultHeaderComponent, DefaultLayoutComponent } from './containers';
import { MikroWizardProvider } from './providers/mikrowizard/provider';
import { dataProvider } from './providers/mikrowizard/data';
import { loginChecker } from './providers/login_checker';
import { FontAwesomeModule } from '@fortawesome/angular-fontawesome';
import { provideHighlightOptions, Highlight, HighlightAuto } from 'ngx-highlightjs';
import {
AvatarModule,
BadgeModule,
BreadcrumbModule,
ButtonGroupModule,
ButtonModule,
CardModule,
DropdownModule,
FooterModule,
FormModule,
GridModule,
HeaderModule,
ListGroupModule,
NavModule,
ProgressModule,
SharedModule,
SidebarModule,
TabsModule,
UtilitiesModule,
ModalModule
} from '@coreui/angular';
import { IconModule, IconSetService } from '@coreui/icons-angular';
const APP_CONTAINERS = [
DefaultFooterComponent,
DefaultHeaderComponent,
DefaultLayoutComponent
];
export function loginStatusProviderFactory(provider: loginChecker) {
return () => provider.load();
}
@NgModule({
declarations: [AppComponent, ...APP_CONTAINERS],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
AvatarModule,
BreadcrumbModule,
FooterModule,
DropdownModule,
GridModule,
HeaderModule,
SidebarModule,
IconModule,
NavModule,
HttpClientModule,
ButtonModule,
FormModule,
UtilitiesModule,
ButtonGroupModule,
ReactiveFormsModule,
FormsModule,
SidebarModule,
SharedModule,
TabsModule,
ListGroupModule,
ProgressModule,
BadgeModule,
ListGroupModule,
CardModule,
NgScrollbarModule,
ModalModule,
FontAwesomeModule
],
providers: [
{
provide: LocationStrategy,
useClass: HashLocationStrategy
},
MikroWizardProvider,
dataProvider,
loginChecker,
IconSetService,
provideDateFnsAdapter(),
provideHighlightOptions({
fullLibraryLoader: () => import('highlight.js'),
lineNumbersLoader: () => import('ngx-highlightjs/line-numbers')
}),
{
provide: APP_INITIALIZER,
useFactory: loginStatusProviderFactory,
deps: [loginChecker],
multi: true,
},
Title
],
bootstrap: [AppComponent]
})
export class AppModule {
}

View file

@ -0,0 +1,158 @@
import { INavData } from '@coreui/angular';
export const navItems: INavData[] = [
{
name: 'Dashboard',
url: '/dashboard',
iconComponent: { name: 'cil-speedometer' },
},
{
title: true,
name: 'Device Managment'
},
{
name: 'Devices',
url: '/devices',
icon: 'fa-solid fa-server'
},
{
name: 'Device Groups',
url: '/deviceGroup',
// linkProps: { fragment: 'someAnchor' },
icon: 'fa-solid fa-layer-group'
},
// {
// name: 'Tools',
// url: '/login',
// icon: 'fa-solid fa-screwdriver-wrench',
// children: [
// {
// name: 'BW test',
// url: '/login',
// icon: 'fa-solid fa-file-circle-check'
// },
// {
// name: 'Ping test',
// url: '/register',
// icon: 'fa-solid fa-arrow-right-arrow-left'
// },
// ]
// },
{
name: 'Backup & Config',
title: true
},
{
name: 'Task Planer',
url: '/user_tasks',
icon: 'fa-solid fa-calendar-week'
},
{
name: 'Backups',
url: '/backups',
icon: 'fa-solid fa-database'
},
{
name: 'snippets',
url: '/snippets',
icon: 'fa-solid fa-code'
},
// {
// name: 'Tools',
// url: '/login',
// icon: 'fa-solid fa-screwdriver-wrench',
// children: [
// {
// name: 'Backup comparator',
// url: '/login',
// icon: 'fa-solid fa-code-compare'
// },
// {
// name: 'Backup search',
// url: '/register',
// icon: 'fa-solid fa-magnifying-glass-arrow-right'
// },
// {
// name: 'batch execute',
// url: '/register',
// icon: 'fa-solid fa-terminal'
// },
// ]
// },
{
name: 'Reports',
title: true
},
{
name: 'Authentication',
url: '/authlog',
icon: 'fa-solid fa-check-to-slot',
},
{
name: 'Accounting',
url: '/accountlog',
icon: 'fa-solid fa-list-check',
},
{
name: 'Device Logs',
url: '/devlogs',
icon: 'fa-regular fa-rectangle-list',
},
{
name: 'System Logs',
url: '/syslog',
icon: 'fa-solid fa-person-circle-question',
},
{
title: true,
name: 'Users'
},
{
name: 'Users Management',
url: '/user_manager',
icon: 'fa-solid fa-user-gear' ,
},
{
name: 'Permissions',
url: '/permissions',
icon: 'fa-solid fa-users' ,
},
{
title: true,
name: 'System',
class: 'py-0'
},
{
name: 'Settings',
url: '/settings',
icon: 'fa-solid fa-gear' ,
},
// {
// name: 'Backup',
// url: '/login',
// icon: 'cil-star' ,
// },
{
title: true,
name: 'Links',
class: 'py-0'
},
{
name: 'Docs',
url: 'https://mikrowizard.com/docs',
iconComponent: { name: 'cil-description' },
attributes: { target: '_blank', class: '-text-dark' },
class: 'mt-auto'
},
{
name: 'Buy Pro',
url: 'https://mikrowizard.com/pricing/',
icon:'fa-solid fa-money-check-dollar',
attributes: { target: '_blank' }
}
];

View file

@ -0,0 +1,6 @@
<!--<c-footer>-->
<div>
<a href="https://mikrowizard.com" target="_blank">MikroWizard</a>
<span> &copy; 2024 </span>
</div>
<!--</c-footer>-->

View file

@ -0,0 +1,25 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { DefaultFooterComponent } from './default-footer.component';
describe('DefaultFooterComponent', () => {
let component: DefaultFooterComponent;
let fixture: ComponentFixture<DefaultFooterComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ DefaultFooterComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(DefaultFooterComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,13 @@
import { Component } from '@angular/core';
import { FooterComponent } from '@coreui/angular';
@Component({
selector: 'app-default-footer',
templateUrl: './default-footer.component.html',
styleUrls: ['./default-footer.component.scss'],
})
export class DefaultFooterComponent extends FooterComponent {
constructor() {
super();
}
}

View file

@ -0,0 +1,93 @@
<!--<c-header class="mb-4 d-print-none" position="sticky">-->
<ng-container>
<c-container [fluid]="true">
<button
toggle="visible"
cHeaderToggler
[cSidebarToggle]="sidebarId"
class="ps-1"
>
<svg cIcon
name="cilMenu"
size="lg"
></svg>
</button>
<!-- <c-header-nav class="d-none d-lg-flex me-auto">
<c-nav-item>
<a cNavLink routerLink="/dashboard" routerLinkActive="active">
Dashboard
</a>
</c-nav-item>
<c-nav-item>
<a cNavLink routerLink="/users" routerLinkActive="active">Users</a>
</c-nav-item>
<c-nav-item>
<a cNavLink routerLink="/settings" routerLinkActive="active">
Settings
</a>
</c-nav-item>
</c-header-nav> -->
<!-- <c-header-nav class="d-none d-lg-flex">
<c-nav-item>
<a routerLink="./" cNavLink>
<svg cIcon name="cilBell" size="lg"></svg>
</a>
</c-nav-item>
<c-nav-item>
<a routerLink="./" cNavLink>
<svg cIcon name="cilList" size="lg"></svg>
</a>
</c-nav-item>
<c-nav-item>
<a routerLink="./" cNavLink>
<svg cIcon name="cilEnvelopeOpen" size="lg"></svg>
</a>
</c-nav-item>
</c-header-nav> -->
<c-header-nav class="ms-3">
<ng-container *ngTemplateOutlet="userDropdown"></ng-container>
</c-header-nav>
</c-container>
<c-header-divider></c-header-divider>
<c-container [fluid]="true">
<c-breadcrumb-router class="ms-2"></c-breadcrumb-router>
</c-container>
</ng-container>
<!--</c-header>-->
<ng-template #userDropdown>
<c-dropdown alignment="end" variant="nav-item">
<button
cButton
color=""
[caret]="false"
cDropdownToggle
class="py-0"
>
<svg cIcon class="me-2" name="cilUser"></svg>
{{fname}} {{lname}}
</button>
<ul cDropdownMenu class="pt-0 pr-5 w-auto">
<li>
<h6 cDropdownHeader class="bg-light fw-semibold py-2">User Menu</h6>
</li>
<li>
<button (click)="callParent()" cDropdownItem>
<svg cIcon class="me-2" name="cilUser"></svg>
Change password
</button>
</li>
<li>
<a routerLink="./" (click)="logout()" cDropdownItem>
<svg cIcon class="me-2" name="cilExitToApp"></svg>
Logout
</a>
</li>
</ul>
</c-dropdown>
</ng-template>

View file

@ -0,0 +1,43 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import {
AvatarModule,
BadgeModule,
BreadcrumbModule,
DropdownModule,
GridModule,
HeaderModule,
NavModule, SidebarModule
} from '@coreui/angular';
import { IconSetService } from '@coreui/icons-angular';
import { iconSubset } from '../../../icons/icon-subset';
import { DefaultHeaderComponent } from './default-header.component';
import { RouterTestingModule } from '@angular/router/testing';
describe('DefaultHeaderComponent', () => {
let component: DefaultHeaderComponent;
let fixture: ComponentFixture<DefaultHeaderComponent>;
let iconSetService: IconSetService;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [DefaultHeaderComponent],
imports: [GridModule, HeaderModule, NavModule, BadgeModule, AvatarModule, DropdownModule, BreadcrumbModule, RouterTestingModule, SidebarModule],
providers: [IconSetService]
})
.compileComponents();
});
beforeEach(() => {
iconSetService = TestBed.inject(IconSetService);
iconSetService.icons = { ...iconSubset };
fixture = TestBed.createComponent(DefaultHeaderComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View file

@ -0,0 +1,67 @@
import { Component, Input ,Output,EventEmitter} from '@angular/core';
import { FormControl, FormGroup } from '@angular/forms';
import { loginChecker } from '../../../providers/login_checker';
import { Router } from "@angular/router";
import { dataProvider } from '../../../providers/mikrowizard/data';
import { User } from '../../../providers/mikrowizard/user';
import { ClassToggleService, HeaderComponent } from '@coreui/angular';
@Component({
selector: 'app-default-header',
templateUrl: './default-header.component.html',
})
export class DefaultHeaderComponent extends HeaderComponent {
@Input() sidebarId: string = "sidebar";
@Output() UserModalEvent = new EventEmitter<any>();
public newMessages = new Array(4)
public newTasks = new Array(5)
public newNotifications = new Array(5)
public current_user: User;
public uid: number;
public uname: string;
public fname: string;
public lname: string;
public UserProfileModalVisible : boolean = false;
constructor(
private classToggler: ClassToggleService,
private router: Router,
private login_checker: loginChecker,
private data_provider: dataProvider,
) {
super();
var _self = this;
var session_info: string = localStorage.getItem('current_user') || "[]]";
this.current_user = JSON.parse(session_info);
}
submit(){
}
get_user_info() {
var _self = this;
this.uid = this.current_user.partner_id;
this.uname = this.current_user.name;
this.fname = this.current_user.firstname;
this.lname = this.current_user.lastname;
}
callParent(): void {
this.UserModalEvent.next('test');
}
logout() {
this.data_provider.logout().then(res => {
this.router.navigate(['login']);
})
}
ngOnInit(): void {
var _self = this;
this.get_user_info();
}
}

View file

@ -0,0 +1,80 @@
<!--sidebar-->
<c-sidebar
#sidebar="cSidebar"
class="d-print-none sidebar sidebar-fixed"
id="sidebar"
visible
>
<c-sidebar-brand
[brandFull]="{
src: 'assets/img/brand/logo-MIkroWizard-big-white.svg',
width: 200,
height: 46,
alt: 'MikroWizard Logo'
}"
[brandNarrow]="{
src: 'assets/img/brand/logo-MIkroWizard-small-color.svg',
width: 46,
height: 46,
alt: 'MikroWizard Logo'
}"
routerLink="./"
/>
<ng-scrollbar pointerEventsMethod="scrollbar">
<c-sidebar-nav
[navItems]="navItems"
dropdownMode="close"
/>
</ng-scrollbar>
<c-sidebar-toggler
*ngIf="!sidebar.narrow"
toggle="unfoldable"
cSidebarToggle="sidebar"
/>
</c-sidebar>
<!--main-->
<div class="wrapper d-flex flex-column min-vh-100 bg-light dark:bg-transparent">
<!--app-header-->
<app-default-header (UserModalEvent)="show_user_modal()" class="mb-4 d-print-none header header-sticky" position="sticky" sidebarId="sidebar" />
<!--app-body-->
<div class="body flex-grow-1 px-3">
<c-container breakpoint="fluid" class="h-auto">
<router-outlet />
</c-container>
</div>
<!--app footer-->
<app-default-footer />
</div>
<c-modal #UserProfileModal backdrop="static" size="lg" [(visible)]="UserProfileModalVisible" id="UserProfileModal">
<c-modal-header>
<h5 cModalTitle>Change Password Form of<code><b>{{ uname }}({{ fname }} {{lname}})</b></code></h5>
<button [cModalToggle]="UserProfileModal.id" cButtonClose></button>
</c-modal-header>
<c-modal-body>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl id="floatingInput" [(ngModel)]="password['cupass']" placeholder="Current Password" />
<label cLabel for="floatingInput">Current Password</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl (ngModelChange)="password_changed('pass1',$event)" [(ngModel)]="password['pass1']" id="floatingInput" placeholder="New Password" />
<label cLabel for="floatingInput">New Password</label>
</div>
<div [cFormFloating]="true" class="mb-3">
<input type="password" cFormControl (ngModelChange)="password_changed('pass2',$event)" [(ngModel)]="password['pass2']" [valid]="passvalid['pass2']" id="floatingInput" placeholder="New Password confirm" />
<label cLabel for="floatingInput">New Password confirm</label>
</div>
<code *ngIf="error"><i class="fa-solid fa-triangle-exclamation"></i><small> {{error}}</small></code>
</c-modal-body>
<c-modal-footer>
<button (click)="submit()" cButton color="primary">submit</button>
<button [cModalToggle]="UserProfileModal.id" cButton color="secondary">
Close
</button>
</c-modal-footer>
</c-modal>

View file

@ -0,0 +1,7 @@
:host {
ng-scrollbar {
--scrollbar-thumb-color: var(--cui-border-color, #999);
--scrollbar-track-color: var(--cui-body-color, #fff);
--scrollbar-hover-size: calc(var(--scrollbar-size) * 1.5);
}
}

View file

@ -0,0 +1,125 @@
import { Component, OnInit } from '@angular/core';
import { Router, NavigationEnd } from "@angular/router";
import { loginChecker } from '../../providers/login_checker';
import { User } from '../../providers/mikrowizard/user';
import { navItems } from './_nav';
import { dataProvider } from '../../providers/mikrowizard/data';
import { version } from 'os';
@Component({
selector: 'app-dashboard',
templateUrl: './default-layout.component.html',
styleUrls: ['./default-layout.component.scss'],
})
export class DefaultLayoutComponent implements OnInit {
public navItems = navItems;
public current_user: User;
public uid: number;
public uname: string;
public fname: string;
public lname: string;
public UserProfileModalVisible:boolean;
public error:any=false;
public password:any={
'cupass':'',
'pass1':'',
'pass2':''
};
public passvalid:any={
'cupass':false,
'pass1':false,
'pass2':false
};
version=require('../../../../package.json').version;
constructor(
private router: Router,
private login_checker: loginChecker,
private data_provider: dataProvider,
) {
var _self = this;
var session_info: string = localStorage.getItem('current_user') || "[]";
this.current_user = JSON.parse(session_info);
this.router.events.subscribe((ev) => {
if (ev instanceof NavigationEnd) {
if (!this.login_checker.isLoggedIn()) {
setTimeout(function () {
_self.router.navigate(['login']);
}, 100);
}
}
});
}
password_changed(variable:string,value:any){
var _self=this;
this.password[variable]=value;
console.dir(this.password['pass1']);
console.dir(this.password['pass2']);
if(this.password['pass1']==this.password['pass2']){
_self.passvalid['pass2']=true;
}
else{
_self.passvalid['pass2']=false;
}
}
show_user_modal(){
this.UserProfileModalVisible = true;
}
submit(){
var _self=this;
if(!_self.passvalid['pass2']){
return;
}
this.data_provider.change_password(this.password['cupass'], this.password['pass1']).then(res => {
if(res['status']=='success'){
_self.logout();
setTimeout(function () {
_self.router.navigate(['login']);
}, 100);
}
else{
_self.error=res['err'];
}
},
(err) => {
console.dir(err);
}
);
}
get_user_info() {
var _self = this;
this.uid = this.current_user.partner_id;
this.uname = this.current_user.name;
this.fname = this.current_user.firstname;
this.lname = this.current_user.lastname;
}
logout() {
this.data_provider.logout();
}
ngOnInit(): void {
var _self = this;
this.get_user_info();
_self.data_provider.get_front_version().then((res:any) => {
console.log("ressssssssssssssssss");
console.dir(res['version']);
console.dir(this.version);
if(res['version']!=this.version){
console.dir("New version is available. Please refresh the page.");
window.location.href = window.location.href.replace(/#.*$/, '');
}
});
}
}

View file

@ -0,0 +1,3 @@
export * from './default-footer/default-footer.component';
export * from './default-header/default-header.component';
export * from './default-layout.component';

View file

@ -0,0 +1 @@
export * from './default-layout';

View file

@ -0,0 +1,281 @@
import {
cibCcAmex,
cibCcApplePay,
cibCcMastercard,
cibCcPaypal,
cibCcStripe,
cibCcVisa,
cibFacebook,
cibGoogle,
cibLinkedin,
cibSkype,
cibTwitter,
cifBr,
cifEs,
cifFr,
cifIn,
cifPl,
cifUs,
cilAlignCenter,
cilAlignLeft,
cilAlignRight,
cilApplicationsSettings,
cilArrowBottom,
cilArrowRight,
cilArrowTop,
cilBasket,
cilBell,
cilBold,
cilBookmark,
cilCalculator,
cilCalendar,
cilChart,
cilChartPie,
cilCheck,
cilChevronLeft,
cilChevronRight,
cilCloudDownload,
cilCode,
cilCommentSquare,
cilCreditCard,
cilCursor,
cilDescription,
cilDollar,
cilDrop,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilFile,
cilHome,
cilInbox,
cilIndentDecrease,
cilIndentIncrease,
cilItalic,
cilJustifyCenter,
cilLayers,
cilList,
cilListNumbered,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMap,
cilMediaPlay,
cilMenu,
cilMoon,
cilNotes,
cilOptions,
cilPaperclip,
cilPaperPlane,
cilPen,
cilPencil,
cilPeople,
cilPrint,
cilPuzzle,
cilReportSlash,
cilSave,
cilSettings,
cilShare,
cilShareAll,
cilShareBoxed,
cilSpeech,
cilSpeedometer,
cilSpreadsheet,
cilStar,
cilSun,
cilTags,
cilTask,
cilTrash,
cilUnderline,
cilUser,
cilUserFemale,
cilUserFollow,
cilUserUnfollow,
cilExitToApp
} from '@coreui/icons';
export const iconSubset = {
cibCcAmex,
cibCcApplePay,
cibCcMastercard,
cibCcPaypal,
cibCcStripe,
cibCcVisa,
cibFacebook,
cibGoogle,
cibLinkedin,
cibSkype,
cibTwitter,
cifBr,
cifEs,
cifFr,
cifIn,
cifPl,
cifUs,
cilAlignCenter,
cilAlignLeft,
cilAlignRight,
cilApplicationsSettings,
cilArrowBottom,
cilArrowRight,
cilArrowTop,
cilBasket,
cilBell,
cilBold,
cilBookmark,
cilCalculator,
cilCalendar,
cilChart,
cilChartPie,
cilCheck,
cilChevronLeft,
cilChevronRight,
cilCloudDownload,
cilCode,
cilCommentSquare,
cilCreditCard,
cilCursor,
cilDescription,
cilDollar,
cilDrop,
cilEnvelopeClosed,
cilEnvelopeOpen,
cilFile,
cilHome,
cilInbox,
cilIndentDecrease,
cilIndentIncrease,
cilItalic,
cilJustifyCenter,
cilLayers,
cilList,
cilListNumbered,
cilLocationPin,
cilLockLocked,
cilMagnifyingGlass,
cilMap,
cilMediaPlay,
cilMenu,
cilMoon,
cilNotes,
cilOptions,
cilPaperclip,
cilPaperPlane,
cilPen,
cilPencil,
cilPeople,
cilPrint,
cilPuzzle,
cilReportSlash,
cilSave,
cilSettings,
cilShare,
cilShareAll,
cilShareBoxed,
cilSpeech,
cilSpeedometer,
cilSpreadsheet,
cilStar,
cilSun,
cilTags,
cilTask,
cilTrash,
cilUnderline,
cilUser,
cilUserFemale,
cilUserFollow,
cilUserUnfollow,
cilExitToApp
};
export enum IconSubset {
cibCcAmex = 'cibCcAmex',
cibCcApplePay = 'cibCcApplePay',
cibCcMastercard = 'cibCcMastercard',
cibCcPaypal = 'cibCcPaypal',
cibCcStripe = 'cibCcStripe',
cibCcVisa = 'cibCcVisa',
cibFacebook = 'cibFacebook',
cibGoogle = 'cibGoogle',
cibLinkedin = 'cibLinkedin',
cibSkype = 'cibSkype',
cibTwitter = 'cibTwitter',
cifBr = 'cifBr',
cifEs = 'cifEs',
cifFr = 'cifFr',
cifIn = 'cifIn',
cifPl = 'cifPl',
cifUs = 'cifUs',
cilAlignCenter = 'cilAlignCenter',
cilAlignLeft = 'cilAlignLeft',
cilAlignRight = 'cilAlignRight',
cilApplicationsSettings = 'cilApplicationsSettings',
cilArrowBottom = 'cilArrowBottom',
cilArrowRight = 'cilArrowRight',
cilArrowTop = 'cilArrowTop',
cilBasket = 'cilBasket',
cilBell = 'cilBell',
cilBold = 'cilBold',
cilBookmark = 'cilBookmark',
cilCalculator = 'cilCalculator',
cilCalendar = 'cilCalendar',
cilChart = 'cilChart',
cilChartPie = 'cilChartPie',
cilCheck = 'cilCheck',
cilChevronLeft = 'cilChevronLeft',
cilChevronRight = 'cilChevronRight',
cilCloudDownload = 'cilCloudDownload',
cilCode = 'cilCode',
cilCommentSquare = 'cilCommentSquare',
cilCreditCard = 'cilCreditCard',
cilCursor = 'cilCursor',
cilDescription = 'cilDescription',
cilDollar = 'cilDollar',
cilDrop = 'cilDrop',
cilEnvelopeClosed = 'cilEnvelopeClosed',
cilEnvelopeOpen = 'cilEnvelopeOpen',
cilFile = 'cilFile',
cilHome = 'cilHome',
cilInbox = 'cilInbox',
cilIndentDecrease = 'cilIndentDecrease',
cilIndentIncrease = 'cilIndentIncrease',
cilItalic = 'cilItalic',
cilJustifyCenter = 'cilJustifyCenter',
cilLayers = 'cilLayers',
cilList = 'cilList',
cilListNumbered = 'cilListNumbered',
cilLocationPin = 'cilLocationPin',
cilLockLocked = 'cilLockLocked',
cilMagnifyingGlass = 'cilMagnifyingGlass',
cilMap = 'cilMap',
cilMediaPlay = 'cilMediaPlay',
cilMenu = 'cilMenu',
cilMoon = 'cilMoon',
cilNotes = 'cilNotes',
cilOptions = 'cilOptions',
cilPaperclip = 'cilPaperclip',
cilPaperPlane = 'cilPaperPlane',
cilPen = 'cilPen',
cilPencil = 'cilPencil',
cilPeople = 'cilPeople',
cilPrint = 'cilPrint',
cilPuzzle = 'cilPuzzle',
cilReportSlash = 'cilReportSlash',
cilSave = 'cilSave',
cilSettings = 'cilSettings',
cilShare = 'cilShare',
cilShareAll = 'cilShareAll',
cilShareBoxed = 'cilShareBoxed',
cilSpeech = 'cilSpeech',
cilSpeedometer = 'cilSpeedometer',
cilSpreadsheet = 'cilSpreadsheet',
cilStar = 'cilStar',
cilSun = 'cilSun',
cilTags = 'cilTags',
cilTask = 'cilTask',
cilTrash = 'cilTrash',
cilUnderline = 'cilUnderline',
cilUser = 'cilUser',
cilUserFemale = 'cilUserFemale',
cilUserFollow = 'cilUserFollow',
cilUserUnfollow = 'cilUserUnfollow',
cilExitToApp = 'cilExitToApp'
}

View file

@ -0,0 +1,28 @@
import { Injectable } from '@angular/core';
import { dataProvider } from './mikrowizard/data';
@Injectable()
export class loginChecker {
private logged_in: boolean = false;
private pinging: boolean = false;
constructor(private data_provider: dataProvider) {
}
public isLoggedIn(): boolean {
return this.logged_in;
}
load() {
var _self = this;
return this.data_provider.isLoggedIn().then(result => {
_self.logged_in = result;
}).catch(err => {
_self.logged_in = false;
})
}
setStatus(status: boolean): void {
this.logged_in = status;
}
setPinging(ping: boolean): void {
this.pinging = ping;
}
}

View file

@ -0,0 +1,86 @@
import { Injectable } from '@angular/core';
import { AngularFireDatabase } from '@angular/fire/database';
import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFireMessaging } from '@angular/fire/messaging';
import { mergeMapTo } from 'rxjs/operators';
import { take } from 'rxjs/operators';
import { BehaviorSubject } from 'rxjs'
import { dataProvider } from './odoorpchttp/data';
import { ToastrService } from 'ngx-toastr';
@Injectable()
export class MessagingService {
currentMessage = new BehaviorSubject(null);
constructor(
private angularFireDB: AngularFireDatabase,
private angularFireAuth: AngularFireAuth,
private data_provider: dataProvider,
private toastr: ToastrService,
private angularFireMessaging: AngularFireMessaging,
) {
this.angularFireMessaging.messaging.subscribe(
(_messaging) => {
_messaging.onMessage = _messaging.onMessage.bind(_messaging);
_messaging.onTokenRefresh = _messaging.onTokenRefresh.bind(_messaging);
}
)
}
/**
* update token in firebase database
*
* @param userId userId as a key
* @param token token as a value
*/
updateToken(userId, token) {
// we can change this function to request our backend service
this.angularFireAuth.authState.pipe(take(1)).subscribe(
() => {
const data = {};
data[userId] = token
this.angularFireDB.object('fcmTokens/').update(data)
})
}
/**
* request permission for notification from firebase cloud messaging
*
* @param userId userId
*/
requestPermission(userId) {
this.angularFireMessaging.requestToken.subscribe(
(token) => {
this.data_provider.update_FBC_token(token).then(result => {
if(result.result!='success'){
console.error('Unable to write token.');
}
});
this.updateToken(userId, token);
},
(err) => {
console.error('Unable to get permission to notify.', err);
}
);
}
shownotification(payload){
if(typeof(payload) !== 'undefined'){
if(document.visibilityState){
this.toastr.warning(payload.notification.title, payload.notification.body,{
disableTimeOut:true,
});
}
}
}
/**
* hook method when new notification received in foreground
*/
receiveMessage() {
this.angularFireMessaging.messages.subscribe(
(payload) => {
this.shownotification(payload);
this.currentMessage.next(payload);
})
}
}

View file

@ -0,0 +1,455 @@
import { Injectable } from '@angular/core';
// import { MikroWizardrpcProvider } from '../MikroWizardrpc/MikroWizardrpc';
import { MikroWizardProvider } from './provider';
import { User } from './user';
@Injectable()
export class dataProvider {
// public serverUrl: string = "/api";
public serverUrl: string = "";
private db: string = "NothingImportant";
constructor(
// private http: HTTP,
// public MikroWizardRPC: MikroWizardrpcProvider,
public MikroWizardRPC: MikroWizardProvider,
) {
this.MikroWizardRPC.init({
MikroWizard_server: this.serverUrl
});
}
isLoggedIn() {
return this.MikroWizardRPC.isLoggedIn();
}
login(username: string = "", password: string = "", ga: string = "") {
var _self = this;
this.MikroWizardRPC.clearCookeis();
return this.MikroWizardRPC.login(this.db, username, password, ga).then(res => {
if ('uid' in res && res['uid']) {
let usr: User = new User(
res.name,
res.username,
res.partner_id,
res.uid,
res.first_name,
res.last_name,
res.role,
res.perms,
res.tz,
);
// console.dir(JSON.stringify(usr))
localStorage.setItem('current_user', JSON.stringify(usr));
}
return res;
});
}
logout() {
var _self = this;
_self.MikroWizardRPC.clearCookeis();
this.MikroWizardRPC.setNewSession('', '');
localStorage.removeItem('current_user');
return this.MikroWizardRPC.sendJsonRequest("/api/logout", {});
}
////
//// MikroWizard API
////
get_front_version(){
return this.MikroWizardRPC.sendHttpGetRequest("/api/frontver/");
}
change_password(oldpass:string,newpass:string){
var data={
'oldpass':oldpass,
'newpass':newpass
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/change_password", data);
}
dashboard_stats(versioncheck:boolean){
var data={
'versioncheck':versioncheck
}
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/stats", data);
}
dashboard_traffic(delta:string){
var data={
'delta':delta
}
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/traffic", data);
}
get_dev_list(data:any) {
return this.MikroWizardRPC.sendJsonRequest("/api/dev/list", data);
}
get_devgroup_list() {
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/list", {});
}
get_devgroup_members(gid:number) {
var data={
'gid':gid
}
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/members", data);
}
delete_group(id:number){
var data={
'gid':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/delete", data);
}
delete_devices(devids:any){
var data = {
'devids':devids
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/delete", data);
}
get_dev_info(id: number) {
var data={
'devid':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/info", data);
}
get_editform(id: number) {
var data={
'devid':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/get_editform", data);
}
save_editform(data:any){
return this.MikroWizardRPC.sendJsonRequest("/api/dev/save_editform", data);
}
get_dev_sensors(id: number,delta:string="5m",total_type:string="bps") {
var data={
'devid':id,
'delta':delta,
'total':total_type
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/sensors", data);
}
get_dev_ifstat(id: number,delta:string="5m",iface:string="ether1",type:string="bps") {
var data={
'devid':id,
'delta':delta,
'type':type,
'interface':iface
}
return this.MikroWizardRPC.sendJsonRequest("/api/dev/ifstat", data);
}
get_auth_logs(filters:any) {
var data=filters;
return this.MikroWizardRPC.sendJsonRequest("/api/auth/list", data);
}
get_account_logs(filters:any) {
var data=filters;
return this.MikroWizardRPC.sendJsonRequest("/api/account/list", data);
}
get_dev_logs(filters:any) {
var data=filters;
return this.MikroWizardRPC.sendJsonRequest("/api/devlogs/list", data);
}
get_syslog(filters:any) {
var data=filters;
return this.MikroWizardRPC.sendJsonRequest("/api/syslog/list", data);
}
get_details_grouped(devid:number=0){
var data={
'devid':devid
}
return this.MikroWizardRPC.sendJsonRequest("/api/devlogs/details/list", data);
}
scan_devs(type:string,info:any){
var data: any={
'type':type
}
if(type=="ip"){
data = Object.assign(data, info);
}
return this.MikroWizardRPC.sendJsonRequest("/api/scanner/scan", data);
}
get_groups(searchstr:string=""){
var data={
'searchstr':searchstr
}
return this.MikroWizardRPC.sendJsonRequest("/api/search/groups", data);
}
get_devices(searchstr:string=""){
var data={
'searchstr':searchstr
}
return this.MikroWizardRPC.sendJsonRequest("/api/search/devices", data);
}
update_save_group(group:any){
var data={
...group
}
return this.MikroWizardRPC.sendJsonRequest("/api/devgroup/update_save_group", data);
}
get_snippets(name:string,desc:string,content:string,page:number=0,size:number=1000){
var data={
'name':name,
'description':desc,
'content':content,
'page':page,
'size':size
}
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/list", data);
}
save_snippet(data:any){
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/save", {...data});
}
delete_snippet(id:number){
var data={
'id':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/snippet/delete", data);
}
get_user_task_list() {
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/list", {});
}
Add_task(data:any,members:any) {
data['members']=members;
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/create", data);
}
Delete_task(taskid:Number) {
var data={
'taskid':taskid,
}
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/delete", data);
}
Edit_task(data:any,members:any) {
data['members']=members;
return this.MikroWizardRPC.sendJsonRequest("/api/user_tasks/edit", data);
}
get_task_members(taskid:Number) {
var data={
'taskid':taskid,
}
return this.MikroWizardRPC.sendJsonRequest("/api/taskmember/details", data);
}
get_users(page:Number,size:Number,search:string) {
var data={
'page':page,
'size':size,
'search':search
}
return this.MikroWizardRPC.sendJsonRequest("/api/users/list", data);
}
get_perms(page:Number,size:Number,search:string) {
var data={
'page':page,
'size':size,
'search':search
}
return this.MikroWizardRPC.sendJsonRequest("/api/perms/list", data);
}
create_perm(name:string,perms:any) {
var data={
'name':name,
'perms':perms
}
return this.MikroWizardRPC.sendJsonRequest("/api/perms/create", data);
}
edit_perm(id:Number,name:string,perms:any) {
var data = {
'id':id,
'name':name,
'perms':perms
}
return this.MikroWizardRPC.sendJsonRequest("/api/perms/edit", data);
}
delete_perm(id:number){
var data={
'id':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/perms/delete", data);
}
user_perms(uid:string) {
var data = {
'uid':uid,
}
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/list", data);
}
Add_user_perm(uid:Number,permid:Number,devgroupid:Number){
var data = {
'uid':uid,
'pid':permid,
'gid':devgroupid
}
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/create", data);
}
Delete_user_perm(id:number){
var data={
'id':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/userperms/delete", data);
}
edit_user(data:any) {
return this.MikroWizardRPC.sendJsonRequest("/api/user/edit", data);
}
create_user(data:any) {
return this.MikroWizardRPC.sendJsonRequest("/api/user/create", data);
}
delete_user(id:number){
var data={
'uid':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/user/delete", data);
}
check_firmware(devids:any) {
var data = {
'devids':devids
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/check_firmware_update", data);
}
get_firms(page:Number,size:Number,search:any) {
var data = {
'page':page,
'size':size,
'search':search
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/get_firms", data);
}
get_backups(devid:Number=0,page:Number,size:Number,search:any) {
var data = {
'devid':devid,
'page':page,
'size':size,
'search':search
}
return this.MikroWizardRPC.sendJsonRequest("/api/backup/list", data);
}
get_backup(id:number){
var data = {
'id':id
}
return this.MikroWizardRPC.sendJsonRequest("/api/backup/get", data);
}
get_downloadable_firms() {
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/get_downloadable_firms", {});
}
download_firmware_to_repository(version:string){
var data = {
'version':version
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/download_firmware_to_repository", data);
}
save_firmware_setting(updatebehavior:string,firmwaretoinstall:string,firmwaretoinstallv6:string){
var data = {
'updatebehavior':updatebehavior,
'firmwaretoinstall':firmwaretoinstall,
'firmwaretoinstallv6':firmwaretoinstallv6
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/update_firmware_settings", data);
}
update_firmware(devids:string){
var data = {
'devids':devids
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/update_firmware", data);
}
upgrade_firmware(devids:string){
var data = {
'devids':devids
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/upgrade_firmware", data);
}
reboot_devices(devids:string){
var data = {
'devids':devids
}
return this.MikroWizardRPC.sendJsonRequest("/api/firmware/reboot_devices", data);
}
get_settings(){
return this.MikroWizardRPC.sendJsonRequest("/api/sysconfig/get_all", {});
}
save_sys_setting(data:any){
return this.MikroWizardRPC.sendJsonRequest("/api/sysconfig/save_all", data);
}
////
//// End api funcs
////
setupSession(context: any, session: any) {
this.MikroWizardRPC.clearCookeis();
this.MikroWizardRPC.setNewSession(context, session);
}
checkSessionExpired(error: any) {
console.log(error);
if ('title' in error && error.title == "session_expired")
this.logout();
return Promise.reject(error.message || error);
}
setSession(context: any, session_id: any) {
this.MikroWizardRPC.setNewSession(context, session_id);
}
getSessionInfo() {
return this.MikroWizardRPC.getSessionInfo();
}
getFullUrl(url: any) {
return this.serverUrl + url;
}
}

View file

@ -0,0 +1,209 @@
import { Injectable, Inject } from '@angular/core';
import { HttpClient,HttpResponse } from '@angular/common/http';
class Cookies { // cookies doesn't work with Android default browser / Ionic
private session_id: string = "";
delete_sessionId() {
this.session_id = "";
document.cookie = "";
}
get_sessionId() {
return document
.cookie.split("; ")
.filter(x => { return x.indexOf("session_id") === 0; })
.map(x => { return x.split("=")[1]; })
.pop() || this.session_id || "";
}
set_sessionId(val: string) {
// document.cookie = `session_id=${val}`;
// this.session_id = val;
}
}
@Injectable()
export class MikroWizardProvider {
private MikroWizard_server: string;
private http_auth: string;
private cookies: Cookies;
private uniq_id_counter: number = 0;
private shouldManageSessionId: boolean = false; // try without first
private context: Object = {"lang": "en_US"};
private headers: any;
constructor(private http: HttpClient) {
this.cookies = new Cookies();
}
private buildRequest(url: string, params: any) {
this.uniq_id_counter += 1;
if (this.shouldManageSessionId) {
params.session_id = this.cookies.get_sessionId();
}
this.headers = {
"Content-Type": "application/json",
"Session-Id": this.cookies.get_sessionId(),
"Authorization": "Basic " + btoa(`${this.http_auth}`)
};
return params;
}
private handleMikroWizardErrors(response: any) {
//response = JSON.parse(response.data);
if (!response.error) {
if (typeof response.result === 'string' || response.result instanceof String)
return JSON.parse(response.result);
return response.result;
}
let error = response.error;
let errorObj = {
title: " ",
message: "",
fullTrace: error
};
return Promise.reject(error);
}
private handleRequestErrors(response: any) {
if (!response.error) {
if (typeof response.result === 'string' || response.result instanceof String)
return JSON.parse(response.result);
return response.result;
}
let error = response.error;
let errorObj = {
title: " ",
message: "",
fullTrace: error
};
return Promise.reject(error);
}
private handleHttpErrors(error: any) {
try{
console.log(error, Object.getOwnPropertyNames(error));
}
catch(e){
console.log(error);
}
return Promise.reject(error.message || error);
}
public init(configs: any) {
this.MikroWizard_server = configs.MikroWizard_server;
this.http_auth = configs.http_auth || null;
}
public setMikroWizardServer(MikroWizard_server: string) {
this.MikroWizard_server = MikroWizard_server;
}
public setHttpAuth(http_auth: string) {
this.http_auth = http_auth;
}
public sendRequestauth(url: string, params: Object){
let body = this.buildRequest(url, params);
console.dir(body);
return this.http.post(this.MikroWizard_server + url, body, {observe: "response",headers: this.headers,withCredentials:true});
}
public sendRequest(url: string, params: Object): Promise<any> {
let body = this.buildRequest(url, params);
return this.http.post(this.MikroWizard_server + url, body, {headers: this.headers,withCredentials:true})
.toPromise()
.then((response: any) => this.handleMikroWizardErrors(response))
.catch((response: any) => this.handleHttpErrors(response));
}
public sendJsonRequest(url: string, params: Object) {
let headers = {
"Content-Type": "application/json",
};
return this.http.post(url, params,
{headers:this.headers,withCredentials:true}
).toPromise()
.then(this.handleRequestErrors)
.catch(this.handleHttpErrors);
}
public sendHttpRequest(url: string, params: any) {
let headers = {
"Content-Type": "application/x-www-form-urlencoded",
};
return this.http.post(this.MikroWizard_server + url, params,
{headers:headers,withCredentials:true}
).toPromise()
.then(this.handleRequestErrors)
.catch(this.handleHttpErrors);
}
public sendHttpGetRequest(url: string) {
let headers = {
"Content-Type": "application/x-www-form-urlencoded",
};
return this.http.get( url,
{ responseType: 'json' }
).toPromise()
}
public getServerInfo() {
return this.sendRequest("/api/version_info", {});
}
public getSessionInfo() {
return this.sendRequest("/api/me", {});
}
//Set-Cookie
public login(db: string, login: string, password: string, ga: string) {
let params = {
username : login,
password : password,
// token: token,
ga: ga
};
let $this = this;
return this.sendRequest("/api/login", params);
}
public isLoggedIn() {
return this.getSessionInfo().then(function(result: any) {
// console.dir("result");
console.dir(result);
// return true;
if ( "uid" in result === false ) return false;
else return true;
});
}
public clearCookeis() {
this.cookies = new Cookies();
}
public logout() {
this.clearCookeis();
return Promise.resolve();
}
public getUserContext(context: any) {
localStorage.setItem("user_context", JSON.stringify(context));
}
public getContext() {
return this.context;
}
public setNewSession(user_context: any, session_id: any) {
this.context = user_context;
localStorage.setItem("user_context", JSON.stringify(this.context));
}
}

View file

@ -0,0 +1,21 @@
export class User {
name: string;
username: string;
firstname: string;
lastname: string;
partner_id: number;
id: number;
role: string;
perms:any;
tz:string;
constructor(name: any, username: any, partner_id: any, user_id: any,firstname: any,lastname: any,role: any,perms:any,tz:string) { this.name = name;
this.username = username;
this.partner_id = partner_id;
this.id = user_id;
this.firstname = firstname;
this.lastname = lastname;
this.role = role;
this.perms = perms;
this.tz=tz;
}
}

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

After

Width:  |  Height:  |  Size: 231 B

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