--------------------------
* Add ANR xApp neighbor cell relation table
* Drop the pendulum xApp control screen
+* Add column sorting on xApp catalog and xApp control
* Add disconnect-all button to RAN connection screen
Version 1.0.3, 28 May 2019
<div class="spinner-container" *ngIf="dataSource.loading$ | async">
<mat-spinner></mat-spinner>
</div>
- <table mat-table [dataSource]="dataSource" class="catalog-table mat-elevation-z8">
+ <table mat-table [dataSource]="dataSource" matSort class="catalog-table mat-elevation-z8">
<ng-container matColumnDef="name">
- <mat-header-cell *matHeaderCellDef> xApp Name </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> xApp Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="version">
- <mat-header-cell *matHeaderCellDef> xApp version </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> xApp version </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.version}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
- <mat-header-cell *matHeaderCellDef> Status </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> Status </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.status}} </mat-cell>
</ng-container>
* limitations under the License.
* ========================LICENSE_END===================================
*/
-import { Component, OnInit} from '@angular/core';
-import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
-import { ConfirmDialogService } from './../services/ui/confirm-dialog.service'
-import { NotificationService } from './../services/ui/notification.service'
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { MatSort } from '@angular/material/sort';
import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
+import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
+import { NotificationService } from './../services/ui/notification.service';
import { CatalogDataSource } from './catalog.datasource';
@Component({
displayedColumns: string[] = ['name', 'version', 'status', 'action'];
dataSource: CatalogDataSource;
+ @ViewChild(MatSort) sort: MatSort;
constructor(
private xappMgrSvc: XappMgrService,
private notification: NotificationService) { }
ngOnInit() {
- this.dataSource = new CatalogDataSource(this.xappMgrSvc);
+ this.dataSource = new CatalogDataSource(this.xappMgrSvc, this.sort );
this.dataSource.loadTable();
}
*/
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { MatSort } from '@angular/material';
+import { merge } from 'rxjs';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
-import { catchError, finalize } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
-import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
+import { catchError, finalize, map } from 'rxjs/operators';
import { XMXapp } from '../interfaces/xapp-mgr.types';
+import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
export class CatalogDataSource extends DataSource<XMXapp> {
public loading$ = this.loadingSubject.asObservable();
- constructor(private xappMgrSvc: XappMgrService) {
+ constructor(private xappMgrSvc: XappMgrService, private sort: MatSort ) {
super();
};
}
connect(collectionViewer: CollectionViewer): Observable<XMXapp[]> {
- return this.xAppsSubject.asObservable();
+ const dataMutations = [
+ this.xAppsSubject.asObservable(),
+ this.sort.sortChange
+ ];
+ return merge(...dataMutations).pipe(map(() => {
+ return this.getSortedData([...this.xAppsSubject.getValue()]);
+ }));
}
disconnect(collectionViewer: CollectionViewer): void {
this.xAppsSubject.complete();
this.loadingSubject.complete();
}
+
+ private getSortedData(data: XMXapp[]) {
+ if (!this.sort.active || this.sort.direction === '') {
+ return data;
+ }
+
+ return data.sort((a, b) => {
+ const isAsc = this.sort.direction === 'asc';
+ switch (this.sort.active) {
+ case 'name': return compare(a.name, b.name, isAsc);
+ case 'version': return compare(a.version, b.version, isAsc);
+ case 'status': return compare(a.status, b.status, isAsc);
+ default: return 0;
+ }
+ });
+ }
}
+
+function compare(a, b, isAsc) {
+ return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+}
+
<div class="spinner-container" *ngIf="dataSource.loading$ | async">
<mat-spinner></mat-spinner>
</div>
- <table mat-table [dataSource]="dataSource" multiTemplateDataRows class="control-table mat-elevation-z8">
+ <table mat-table [dataSource]="dataSource" matSort multiTemplateDataRows class="control-table mat-elevation-z8">
<ng-container matColumnDef="xapp">
- <mat-header-cell *matHeaderCellDef> xApp Name </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> xApp Name </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.xapp}} </mat-cell>
</ng-container>
<ng-container matColumnDef="name">
- <mat-header-cell *matHeaderCellDef> Instance Name</mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> Instance Name</mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.instance.name}} </mat-cell>
</ng-container>
<ng-container matColumnDef="status">
- <mat-header-cell *matHeaderCellDef> Status </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> Status </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.instance.status}} </mat-cell>
</ng-container>
- <ng-container matColumnDef="ip">
- <mat-header-cell *matHeaderCellDef> IP </mat-header-cell>
+ <ng-container matColumnDef="ip" >
+ <mat-header-cell *matHeaderCellDef mat-sort-header> IP </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.instance.ip}} </mat-cell>
</ng-container>
<ng-container matColumnDef="port">
- <mat-header-cell *matHeaderCellDef> Port </mat-header-cell>
+ <mat-header-cell *matHeaderCellDef mat-sort-header> Port </mat-header-cell>
<mat-cell *matCellDef="let element"> {{element.instance.port}} </mat-cell>
</ng-container>
* limitations under the License.
* ========================LICENSE_END===================================
*/
-import { Component, OnInit } from '@angular/core';
-import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { MatSort } from '@angular/material/sort';
import { Router } from '@angular/router';
-import { ErrorDialogService } from './../services/ui/error-dialog.service';
+import { XappControlRow } from '../interfaces/xapp-mgr.types';
+import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
+import { ErrorDialogService } from './../services/ui/error-dialog.service';
import { NotificationService } from './../services/ui/notification.service';
-import { XappControlRow } from '../interfaces/xapp-mgr.types';
import { ControlAnimations } from './control.animations';
import { ControlDataSource } from './control.datasource';
-import { routerNgProbeToken } from '@angular/router/src/router_module';
@Component({
selector: 'app-control',
displayedColumns: string[] = ['xapp', 'name', 'status', 'ip', 'port', 'action'];
dataSource: ControlDataSource;
+ @ViewChild(MatSort) sort: MatSort;
constructor(
private xappMgrSvc: XappMgrService,
private notification: NotificationService) { }
ngOnInit() {
- this.dataSource = new ControlDataSource(this.xappMgrSvc);
+ this.dataSource = new ControlDataSource(this.xappMgrSvc, this.sort);
this.dataSource.loadTable();
}
*/
import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { MatSort } from '@angular/material';
+import { merge } from 'rxjs';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import { Observable } from 'rxjs/Observable';
-import { catchError, finalize } from 'rxjs/operators';
import { of } from 'rxjs/observable/of';
-import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { catchError, finalize, map } from 'rxjs/operators';
+import { XappControlRow, XMXapp } from '../interfaces/xapp-mgr.types';
import { XappMgrService } from '../services/xapp-mgr/xapp-mgr.service';
-import { XMXapp, XappControlRow } from '../interfaces/xapp-mgr.types';
export class ControlDataSource extends DataSource<XappControlRow> {
public loading$ = this.loadingSubject.asObservable();
- constructor(private xappMgrSvc: XappMgrService) {
+ constructor(private xappMgrSvc: XappMgrService, private sort: MatSort) {
super();
};
}
connect(collectionViewer: CollectionViewer): Observable<XappControlRow[]> {
- return this.xAppInstancesSubject.asObservable();
+ const dataMutations = [
+ this.xAppInstancesSubject.asObservable(),
+ this.sort.sortChange
+ ];
+ return merge(...dataMutations).pipe(map(() => {
+ return this.getSortedData([...this.xAppInstancesSubject.getValue()]);
+ }));
}
disconnect(collectionViewer: CollectionViewer): void {
}
return xAppInstances;
}
+
+ private getSortedData(data: XappControlRow[]) {
+ if (!this.sort.active || this.sort.direction === '') {
+ return data;
+ }
+
+ return data.sort((a, b) => {
+ const isAsc = this.sort.direction === 'asc';
+ switch (this.sort.active) {
+ case 'xapp': return compare(a.xapp, b.xapp, isAsc);
+ case 'name': return compare(a.instance.name, b.instance.name, isAsc);
+ case 'status': return compare(a.instance.status, b.instance.status, isAsc);
+ case 'ip': return compare(a.instance.ip, b.instance.ip, isAsc);
+ case 'port': return compare(a.instance.port, b.instance.port, isAsc);
+ default: return 0;
+ }
+ });
+ }
}
+
+function compare(a, b, isAsc) {
+ return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+}
\ No newline at end of file