mirror of
https://github.com/MikroWizard/mikrofront.git
synced 2025-12-10 12:09:29 +00:00
monitoring bugs and devices list pagination fix
This commit is contained in:
parent
6cc1060e36
commit
cfbffe1f64
7 changed files with 131 additions and 28 deletions
|
|
@ -55,6 +55,7 @@
|
||||||
"ngx-date-fns": "^11.0.0",
|
"ngx-date-fns": "^11.0.0",
|
||||||
"ngx-diff": "^9.0.0",
|
"ngx-diff": "^9.0.0",
|
||||||
"ngx-highlightjs": "^12.0.0",
|
"ngx-highlightjs": "^12.0.0",
|
||||||
|
"ngx-infinite-scroll": "^18.0.0",
|
||||||
"ngx-mat-select-search": "^7.0.6",
|
"ngx-mat-select-search": "^7.0.6",
|
||||||
"ngx-material-date-fns-adapter": "^18.0.0",
|
"ngx-material-date-fns-adapter": "^18.0.0",
|
||||||
"ngx-scrollbar": "^13.0.3",
|
"ngx-scrollbar": "^13.0.3",
|
||||||
|
|
|
||||||
|
|
@ -77,9 +77,13 @@ export class dataProvider {
|
||||||
}
|
}
|
||||||
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/stats", data);
|
return this.MikroWizardRPC.sendJsonRequest("/api/dashboard/stats", data);
|
||||||
}
|
}
|
||||||
monitoring_devices_events(){
|
monitoring_devices_events(page:number,textfilter:string=''){
|
||||||
|
var data={
|
||||||
|
'page':page,
|
||||||
|
'textfilter':textfilter
|
||||||
|
}
|
||||||
|
|
||||||
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/devs/get", {});
|
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/devs/get", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
monitoring_events_fix(event_id:number){
|
monitoring_events_fix(event_id:number){
|
||||||
|
|
@ -89,9 +93,10 @@ export class dataProvider {
|
||||||
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/fix", data);
|
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/fix", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
monitoring_all_events(devid:number){
|
monitoring_all_events(devid:number,page:number){
|
||||||
var data={
|
var data={
|
||||||
'devid':devid
|
'devid':devid,
|
||||||
|
'page':page
|
||||||
}
|
}
|
||||||
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/get", data);
|
return this.MikroWizardRPC.sendJsonRequest("/api/monitoring/events/get", data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -416,8 +416,6 @@ export class DevicesComponent implements OnInit, OnDestroy {
|
||||||
var data = {
|
var data = {
|
||||||
group_id: this.selected_group,
|
group_id: this.selected_group,
|
||||||
search: false,
|
search: false,
|
||||||
page: this.paging.page,
|
|
||||||
size: this.paging.pageSize,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
_self.data_provider.get_dev_list(data).then((res) => {
|
_self.data_provider.get_dev_list(data).then((res) => {
|
||||||
|
|
@ -451,7 +449,7 @@ export class DevicesComponent implements OnInit, OnDestroy {
|
||||||
// _self.loading = false;
|
// _self.loading = false;
|
||||||
// });
|
// });
|
||||||
//we don't want to reload table if user is selected devices from list
|
//we don't want to reload table if user is selected devices from list
|
||||||
if (_self.Selectedrows.length < 1) _self.initGridTable();
|
if (_self.Selectedrows && _self.Selectedrows.length < 1) _self.initGridTable();
|
||||||
}, 10000);
|
}, 10000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,20 +2,24 @@
|
||||||
<c-col xs="3" style="height:100%;">
|
<c-col xs="3" style="height:100%;">
|
||||||
<c-card style="height:100%">
|
<c-card style="height:100%">
|
||||||
<c-card-header>
|
<c-card-header>
|
||||||
<c-row><c-col md="10">Devices</c-col>
|
<c-row><c-col xl="3" lg="12" style="padding: 0;">Devices</c-col>
|
||||||
<c-col style="text-align: right;" md="2">
|
<c-col xl="7" lg="12" style="padding: 0;">
|
||||||
|
<input type="text" [(ngModel)]="devicesearch" (ngModelChange)="filter_device(false)" placeholder="search" style="width: 100%;background: transparent;border: 1px solid #cdcdcd;">
|
||||||
|
</c-col>
|
||||||
|
<c-col style="text-align: right;" xl="2" lg="12">
|
||||||
<i class="fa-regular fa-circle-question" style="cursor: pointer;" [cTooltip]="iconstooltip"></i>
|
<i class="fa-regular fa-circle-question" style="cursor: pointer;" [cTooltip]="iconstooltip"></i>
|
||||||
</c-col></c-row>
|
</c-col></c-row>
|
||||||
</c-card-header>
|
</c-card-header>
|
||||||
<c-card-body *ngIf="devices" style="padding: 4px;">
|
<c-card-body *ngIf="devices" style="padding: 4px;">
|
||||||
<ng-scrollbar pointerEventsMethod="scrollbar">
|
<ng-scrollbar pointerEventsMethod="scrollbar">
|
||||||
|
<div infiniteScroll [scrollWindow]="false" scrollViewport [infiniteScrollDistance]="scrollDownDistance" [infiniteScrollThrottle]="throttle" style="width: 100%;" (scrolled)="onDown($event)" >
|
||||||
<ul cListGroup oncontextmenu="return false;" flush>
|
<ul cListGroup oncontextmenu="return false;" flush>
|
||||||
<li cListGroupItem (click)="filter_device(0)" style="cursor: pointer;padding: 5px 8px;"
|
<li cListGroupItem (click)="filter_device(0)" style="cursor: pointer;padding: 5px 8px;"
|
||||||
class="d-flex justify-content-between align-items-center">
|
class="d-flex justify-content-between align-items-center">
|
||||||
<div><i style="color:rgb(9, 44, 9)" class="fa-solid fa-hard-drive"></i>
|
<div><i style="color:rgb(9, 44, 9)" class="fa-solid fa-hard-drive"></i>
|
||||||
| All Devices
|
| All Devices
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex"
|
<div class="d-flex alerts-badges"
|
||||||
style="min-width: 135px;border-left: 1px solid #ccc;height: 100%;/* text-align: right; */display: flex;flex-direction: row-reverse;">
|
style="min-width: 135px;border-left: 1px solid #ccc;height: 100%;/* text-align: right; */display: flex;flex-direction: row-reverse;">
|
||||||
<c-badge *ngIf="CCount" color="danger" style="margin: 0 0 0 1px;" size="sm"
|
<c-badge *ngIf="CCount" color="danger" style="margin: 0 0 0 1px;" size="sm"
|
||||||
shape="rounded-pill">{{CCount}}
|
shape="rounded-pill">{{CCount}}
|
||||||
|
|
@ -44,7 +48,7 @@
|
||||||
[class.fa-tower-broadcast]="x.router_type=='special'"></i>
|
[class.fa-tower-broadcast]="x.router_type=='special'"></i>
|
||||||
| {{x.name}}
|
| {{x.name}}
|
||||||
</div>
|
</div>
|
||||||
<div class="d-flex"
|
<div class="d-flex alerts-badges"
|
||||||
style="min-width: 135px;border-left: 1px solid #ccc;height: 100%;display: flex;flex-direction: row-reverse;">
|
style="min-width: 135px;border-left: 1px solid #ccc;height: 100%;display: flex;flex-direction: row-reverse;">
|
||||||
<c-badge *ngIf="x.CCount" color="danger" style="margin: 0 0 0 1px;" size="sm"
|
<c-badge *ngIf="x.CCount" color="danger" style="margin: 0 0 0 1px;" size="sm"
|
||||||
shape="rounded-pill">{{x.CCount}}
|
shape="rounded-pill">{{x.CCount}}
|
||||||
|
|
@ -57,6 +61,7 @@
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
</div>
|
||||||
</ng-scrollbar>
|
</ng-scrollbar>
|
||||||
</c-card-body>
|
</c-card-body>
|
||||||
</c-card>
|
</c-card>
|
||||||
|
|
@ -70,8 +75,8 @@
|
||||||
class="fa-solid fa-clock-rotate-left mx-1"></i>{{display}}</c-badge></c-col></c-row></c-card-header>
|
class="fa-solid fa-clock-rotate-left mx-1"></i>{{display}}</c-badge></c-col></c-row></c-card-header>
|
||||||
<c-card-body style="padding: 4px;">
|
<c-card-body style="padding: 4px;">
|
||||||
<ng-scrollbar #scrollable="ngScrollbar">
|
<ng-scrollbar #scrollable="ngScrollbar">
|
||||||
|
<div infiniteScroll [scrollWindow]="false" scrollViewport [infiniteScrollUpDistance]="scrollUpDistance" [infiniteScrollThrottle]="throttle" style="width: 100%;" (scrolledUp)="onUp($event)" >
|
||||||
<table class="alarms24" small bordered responsive hover style="margin-bottom:0;white-space: nowrap;" cTable>
|
<table class="alarms24" small bordered responsive hover style="margin-bottom:0;white-space: nowrap;display: table;" cTable>
|
||||||
<thead>
|
<thead>
|
||||||
<tr style="position: sticky;top: -1px;background: #fff;">
|
<tr style="position: sticky;top: -1px;background: #fff;">
|
||||||
<th scope="col">#</th>
|
<th scope="col">#</th>
|
||||||
|
|
@ -85,7 +90,7 @@
|
||||||
<th scope="col">comment</th>
|
<th scope="col">comment</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody *ngIf="eventsall" >
|
||||||
<!-- {
|
<!-- {
|
||||||
"id": 2,
|
"id": 2,
|
||||||
"mac": "6C:3B:6B:86:66:5B",
|
"mac": "6C:3B:6B:86:66:5B",
|
||||||
|
|
@ -120,12 +125,13 @@
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
</div>
|
||||||
</ng-scrollbar>
|
</ng-scrollbar>
|
||||||
</c-card-body>
|
</c-card-body>
|
||||||
</c-card>
|
</c-card>
|
||||||
<c-card style="height:40%">
|
<c-card style="height:40%">
|
||||||
<c-card-header>All Active Alerts</c-card-header>
|
<c-card-header>All Active Alerts</c-card-header>
|
||||||
<c-card-body style="padding: 4px;">
|
<c-card-body *ngIf="eventUnfixedsall" style="padding: 4px;">
|
||||||
<ng-scrollbar #scrollable2="ngScrollbar">
|
<ng-scrollbar #scrollable2="ngScrollbar">
|
||||||
<table small bordered responsive hover style="margin-bottom:0" cTable oncontextmenu="return false;">
|
<table small bordered responsive hover style="margin-bottom:0" cTable oncontextmenu="return false;">
|
||||||
<thead>
|
<thead>
|
||||||
|
|
|
||||||
|
|
@ -39,3 +39,15 @@
|
||||||
font-weight:normal;
|
font-weight:normal;
|
||||||
line-height:110%
|
line-height:110%
|
||||||
}
|
}
|
||||||
|
@media only screen and (max-width: 1600px) {
|
||||||
|
.alerts-badges{
|
||||||
|
flex-direction:column!important;
|
||||||
|
align-items: flex-start;
|
||||||
|
max-width:50px;
|
||||||
|
align-items: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li div:first-of-type{
|
||||||
|
min-width:50%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,8 +17,9 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
public tz: string;
|
public tz: string;
|
||||||
public copy_msg: any = false;
|
public copy_msg: any = false;
|
||||||
public devices: any = false;
|
public devices: any = false;
|
||||||
public eventsall: any = {};
|
public devicesearch:string='';
|
||||||
public eventUnfixedsall: any = {};
|
public eventsall: any = false;
|
||||||
|
public eventUnfixedsall: any = false;
|
||||||
public list_update_timer : any;
|
public list_update_timer : any;
|
||||||
public timer_interval : any;
|
public timer_interval : any;
|
||||||
public ECount: number = 0;
|
public ECount: number = 0;
|
||||||
|
|
@ -27,11 +28,19 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
public display: any;
|
public display: any;
|
||||||
public selected_devid : number =0;
|
public selected_devid : number =0;
|
||||||
public contexItem:any=false;
|
public contexItem:any=false;
|
||||||
|
public throttle:number = 10;
|
||||||
|
public scrollUpDistance:number = 2;
|
||||||
|
|
||||||
|
public devicespage:number=1;
|
||||||
|
public scrollDownDistance:number = 2;
|
||||||
|
|
||||||
|
public allallertpage:number=1;
|
||||||
|
public allowinfinite:boolean=false;
|
||||||
contextmenu : any= false;
|
contextmenu : any= false;
|
||||||
contextmainmenu: any= false;
|
contextmainmenu: any= false;
|
||||||
contextmenuX : any= 0;
|
contextmenuX : any= 0;
|
||||||
contextmenuY : any= 0;
|
contextmenuY : any= 0;
|
||||||
|
AutoScrollTimer:any=false;
|
||||||
constructor(
|
constructor(
|
||||||
private data_provider: dataProvider,
|
private data_provider: dataProvider,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
|
|
@ -72,6 +81,7 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
this.initAllalerts();
|
this.initAllalerts();
|
||||||
this.initUnfixedalerts();
|
this.initUnfixedalerts();
|
||||||
this.update_tables();
|
this.update_tables();
|
||||||
|
this.auto_scroll();
|
||||||
}
|
}
|
||||||
set_table_color(item:any,bypass=true){
|
set_table_color(item:any,bypass=true){
|
||||||
if('status' in item && item.status==true && bypass) {
|
if('status' in item && item.status==true && bypass) {
|
||||||
|
|
@ -120,7 +130,8 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
_self.ECount = 0;
|
_self.ECount = 0;
|
||||||
_self.WCount = 0;
|
_self.WCount = 0;
|
||||||
_self.CCount = 0;
|
_self.CCount = 0;
|
||||||
this.data_provider.monitoring_devices_events().then((res) => {
|
this.devicespage=1;
|
||||||
|
this.data_provider.monitoring_devices_events(this.devicespage,this.devicesearch).then((res) => {
|
||||||
_self.devices = res.map((d: any) => {
|
_self.devices = res.map((d: any) => {
|
||||||
d.ECount = 0;
|
d.ECount = 0;
|
||||||
d.WCount = 0;
|
d.WCount = 0;
|
||||||
|
|
@ -145,7 +156,8 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
|
|
||||||
initAllalerts(){
|
initAllalerts(){
|
||||||
var _self = this;
|
var _self = this;
|
||||||
this.data_provider.monitoring_all_events(_self.selected_devid).then((res) => {
|
this.allowinfinite=false;
|
||||||
|
this.data_provider.monitoring_all_events(_self.selected_devid,_self.allallertpage).then((res) => {
|
||||||
var index=1;
|
var index=1;
|
||||||
_self.eventsall = res.map((d: any) => {
|
_self.eventsall = res.map((d: any) => {
|
||||||
d.time = formatInTimeZone(
|
d.time = formatInTimeZone(
|
||||||
|
|
@ -162,14 +174,20 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
d.index = index++;
|
d.index = index++;
|
||||||
return d
|
return d
|
||||||
});
|
});
|
||||||
console.dir(res)
|
_self.auto_scroll();
|
||||||
setTimeout(function() {
|
|
||||||
_self.scrollable.scrollTo({ bottom: 0, duration: 500 });
|
|
||||||
}, 100);
|
|
||||||
});
|
});
|
||||||
|
setTimeout(function() {
|
||||||
|
_self.allowinfinite=true;
|
||||||
|
console.dir("allowing infinite")
|
||||||
|
}, 1500);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto_scroll(){
|
||||||
|
var _self=this;
|
||||||
|
this.AutoScrollTimer=setTimeout(function() {
|
||||||
|
_self.scrollable.scrollTo({ bottom: 0, duration: 500 });
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
initUnfixedalerts(){
|
initUnfixedalerts(){
|
||||||
var _self = this;
|
var _self = this;
|
||||||
|
|
@ -222,8 +240,11 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
this.reload_data();
|
this.reload_data();
|
||||||
}
|
}
|
||||||
reload_data(){
|
reload_data(){
|
||||||
|
|
||||||
clearTimeout(this.list_update_timer);
|
clearTimeout(this.list_update_timer);
|
||||||
clearTimeout(this.timer_interval);
|
clearTimeout(this.timer_interval);
|
||||||
|
console.dir("reloading data");
|
||||||
|
this.allallertpage=1;
|
||||||
this.initEvents();
|
this.initEvents();
|
||||||
this.initAllalerts();
|
this.initAllalerts();
|
||||||
this.initUnfixedalerts();
|
this.initUnfixedalerts();
|
||||||
|
|
@ -244,16 +265,73 @@ export class MonitoringComponent implements OnInit,OnDestroy {
|
||||||
clearTimeout(this.timer_interval);
|
clearTimeout(this.timer_interval);
|
||||||
this.timer(1)
|
this.timer(1)
|
||||||
this.list_update_timer = setTimeout(() => {
|
this.list_update_timer = setTimeout(() => {
|
||||||
|
_self.allallertpage=1;
|
||||||
_self.initEvents();
|
_self.initEvents();
|
||||||
_self.initAllalerts();
|
_self.initAllalerts();
|
||||||
_self.initUnfixedalerts();
|
_self.initUnfixedalerts();
|
||||||
_self.update_tables();
|
_self.update_tables();
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onUp(ev:any) {
|
||||||
|
if(!this.allowinfinite){
|
||||||
|
console.dir("scroll up not allowed");
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
var _self = this;
|
||||||
|
this.allallertpage++;
|
||||||
|
this.data_provider.monitoring_all_events(_self.selected_devid,_self.allallertpage).then((res) => {
|
||||||
|
var index=1;
|
||||||
|
let eventsall = res.map((d: any) => {
|
||||||
|
d.time = formatInTimeZone(
|
||||||
|
d.eventtime.split(".")[0] + ".000Z",
|
||||||
|
_self.tz,
|
||||||
|
"yyyy-MM-dd HH:mm:ss"
|
||||||
|
);
|
||||||
|
if(d.fixtime)
|
||||||
|
d.fixtime = formatInTimeZone(
|
||||||
|
d.fixtime.split(".")[0] + ".000Z",
|
||||||
|
_self.tz,
|
||||||
|
"yyyy-MM-dd HH:mm:ss"
|
||||||
|
);
|
||||||
|
d.index = index++;
|
||||||
|
return d
|
||||||
|
});
|
||||||
|
_self.eventsall.unshift(...eventsall);
|
||||||
|
// re calculate index
|
||||||
|
var index=1;
|
||||||
|
_self.eventsall = _self.eventsall.map((d: any) => {
|
||||||
|
d.index = index++;
|
||||||
|
return d
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
onDown(ev:any) {
|
||||||
|
var _self = this;
|
||||||
|
console.dir("scroll down");
|
||||||
|
this.devicespage++;
|
||||||
|
this.data_provider.monitoring_devices_events(this.devicespage).then((res) => {
|
||||||
|
let devices = res;
|
||||||
|
console.dir(_self.devices);
|
||||||
|
console.dir(devices);
|
||||||
|
_self.devices=_self.devices.concat(devices);
|
||||||
|
console.dir(_self.devices);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
ngOnDestroy(){
|
ngOnDestroy(){
|
||||||
clearTimeout(this.list_update_timer);
|
clearTimeout(this.list_update_timer);
|
||||||
clearTimeout(this.timer_interval);
|
clearTimeout(this.timer_interval);
|
||||||
|
this.eventsall=false;
|
||||||
|
this.eventUnfixedsall=false;
|
||||||
|
this.scrollable.update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { NgModule } from "@angular/core";
|
import { NgModule } from "@angular/core";
|
||||||
import { CommonModule } from "@angular/common";
|
import { CommonModule } from "@angular/common";
|
||||||
import { ReactiveFormsModule } from "@angular/forms";
|
import { ReactiveFormsModule } from "@angular/forms";
|
||||||
|
import { FormsModule } from "@angular/forms";
|
||||||
|
|
||||||
import {
|
import {
|
||||||
ButtonGroupModule,
|
ButtonGroupModule,
|
||||||
|
|
@ -20,10 +21,10 @@ import {
|
||||||
|
|
||||||
import { ChartjsModule } from "@coreui/angular-chartjs";
|
import { ChartjsModule } from "@coreui/angular-chartjs";
|
||||||
import { NgScrollbarModule } from 'ngx-scrollbar';
|
import { NgScrollbarModule } from 'ngx-scrollbar';
|
||||||
|
|
||||||
import { MonitoringRoutingModule } from "./monitoring-routing.module";
|
import { MonitoringRoutingModule } from "./monitoring-routing.module";
|
||||||
import { MonitoringComponent } from "./monitoring.component";
|
import { MonitoringComponent } from "./monitoring.component";
|
||||||
import { ClipboardModule } from "@angular/cdk/clipboard";
|
import { ClipboardModule } from "@angular/cdk/clipboard";
|
||||||
|
import { InfiniteScrollModule } from 'ngx-infinite-scroll';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
|
@ -35,6 +36,7 @@ import { ClipboardModule } from "@angular/cdk/clipboard";
|
||||||
ProgressModule,
|
ProgressModule,
|
||||||
ReactiveFormsModule,
|
ReactiveFormsModule,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
|
FormsModule,
|
||||||
TemplateIdDirective,
|
TemplateIdDirective,
|
||||||
ButtonModule,
|
ButtonModule,
|
||||||
ButtonGroupModule,
|
ButtonGroupModule,
|
||||||
|
|
@ -46,7 +48,8 @@ import { ClipboardModule } from "@angular/cdk/clipboard";
|
||||||
NgScrollbarModule,
|
NgScrollbarModule,
|
||||||
TableModule,
|
TableModule,
|
||||||
TooltipModule,
|
TooltipModule,
|
||||||
UtilitiesModule
|
UtilitiesModule,
|
||||||
|
InfiniteScrollModule
|
||||||
],
|
],
|
||||||
declarations: [MonitoringComponent],
|
declarations: [MonitoringComponent],
|
||||||
})
|
})
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue