mirror of
https://github.com/MikroWizard/mikrofront.git
synced 2025-08-02 17:25:06 +02:00
Now displays DHCP server details along with historical lease information(pro feature)). Added a ping status component for monitoring device connectivity. Device pages now include logs, accounting, and authorization data for improved tracking. New component in the device page to display active sessions with the ability to terminate them. Redesigned Device Detail Page Reload Buttons for device details page Tabs Device detail pages now refresh every 30 seconds. Restored the missing device logs action menu on the devices list page. Improved handling of duplicate serial numbers when the license serial is not set, with better registration status details on the dashboard. Various minor stability and performance improvements.
662 lines
18 KiB
TypeScript
662 lines
18 KiB
TypeScript
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";
|
|
import { formatInTimeZone } from "date-fns-tz";
|
|
|
|
|
|
|
|
@Component({
|
|
templateUrl: "devices.component.html",
|
|
})
|
|
export class DevicesComponent implements OnInit, OnDestroy {
|
|
public uid: number;
|
|
public uname: string;
|
|
public tz: string;
|
|
public ispro:boolean=false;
|
|
|
|
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;
|
|
_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 !== "";
|
|
}
|
|
}
|
|
@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;
|
|
public ExecutedDataModalVisible: boolean = false;
|
|
public ExecutedData: any = [];
|
|
|
|
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 "devlogs":
|
|
this.router.navigate(["/devlogs", { 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 ("error" in res && 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) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_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);
|
|
});
|
|
}
|
|
}
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else
|
|
_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) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_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) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else if ("error" in res) {
|
|
_self.show_toast("Error", res.error, "danger");
|
|
}
|
|
else{
|
|
_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) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_self.show_toast("info", "Upgrading Firmwares", "light");
|
|
_self.initGridTable();
|
|
}
|
|
});
|
|
}
|
|
|
|
reboot_devices() {
|
|
var _self = this;
|
|
this.data_provider
|
|
.reboot_devices(this.Selectedrows.toString())
|
|
.then((res) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_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) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
if( "status" in res && res.status == 'failed' )
|
|
_self.groups = false
|
|
else
|
|
_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,
|
|
};
|
|
|
|
_self.data_provider.get_dev_list(data).then((res) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_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,
|
|
};
|
|
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 && _self.Selectedrows.length < 1) _self.initGridTable();
|
|
}, 10000);
|
|
}
|
|
|
|
sanitizeString(desc:string) {
|
|
var itemDesc:string='';
|
|
if (desc) {
|
|
itemDesc = desc.toString().replace(/"/g, '\"');
|
|
itemDesc = itemDesc.replace(/'/g, '\'');
|
|
} else {
|
|
itemDesc = '';
|
|
}
|
|
return itemDesc;
|
|
}
|
|
|
|
exportToCsv(jsonResponse:any) {
|
|
const data = jsonResponse;
|
|
const columns = this.getColumns(data);
|
|
const csvData = this.convertToCsv(data, columns);
|
|
this.downloadFile(csvData, 'data.csv', 'text/csv');
|
|
}
|
|
|
|
getColumns(data: any[]): string[] {
|
|
const columns : any = [];
|
|
data.forEach(row => {
|
|
Object.keys(row).forEach((col) => {
|
|
if (!columns.includes(col)) {
|
|
columns.push(col);
|
|
}
|
|
});
|
|
});
|
|
return columns;
|
|
}
|
|
|
|
convertToCsv(data: any[], columns: string[]): string {
|
|
var _self=this;
|
|
let csv = '';
|
|
csv += columns.join(',') + '\n';
|
|
data.forEach(row => {
|
|
const values : any = [];
|
|
columns.forEach((col:any) => {
|
|
values.push('"'+_self.sanitizeString(row[col])+'"');
|
|
});
|
|
csv += values.join(',') + '\n';
|
|
});
|
|
return csv;
|
|
}
|
|
|
|
downloadFile(data: string, filename: string, type: string) {
|
|
const blob = new Blob([data], { type: type });
|
|
const nav = (window.navigator as any);
|
|
|
|
if (nav.msSaveOrOpenBlob) {
|
|
nav.msSaveBlob(blob, filename);
|
|
} else {
|
|
const link = document.createElement('a');
|
|
link.setAttribute('href', URL.createObjectURL(blob));
|
|
link.setAttribute('download', filename);
|
|
link.style.visibility = 'hidden';
|
|
document.body.appendChild(link);
|
|
link.click();
|
|
document.body.removeChild(link);
|
|
}
|
|
}
|
|
get_device_pass(){
|
|
var _self=this;
|
|
_self.selected_device['editform']['password']="Loading ...";
|
|
if (_self.ispro && !this.show_pass){
|
|
_self.data_provider.get_device_pass(this.selected_device['id']).then((res) => {
|
|
if ("error" in res && "error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
_self.selected_device['editform']['password']=res['password'];
|
|
this.show_pass=!this.show_pass;
|
|
}
|
|
});
|
|
}
|
|
else{
|
|
this.show_pass=!this.show_pass;
|
|
}
|
|
}
|
|
show_exec(){
|
|
var _self=this;
|
|
this.ExecutedDataModalVisible = true;
|
|
this.data_provider
|
|
.scan_results()
|
|
.then((res) => {
|
|
if ("error" in res && res.error.indexOf("Unauthorized")) {
|
|
_self.show_toast(
|
|
"Error",
|
|
"You are not authorized to perform this action",
|
|
"danger"
|
|
);
|
|
}
|
|
else{
|
|
let index = 1;
|
|
_self.ExecutedData= res.data.map((d: any) => {
|
|
d.index = index;
|
|
d.ended = formatInTimeZone(
|
|
d.created.split(".")[0] + ".000Z",
|
|
_self.tz,
|
|
"yyyy-MM-dd HH:mm:ss XXX"
|
|
);
|
|
d.info=JSON.parse(d.info);
|
|
d.started = formatInTimeZone(
|
|
d.info.created.split(".")[0] + ".000Z",
|
|
_self.tz,
|
|
"yyyy-MM-dd HH:mm:ss XXX"
|
|
);
|
|
d.start_ip=d.info.start_ip;
|
|
d.end_ip=d.info.end_ip;
|
|
d.result=JSON.parse(d.result);
|
|
index += 1;
|
|
return d;
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ngOnDestroy(): void {
|
|
clearTimeout(this.scan_timer);
|
|
}
|
|
}
|