diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts index 806ed24..3c4186a 100644 --- a/src/app/app-routing.module.ts +++ b/src/app/app-routing.module.ts @@ -84,6 +84,11 @@ const routes: Routes = [ loadChildren: () => import('./views/user_tasks/user_tasks.module').then((m) => m.UserTasksModule) }, + { + path: 'cloner', + loadChildren: () => + import('./views/cloner/cloner.module').then((m) => m.ClonerModule) + }, { path: 'snippets', loadChildren: () => diff --git a/src/app/containers/default-layout/_nav.ts b/src/app/containers/default-layout/_nav.ts index 6339791..d313617 100644 --- a/src/app/containers/default-layout/_nav.ts +++ b/src/app/containers/default-layout/_nav.ts @@ -60,10 +60,17 @@ export const navItems: INavData[] = [ icon: 'fa-solid fa-database' }, { - name: 'snippets', + name: 'Snippets', url: '/snippets', icon: 'fa-solid fa-code' }, + { + name: 'Sync and Cloner', + url: '/cloner', + icon: 'fa-solid fa-rotate', + attributes: { 'pro':true } + + }, { name: 'Password Vault', url: '/vault', diff --git a/src/app/providers/mikrowizard/data.ts b/src/app/providers/mikrowizard/data.ts index b80fbb0..ba6c8a4 100644 --- a/src/app/providers/mikrowizard/data.ts +++ b/src/app/providers/mikrowizard/data.ts @@ -172,6 +172,12 @@ export class dataProvider { } return this.MikroWizardRPC.sendJsonRequest("/api/dev/radio/sensors", data); } + get_dev_dhcp_info(id: number){ + var data={ + 'devid':id, + } + return this.MikroWizardRPC.sendJsonRequest("/api/dev/dhcp-server/get", data); + } get_dev_ifstat(id: number,delta:string="5m",iface:string="ether1",type:string="bps") { var data={ 'devid':id, @@ -553,6 +559,48 @@ export class dataProvider { } return this.MikroWizardRPC.sendJsonRequest("/api/sysconfig/apply_update", data); } + + + get_cloner_list() { + return this.MikroWizardRPC.sendJsonRequest("/api/cloner/list", {}); + } + + Add_cloner(data:any,members:any) { + data['members']=members; + return this.MikroWizardRPC.sendJsonRequest("/api/cloner/create", data); + } + + Delete_cloner(clonerid:number) { + var data={ + 'clonerid':clonerid, + } + return this.MikroWizardRPC.sendJsonRequest("/api/cloner/delete", data); + } + + Edit_cloner(data:any,members:any) { + data['members']=members; + return this.MikroWizardRPC.sendJsonRequest("/api/cloner/edit", data); + } + + get_cloner_members(clonerid:number) { + var data={ + 'clonerid':clonerid, + } + return this.MikroWizardRPC.sendJsonRequest("/api/cloner/memberdetails", data); + } + killSession(devid:number,item:any){ + var data={ + 'devid':devid, + 'item':item + } + return this.MikroWizardRPC.sendJsonRequest("/api/dev/kill_session", data); + } + getDhcpHistory(item:any){ + var data={ + 'item':item + } + return this.MikroWizardRPC.sendJsonRequest("/api/dhcp-history/get", data); + } //// //// End api funcs //// diff --git a/src/app/views/acc_log/acc.component.html b/src/app/views/acc_log/acc.component.html index 159b290..3b1b9b8 100644 --- a/src/app/views/acc_log/acc.component.html +++ b/src/app/views/acc_log/acc.component.html @@ -1,10 +1,22 @@ - + - - Accunting Logs + +
Accunting Logs + + + +
+ Filtered Result For Device ID + {{devid}} + + Showing last 24 hours logs by default. Use filters to modify the date and time. +
+ +
+
+ + + + + {{value}} + + + + + {{value}} + + + + + {{value}} + + + + + + + + + + + +
+
+
+ + + +
Editing Cloner {{SelectedCloner['name']}}
+
Adding new task
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
{{ section.title }}
+
+
+ + +
{{ command }}
+
+ + +
+
+
+
+
+
+
+
+
+ +
Peers :
+ + + + +   {{value}} + + + + {{value}} + + + + + + + + + +
+ +
+ + + + + +
+ + + + +
Editing Group
+ +
+ + +
Group Members :
+ + + +   {{value}} + + + + {{value}} + + + + + {{value}} + + + +
+
+
+
+ + + + + +
+ + + + +
Confirm delete {{ SelectedCloner['name'] }}
+ +
+ + Are you sure that You want to delete following task ? +
+
+ + + + + + + + + + + + + +
Taks name : {{ SelectedCloner['name'] }}
Description : {{ SelectedCloner['description'] }}
Cron exec : {{ SelectedCloner['desc_cron'] }}
+
+ + + + +
+ + \ No newline at end of file diff --git a/src/app/views/cloner/cloner.component.ts b/src/app/views/cloner/cloner.component.ts new file mode 100644 index 0000000..70a8a90 --- /dev/null +++ b/src/app/views/cloner/cloner.component.ts @@ -0,0 +1,458 @@ +import { Component, OnInit, OnDestroy, ViewChildren ,QueryList } from "@angular/core"; +import { dataProvider } from "../../providers/mikrowizard/data"; +import { Router } from "@angular/router"; +import { loginChecker } from "../../providers/login_checker"; +import { + GuiSelectedRow, + GuiSearching, + GuiInfoPanel, + GuiColumn, + GuiColumnMenu, + GuiPaging, + GuiPagingDisplay, + GuiRowSelectionMode, + GuiRowSelection, + GuiRowSelectionType, +} from "@generic-ui/ngx-grid"; +import { NgxSuperSelectOptions } from "ngx-super-select"; +import { _getFocusedElementPierceShadowDom } from "@angular/cdk/platform"; + + +import { ToasterComponent } from "@coreui/angular"; +import { AppToastComponent } from "../toast-simple/toast.component"; + +@Component({ + templateUrl: "cloner.component.html", + styleUrls: ["cloner.scss"], + +}) +export class ClonerComponent implements OnInit { + public uid: number; + public uname: string; + public ispro: boolean = 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.ispro = res['ISPRO'] + 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; + + public source: Array = []; + public columns: Array = []; + public loading: boolean = true; + public rows: any = []; + public SelectedCloner: any = {}; + public SelectedClonerItems: any = ""; + public EditClonerModalVisible: boolean = false; + public DeleteConfirmModalVisible: boolean = false; + public Members: any = ""; + public SelectedMembers: any = []; + public NewMemberModalVisible: boolean = false; + public availbleMembers: any = []; + public NewMemberRows: any = []; + public SelectedNewMemberRows: any; + public master: number = 0; + public active_commands:any=[]; + public tabs:any=[ + { + "name": "Network", + "sections": [ + { + "title": "IP Management", + "commands": [ + "/ip address", + "/ip cloud", + "/ip dhcp-server", + "/ip dns", + "/ip pool", + "/ip route", + "/ip vrf" + ] + }, + { + "title": "IP Services", + "commands": [ + "/ip service" + ] + } + ] + }, + { + "name": "Security", + "sections": [ + { + "title": "Firewall", + "commands": [ + "/ip firewall address-list", + "/ip firewall connection", + "/ip firewall layer7-protocol", + "/ip firewall nat", + "/ip firewall service-port", + "/ip firewall calea", + "/ip firewall filter", + "/ip firewall mangle", + "/ip firewall raw" + ] + }, + { + "title": "IPSec", + "commands": [ + "/ip ipsec identity", + "/ip ipsec key", + "/ip ipsec peer", + "/ip ipsec profile", + "/ip ipsec settings", + "/ip ipsec statistics", + "/ip ipsec proposal", + "/ip ipsec policy", + "/ip ipsec mode-config", + "/ip ipsec active-peers", + "/ip ipsec installed-sa" + ] + } + ] + }, + { + "name": "System", + "sections": [ + { + "title": "Scripts & Scheduling", + "commands": [ + "/system script", + "/system scheduler" + ] + }, + { + "title": "Time Management", + "commands": [ + "/system ntp client servers", + "/system ntp client", + "/system ntp server", + "/system clock" + ] + }, + { + "title": "RADIUS", + "commands": [ + "/radius" + ] + } + ] + }, + { + "name": "MPLS", + "sections": [ + { + "title": "MPLS Configuration", + "commands": [ + "/mpls forwarding-table", + "/mpls interface", + "/mpls ldp", + "/mpls settings", + "/mpls traffic-eng" + ] + }, + { + "title": "VPLS", + "commands": [ + "/interface vpls" + ] + } + ] + } + ]; + + public sorting = { + enabled: true, + multiSorting: true, + }; + searching: GuiSearching = { + enabled: true, + placeholder: "Search Devices", + }; + + options: Partial = { + selectionMode: "single", + actionsEnabled: false, + displayExpr: "name", + valueExpr: "id", + placeholder: "Snippet", + searchEnabled: true, + enableDarkMode: false, + }; + + public paging: GuiPaging = { + enabled: true, + page: 1, + pageSize: 10, + pageSizes: [5, 10, 25, 50], + display: GuiPagingDisplay.ADVANCED, + }; + + public columnMenu: GuiColumnMenu = { + enabled: true, + sort: true, + columnsManager: true, + }; + + toasterForm = { + autohide: true, + delay: 3000, + position: "fixed", + fade: true, + closeButton: true, + }; + + public infoPanel: GuiInfoPanel = { + enabled: true, + infoDialog: false, + columnsManager: true, + schemaManager: true, + }; + + public rowSelection: boolean | GuiRowSelection = { + enabled: true, + type: GuiRowSelectionType.CHECKBOX, + mode: GuiRowSelectionMode.MULTIPLE, + }; + activate_command(command:string){ + // add to active_commands if it not added before + if(!this.active_commands.includes(command)){ + this.active_commands.push(command); + } + else{ + this.active_commands=this.active_commands.filter((x:any)=>x!=command); + } + } + 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; + } + show_new_member_form() { + this.NewMemberModalVisible = true; + var _self = this; + _self.availbleMembers = []; + this.SelectedNewMemberRows = []; + this.NewMemberRows = []; + + var data = { + group_id: false, + search: false, + page: false, + size: 10000, + }; + + if (this.SelectedCloner["pair_type"] == "devices") + _self.data_provider.get_dev_list(data).then((res) => { + _self.availbleMembers = res.filter( + (x: any) => !_self.SelectedClonerItems.includes(x.id) + ); + _self.NewMemberModalVisible = true; + }); + else + _self.data_provider.get_devgroup_list().then((res) => { + _self.availbleMembers = res.filter( + (x: any) => !_self.SelectedClonerItems.includes(x.id) + ); + _self.NewMemberModalVisible = true; + }); + } + + ngOnInit(): void { + this.initGridTable(); + } + + submit(action: string) { + var _self = this; + if(_self.master==0 && _self.SelectedCloner['direction']=='oneway'){ + _self.show_toast( + "Error", + "Master device is not selected", + "danger" + ); + return; + } + if(_self.SelectedCloner['direction']=='twoway' && _self.SelectedCloner['pair_type']=='groups'){ + _self.show_toast( + "Error", + "Using Groups is only allowed with Master Mode", + "danger" + ); + return; + } + if (_self.master!=0 && _self.SelectedCloner['direction']=='oneway'){ + _self.SelectedCloner["masterid"]=_self.master; + } + _self.SelectedCloner["active_commands"]=_self.active_commands; + if (action == "add") { + this.data_provider + .Add_cloner(_self.SelectedCloner, _self.SelectedClonerItems) + .then((res) => { + _self.initGridTable(); + }); + } else { + this.data_provider + .Edit_cloner(_self.SelectedCloner, _self.SelectedClonerItems) + .then((res) => { + _self.initGridTable(); + }); + } + this.EditClonerModalVisible = false; + } + + onSelectedRowsNewMembers(rows: Array): void { + this.NewMemberRows = rows; + this.SelectedNewMemberRows = rows.map((m: GuiSelectedRow) => m.source); + } + + add_new_members() { + var _self = this; + _self.SelectedMembers = [ + ...new Set(_self.SelectedMembers.concat(_self.SelectedNewMemberRows)), + ]; + + _self.SelectedClonerItems = _self.SelectedMembers.map((x: any) => { + return x.id; + }); + + this.NewMemberModalVisible = false; + } + + set_master(id:number){ + var _self=this; + this.master=id; + // sort SelectedMembers and put master on top + this.SelectedMembers= + [ + ...new Set( + this.SelectedMembers.sort((a:any,b:any)=>{ + if(a.id==_self.master) return -1; + if(b.id==_self.master) return 1; + return 0; + }) + + ), + ]; + } + + + editAddCloner(item: any, action: string) { + if (action == "showadd") { + this.SelectedCloner = { + id: 0, + name: "", + description: "", + pair_type: "devices", + live_mode: false, + schedule: false, + cron: "", + desc_cron: "", + direction: "oneway", + members: "", + action: "add", + }; + this.SelectedMembers = []; + this.SelectedClonerItems = []; + this.EditClonerModalVisible = true; + return; + } + + var _self = this; + this.SelectedCloner = { ...item }; + this.active_commands=item['active_commands']?JSON.parse(item['active_commands']):[]; + if (action != "select_change" ) { + this.SelectedCloner["action"] = "edit"; + this.data_provider.get_cloner_members(_self.SelectedCloner.id).then((res) => { + _self.SelectedMembers = res; + if(_self.SelectedCloner["master"] && _self.SelectedCloner['direction']=='oneway'){ + _self.set_master(_self.SelectedCloner["master"]); + } + _self.EditClonerModalVisible = true; + _self.SelectedClonerItems = res.map((x: any) => { + return x.id; + }); + }); + } else { + _self.SelectedMembers = []; + this.SelectedClonerItems = []; + } + } + + + in_active_commands(command:string){ + return this.active_commands.includes(command); + } + remove_member(item: any) { + var _self = this; + _self.SelectedMembers = _self.SelectedMembers.filter( + (x: any) => x.id != item.id + ); + _self.SelectedClonerItems = _self.SelectedMembers.map((x: any) => { + return x.id; + }); + } + + 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.SelectedCloner = { ...item }; + this.DeleteConfirmModalVisible = true; + } else { + var _self = this; + this.data_provider.Delete_cloner(_self.SelectedCloner["id"]).then((res) => { + _self.initGridTable(); + _self.DeleteConfirmModalVisible = false; + }); + } + } + + form_changed() { + this.editAddCloner(this.SelectedCloner, "select_change"); + } + + logger(item: any) { + console.dir(item); + } + + initGridTable(): void { + var _self = this; + this.data_provider.get_cloner_list().then((res) => { + _self.source = res.map((x: any) => { + return x; + }); + _self.loading = false; + }); + } +} diff --git a/src/app/views/cloner/cloner.module.ts b/src/app/views/cloner/cloner.module.ts new file mode 100644 index 0000000..d42f20e --- /dev/null +++ b/src/app/views/cloner/cloner.module.ts @@ -0,0 +1,44 @@ +import { NgModule } from "@angular/core"; +import { CommonModule } from "@angular/common"; +import { FormsModule,ReactiveFormsModule } from "@angular/forms"; + +import { + ButtonModule, + CardModule, + FormModule, + GridModule, + ModalModule, + ButtonGroupModule, + ToastModule, + TooltipModule, + NavModule, + TabsModule, +} from "@coreui/angular"; +import { ClonerRoutingModule } from "./cloner-routing.module"; +import { ClonerComponent } from "./cloner.component"; +import { GuiGridModule } from "@generic-ui/ngx-grid"; + +import { NgxSuperSelectModule} from "ngx-super-select"; + +@NgModule({ + imports: [ + ClonerRoutingModule, + CardModule, + CommonModule, + GridModule, + FormModule, + ButtonModule, + ButtonGroupModule, + GuiGridModule, + ModalModule, + ReactiveFormsModule, + FormsModule, + NgxSuperSelectModule, + ToastModule, + TooltipModule, + NavModule, + TabsModule, + ], + declarations: [ClonerComponent], +}) +export class ClonerModule {} diff --git a/src/app/views/cloner/cloner.scss b/src/app/views/cloner/cloner.scss new file mode 100644 index 0000000..a502ea6 --- /dev/null +++ b/src/app/views/cloner/cloner.scss @@ -0,0 +1,133 @@ + +.nav-underline { + border-bottom: 2px solid var(--cui-nav-underline-border-color, #c4c9d0) +} + +.nav-underline .nav-item { + margin-bottom: -2px; + cursor: pointer; +} + +.nav-underline .nav-link { + color: var(--cui-nav-underline-link-color, #768192); + border-style: none none solid!important; + border-width:2px; + position:relative; + bottom:-1px; + cursor: pointer; + +} + +.nav-underline .nav-link:hover,.nav-underline .nav-link:focus { + border-color: var(--cui-nav-underline-link-active-border-color, #321fdb) +} + +.nav-underline .nav-link.active,.nav-underline .show>.nav-link { + color: var(--cui-nav-underline-link-active-color, #321fdb); + background: transparent; + border-color: var(--cui-nav-underline-link-active-border-color, #321fdb) +} + + + + + + +.custom-control-label::before, .custom-control-label::after { + top: 0.1rem; + width: 2rem; + height: 1rem; + } + + .custom-control-input:checked ~ .custom-control-label::before { + color: #fff; + border-color: #3498db; + background-color: #3498db; + } + + .custom-control-input:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 0.2rem rgba(52, 152, 219, 0.25); + } + + h5.cloner-sections { + color: #3498db; + margin-bottom: 5px; + font-size: 15px; + font-weight: 600; } + + .nav-link { + color: #333; + } + + .nav-link.active { + color: #3498db; + border-bottom: 2px solid #3498db; + } + + .command-sections c-card-body{ + display: flex!important; + justify-content: space-between!important; + padding:5px!important; + align-items: center!important; + justify-content: space-between!important; + border-radius: 4px; +} + +.command-sections c-card-body h6{ + margin: 0!important; + font-size: 12px!important; + color: var(--primary-color); + white-space: nowrap!important; + overflow: hidden!important; + text-overflow: ellipsis!important; + width: 80%!important; + font-weight: bold; + +} +.command-sections c-card{ + border: 1px solid #e0e0e0!important;; + border-radius: 4px!important;; +} + + /* Checkbox Styling */ + .custom-switch { + position: relative; + width: 40px; + height: 20px; + } + + .custom-switch input { + display: none; + } + + .custom-control-label { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border-radius: 20px; + background: #ccc; + cursor: pointer; + transition: all 0.3s ease; + } + + .custom-control-label::after { + content: ''; + position: absolute; + left: 2px; + top: 2px; + width: 16px; + height: 16px; + background: #fff; + border-radius: 50%; + transition: all 0.3s ease; + } + + .custom-switch input:checked + .custom-control-label { + background: #3498db; + } + + .custom-switch input:checked + .custom-control-label::after { + left: calc(100% - 18px); + } \ No newline at end of file diff --git a/src/app/views/dashboard/dashboard.component.html b/src/app/views/dashboard/dashboard.component.html index e454cf9..af6b2e9 100644 --- a/src/app/views/dashboard/dashboard.component.html +++ b/src/app/views/dashboard/dashboard.component.html @@ -139,9 +139,8 @@ Copy - Not Registred - Learn how to register and get automatic - updates! + Not Registred + License Validation failed
@@ -153,7 +152,7 @@
Unable connect to server/Check server internet connection
-
+
Serial: Update availble
+

License User name is not set in settings read more!

+

Serial number not submitedread more!

+ - - - - - - - - + + + + +

+ {{ devdata["name"] }} ( {{ devdata["ip"] }} ) +

+
+ +
+
+
- {{value}} - {{item['default-name']}} -
-
+ + - - - - {{value}} - - - - - -
{{convert_bw_human(value,'rx')}}
-
-
- - - - {{convert_bw_human(value,'tx')}} - - - - - - curr:{{value}}
- max : {{item['max-l2mtu']}} -
-
- - - - {{convert_bw_human(value,'rx')}} - - - - - - - {{convert_bw_human(value,'tx')}} - - - - - - {{value}} - - - - - - {{value}} - - - - - {{value}} - - - - - - - -
-
-
-
-
-
- - - - -
Radio data
- -
{{raddata.key}}
- + +
Loading...
+ + + + + + + + + + + + + + + + + + + + - - - - - - - - - - -
{{d.key}}{{d.value}}
+ + + + + + - + + + + + + + +
+ + + + + + + + + + {{ value }} - {{ item["default-name"] }} + + - - - - - - - - - -
{{d.key}}{{d.value}}
-
- - - - - - - - - - -
{{d.key}}{{d.value}}
-
- - - - - - - - - - -
{{d.key}}{{d.value}}
-
+ + + {{ value }} + + + + +
{{ convert_bw_human(value, "rx") }}
+
+
+ + + {{ convert_bw_human(value, "tx") }} + + + + + curr:{{ value }}
+ max : {{ item["max-l2mtu"] }} +
+
+ + + {{ convert_bw_human(value, "rx") }} + + + + + {{ convert_bw_human(value, "tx") }} + + + + + {{ value }} + + + + + {{ value }} + + + + + {{ value }} + + + + + + + + +
+
+
+
- - - - - - - - - -
Strength at rates - {{st}} -
-
+ + + + + + +
Radio data
+
+ +
{{ raddata.key }}
+ + + + + + + + + + + + +
+ {{ d.key }} + {{ d.value }}
+
+ + + + + + + + + + +
+ {{ d.key }} + {{ d.value }}
+
+ + + + + + + + + + +
+ {{ d.key }} + {{ d.value }}
+
+ + + + + + + + + + +
{{ d.key }}{{ d.value }}
+
+
+ + + + + + + + + +
+ Strength at rates + + {{ st }} +
+
+
+
+
+
- - +
+ + + + + + + + + + + + + + +
- -
{{interface_rate['name']}}
+
{{ interface_rate["name"] }}
- - + + + + + + + + + + + + + +
History for {{current_dhcp['mac-address']}}
+ +
+ + + + +
{{value}}
+
+
+ + + {{value}} + + + + + {{value}} + + + + + {{item.name}} ({{value}}) + + +
+
+ + + +
\ No newline at end of file diff --git a/src/app/views/device_detail/dhcp-info/dhcp-info.component.scss b/src/app/views/device_detail/dhcp-info/dhcp-info.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/views/device_detail/dhcp-info/dhcp-info.component.ts b/src/app/views/device_detail/dhcp-info/dhcp-info.component.ts new file mode 100644 index 0000000..31d21c9 --- /dev/null +++ b/src/app/views/device_detail/dhcp-info/dhcp-info.component.ts @@ -0,0 +1,47 @@ +import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component,Input } from '@angular/core'; +import { dataProvider } from "../../../providers/mikrowizard/data"; +import { formatInTimeZone } from "date-fns-tz"; + +@Component({ + selector: 'app-dhcp-info', + templateUrl: './dhcp-info.component.html', + styleUrls: ['./dhcp-info.component.scss'], + changeDetection: ChangeDetectionStrategy.Default +}) +export class DhcpInfoComponent implements AfterContentInit { + @Input() dhcp_server_data: any; + @Input() small_screen: boolean=false; + @Input() columnMenu: any; + @Input() sorting: any; + @Input() searching: any; + @Input() infoPanel: any; + @Input() paging: any; + @Input() rowSelectionMode: any; + @Input() tz: any; + dhcp_history:any; + dhcp_history_modal: boolean = false; + current_dhcp:any; + constructor( + private changeDetectorRef: ChangeDetectorRef, + private data_provider: dataProvider, + ) {} + + show_history(item:any) { + var _self = this; + this.data_provider.getDhcpHistory(item).then((res) => { + _self.current_dhcp = item; + this.dhcp_history = res.map((d: any) => { + d.eventtime = formatInTimeZone( + d.eventtime.split(".")[0] + ".000Z", + _self.tz, + "yyyy-MM-dd HH:mm:ss XXX" + ); + return d; + }); + this.dhcp_history_modal=!this.dhcp_history_modal; + }); + } + ngAfterContentInit(): void { + this.changeDetectorRef.detectChanges(); + } +} diff --git a/src/app/views/device_detail/dhcp-info/dhcp-info.module.ts b/src/app/views/device_detail/dhcp-info/dhcp-info.module.ts new file mode 100644 index 0000000..d493f2a --- /dev/null +++ b/src/app/views/device_detail/dhcp-info/dhcp-info.module.ts @@ -0,0 +1,57 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { + ButtonGroupModule, + ButtonModule, + CardModule, + FormModule, + GridModule, + ProgressModule, + NavbarModule, + AlertModule, + ModalModule, + TableModule, + UtilitiesModule, + BadgeModule, + NavModule, + TabsModule, +} from '@coreui/angular'; +import { ChartjsModule } from '@coreui/angular-chartjs'; + +import { WidgetsModule } from "../../widgets/widgets.module"; + +// import { WidgetsRoutingModule } from './widgets-routing.module'; +import { DhcpInfoComponent } from './dhcp-info.component'; +import { GuiGridModule } from "@generic-ui/ngx-grid"; + +@NgModule({ + declarations: [ + DhcpInfoComponent, + ], + imports: [ + CardModule, + AlertModule, + CommonModule, + GridModule, + ProgressModule, + FormModule, + ButtonModule, + ButtonGroupModule, + ChartjsModule, + WidgetsModule, + NavbarModule, + ModalModule, + GuiGridModule, + TableModule, + UtilitiesModule, + BadgeModule, + NavModule, + TabsModule, + ], + exports: [ + DhcpInfoComponent, + ] +}) +export class DhcpInfoModule { +} diff --git a/src/app/views/device_detail/dhcp-info/dhcp-inforouting.module.ts b/src/app/views/device_detail/dhcp-info/dhcp-inforouting.module.ts new file mode 100644 index 0000000..7216364 --- /dev/null +++ b/src/app/views/device_detail/dhcp-info/dhcp-inforouting.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { DhcpInfoComponent } from './dhcp-info.component'; + +const routes: Routes = [ + { + path: '', + component: DhcpInfoComponent, + data: { + title: 'Widgets' + } + } +]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class DhcpInfoRoutingModule { +} diff --git a/src/app/views/device_detail/ping-status/ping-status-routing.module.ts b/src/app/views/device_detail/ping-status/ping-status-routing.module.ts new file mode 100644 index 0000000..2aa3361 --- /dev/null +++ b/src/app/views/device_detail/ping-status/ping-status-routing.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { PingStatsComponent } from './ping-status.component'; + +const routes: Routes = [ + { + path: '', + component: PingStatsComponent, + data: { + title: 'Widgets' + } + } +]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class PingStatsRoutingModule { +} diff --git a/src/app/views/device_detail/ping-status/ping-status.component.html b/src/app/views/device_detail/ping-status/ping-status.component.html new file mode 100644 index 0000000..10a201c --- /dev/null +++ b/src/app/views/device_detail/ping-status/ping-status.component.html @@ -0,0 +1,42 @@ + + + + +
Ping status
+
+ +
Successful pings : + {{ping['successful_pings']}}
+
| Failed pings : {{ping['failed_pings']}}
+
| Avrage : + {{ping['average_ping_time']}} ms
+ + + + + + + + + + + + + + + + + + + + + +
#HostTimeStatusQualitydetails
{{i+1}}{{item['host']}}{{item['time']}} ms{{item['status']}}{{item['ping_quality']}}
+
+
+
+
\ No newline at end of file diff --git a/src/app/views/device_detail/ping-status/ping-status.component.scss b/src/app/views/device_detail/ping-status/ping-status.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/views/device_detail/ping-status/ping-status.component.ts b/src/app/views/device_detail/ping-status/ping-status.component.ts new file mode 100644 index 0000000..ec2a2b8 --- /dev/null +++ b/src/app/views/device_detail/ping-status/ping-status.component.ts @@ -0,0 +1,19 @@ +import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component,Input } from '@angular/core'; + +@Component({ + selector: 'app-ping-stats', + templateUrl: './ping-status.component.html', + styleUrls: ['./ping-status.component.scss'], + changeDetection: ChangeDetectionStrategy.Default +}) +export class PingStatsComponent implements AfterContentInit { + @Input() ping: any; + constructor( + private changeDetectorRef: ChangeDetectorRef + ) {} + + ngAfterContentInit(): void { + + this.changeDetectorRef.detectChanges(); + } +} diff --git a/src/app/views/device_detail/ping-status/ping-status.module.ts b/src/app/views/device_detail/ping-status/ping-status.module.ts new file mode 100644 index 0000000..cc3b3a0 --- /dev/null +++ b/src/app/views/device_detail/ping-status/ping-status.module.ts @@ -0,0 +1,46 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { + ButtonGroupModule, + ButtonModule, + CardModule, + FormModule, + GridModule, + ProgressModule, + NavbarModule, + ModalModule, + TableModule, + UtilitiesModule, + BadgeModule, + TooltipModule, +} from '@coreui/angular'; + +// import { WidgetsRoutingModule } from './widgets-routing.module'; +import { PingStatsComponent } from './ping-status.component'; + +@NgModule({ + declarations: [ + PingStatsComponent, + ], + imports: [ + CardModule, + CommonModule, + GridModule, + ProgressModule, + FormModule, + ButtonModule, + ButtonGroupModule, + NavbarModule, + ModalModule, + TableModule, + UtilitiesModule, + BadgeModule, + TooltipModule, + ], + exports: [ + PingStatsComponent, + ] +}) +export class PingStatsModule { +} diff --git a/src/app/views/device_detail/radio-data/interface-bw.component.html b/src/app/views/device_detail/radio-data/interface-bw.component.html new file mode 100644 index 0000000..250b2e4 --- /dev/null +++ b/src/app/views/device_detail/radio-data/interface-bw.component.html @@ -0,0 +1,77 @@ + + +
Radio data
+
+ +
{{raddata.key}}
+ + + + + + + + + + + + +
{{d.key}}{{d.value}}
+
+ + + + + + + + + + + +
{{d.key}}{{d.value}}
+
+ + + + + + + + + + +
{{d.key}}{{d.value}}
+
+ + + + + + + + + + +
{{d.key}}{{d.value}}
+
+
+ + + + + + + + + +
+ Strength at rates + {{st}} +
+
+
+
+
\ No newline at end of file diff --git a/src/app/views/device_detail/radio-data/radio-data-routing.module.ts b/src/app/views/device_detail/radio-data/radio-data-routing.module.ts new file mode 100644 index 0000000..53b7f99 --- /dev/null +++ b/src/app/views/device_detail/radio-data/radio-data-routing.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { RouterModule, Routes } from '@angular/router'; +import { RadioDataComponent } from './radio-data.component'; + +const routes: Routes = [ + { + path: '', + component: RadioDataComponent, + data: { + title: 'Widgets' + } + } +]; + + +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule] +}) +export class RadioDataRoutingModule { +} diff --git a/src/app/views/device_detail/radio-data/radio-data.component.scss b/src/app/views/device_detail/radio-data/radio-data.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/src/app/views/device_detail/radio-data/radio-data.component.ts b/src/app/views/device_detail/radio-data/radio-data.component.ts new file mode 100644 index 0000000..ace8e53 --- /dev/null +++ b/src/app/views/device_detail/radio-data/radio-data.component.ts @@ -0,0 +1,24 @@ +import { AfterContentInit, ChangeDetectionStrategy, ChangeDetectorRef, Component,Input } from '@angular/core'; + +@Component({ + selector: 'app-iradio-data', + templateUrl: './radio-data.component.html', + styleUrls: ['./radio-data.component.scss'], + changeDetection: ChangeDetectionStrategy.Default +}) +export class RadioDataComponent implements AfterContentInit { + @Input() raddata: any; + constructor( + private changeDetectorRef: ChangeDetectorRef + ) {} + + objectlen(object:any){ + return Object.keys(object).length; + } + strangth_at_rate_extract(data:string){ + return data.split(','); + } + ngAfterContentInit(): void { + this.changeDetectorRef.detectChanges(); + } +} diff --git a/src/app/views/device_detail/radio-data/radio-data.module.ts b/src/app/views/device_detail/radio-data/radio-data.module.ts new file mode 100644 index 0000000..0b286bb --- /dev/null +++ b/src/app/views/device_detail/radio-data/radio-data.module.ts @@ -0,0 +1,56 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +import { + ButtonGroupModule, + ButtonModule, + CardModule, + FormModule, + GridModule, + ProgressModule, + NavbarModule, + AlertModule, + ModalModule, + TableModule, + UtilitiesModule, + BadgeModule, + NavModule, + TabsModule, +} from '@coreui/angular'; +import { IconModule } from '@coreui/icons-angular'; +import { ChartjsModule } from '@coreui/angular-chartjs'; + +import { WidgetsModule } from "../../widgets/widgets.module"; + +// import { WidgetsRoutingModule } from './widgets-routing.module'; +import { RadioDataComponent } from './radio-data.component'; + +@NgModule({ + declarations: [ + RadioDataComponent, + ], + imports: [ + CardModule, + AlertModule, + CommonModule, + GridModule, + ProgressModule, + FormModule, + ButtonModule, + ButtonGroupModule, + ChartjsModule, + WidgetsModule, + NavbarModule, + ModalModule, + TableModule, + UtilitiesModule, + BadgeModule, + NavModule, + TabsModule, + ], + exports: [ + RadioDataComponent, + ] +}) +export class RadioDataModule { +} diff --git a/src/app/views/device_logs/devlogs.component.html b/src/app/views/device_logs/devlogs.component.html index 89ffbf0..5d06c01 100644 --- a/src/app/views/device_logs/devlogs.component.html +++ b/src/app/views/device_logs/devlogs.component.html @@ -1,10 +1,22 @@ - + - - Device LOGS + +
Device LOGS + + + +
+ Filtered Result For Device ID + {{devid}} + + Showing last 24 hours logs by default. Use filters to modify the date and time. +
@@ -176,8 +179,8 @@
Please select searching method
- +
@@ -256,8 +259,9 @@
-
- Empty username and password means system default +
+ Empty username and password means system default configuration
@@ -271,9 +275,7 @@ + [source]="ExecutedData" [columnMenu]="columnMenu" [sorting]="sorting" [infoPanel]="infoPanel" [paging]="paging">   {{value}} @@ -286,18 +288,18 @@   {{value}} - + {{value}} - + -
+

@@ -377,7 +379,8 @@ peer ip - diff --git a/src/app/views/devices/devices.component.ts b/src/app/views/devices/devices.component.ts index edb012b..ef56bf8 100644 --- a/src/app/views/devices/devices.component.ts +++ b/src/app/views/devices/devices.component.ts @@ -173,6 +173,9 @@ export class DevicesComponent implements OnInit, OnDestroy { case "logauth": this.router.navigate(["/authlog", { devid: dev.id }]); break; + case "devlogs": + this.router.navigate(["/devlogs", { devid: dev.id }]); + break; case "logacc": this.router.navigate(["/accountlog", { devid: dev.id }]); break; @@ -403,6 +406,9 @@ export class DevicesComponent implements OnInit, OnDestroy { "danger" ); } + else if ("error" in res) { + _self.show_toast("Error", res.error, "danger"); + } else{ _self.show_toast("info", "Updating Firmwares Sent", "light"); _self.initGridTable();} diff --git a/src/app/views/syslog/syslog.component.html b/src/app/views/syslog/syslog.component.html index 6be0bf3..0f804b1 100644 --- a/src/app/views/syslog/syslog.component.html +++ b/src/app/views/syslog/syslog.component.html @@ -3,8 +3,11 @@ - - Devices + +
Devices
+ + Showing last 24 hours logs by default. Use filters to modify the date and time. +