add column sorting 15/215/4
authorjh245g <jh245g@att.com>
Thu, 30 May 2019 17:32:08 +0000 (13:32 -0400)
committerjh245g <jh245g@att.com>
Fri, 31 May 2019 15:09:45 +0000 (11:09 -0400)
Issue-ID: RICPLT-1344
Signed-off-by: Jun (Nicolas) Hu <jh245g@att.com>
Change-Id: Ia7be93ec29aff5ebdb7eaf992bab0ca0a8b860cc

docs/release-notes.rst
webapp-frontend/src/app/catalog/catalog.component.html
webapp-frontend/src/app/catalog/catalog.component.ts
webapp-frontend/src/app/catalog/catalog.datasource.ts
webapp-frontend/src/app/control/control.component.html
webapp-frontend/src/app/control/control.component.ts
webapp-frontend/src/app/control/control.datasource.ts

index e2f00c6..c50e4cc 100644 (file)
@@ -24,6 +24,7 @@ Version 1.0.4, 30 May 2019
 --------------------------
 * 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
index 2379fd4..2277bb7 100644 (file)
   <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>
 
index 96e040e..04b8380 100644 (file)
  * 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({
@@ -33,6 +34,7 @@ export class CatalogComponent implements OnInit{
 
   displayedColumns: string[] = ['name', 'version', 'status', 'action'];
   dataSource: CatalogDataSource;
+  @ViewChild(MatSort) sort: MatSort;
 
   constructor(
     private xappMgrSvc: XappMgrService,
@@ -41,7 +43,7 @@ export class CatalogComponent implements OnInit{
     private notification: NotificationService) { }
 
   ngOnInit() {
-    this.dataSource = new CatalogDataSource(this.xappMgrSvc);
+    this.dataSource = new CatalogDataSource(this.xappMgrSvc, this.sort );
     this.dataSource.loadTable();
   }
 
index 6ee6e92..f6ae32d 100644 (file)
  */
 
 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> {
 
@@ -34,7 +36,7 @@ export class CatalogDataSource extends DataSource<XMXapp> {
 
   public loading$ = this.loadingSubject.asObservable();
 
-  constructor(private xappMgrSvc: XappMgrService) {
+  constructor(private xappMgrSvc: XappMgrService, private sort: MatSort ) {
     super();
   };
 
@@ -49,11 +51,38 @@ export class CatalogDataSource extends DataSource<XMXapp> {
   }
 
   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);
+}
+
index 1e7bca2..5ae35aa 100644 (file)
   <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>
 
index 29a88cc..755625c 100644 (file)
  * 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',
@@ -38,6 +38,7 @@ export class ControlComponent implements OnInit {
 
   displayedColumns: string[] = ['xapp', 'name', 'status', 'ip', 'port', 'action'];
   dataSource: ControlDataSource;
+  @ViewChild(MatSort) sort: MatSort;
 
   constructor(
     private xappMgrSvc: XappMgrService,
@@ -47,7 +48,7 @@ export class ControlComponent implements OnInit {
     private notification: NotificationService) { }
 
   ngOnInit() {
-    this.dataSource = new ControlDataSource(this.xappMgrSvc);
+    this.dataSource = new ControlDataSource(this.xappMgrSvc, this.sort);
     this.dataSource.loadTable();
   }
 
index 833a4f0..30752ef 100644 (file)
  */
 
 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> {
 
@@ -34,7 +36,7 @@ export class ControlDataSource extends DataSource<XappControlRow> {
 
   public loading$ = this.loadingSubject.asObservable();
 
-  constructor(private xappMgrSvc: XappMgrService) {
+  constructor(private xappMgrSvc: XappMgrService, private sort: MatSort) {
     super();
   };
 
@@ -49,7 +51,13 @@ export class ControlDataSource extends DataSource<XappControlRow> {
   }
 
   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 {
@@ -71,4 +79,26 @@ export class ControlDataSource extends DataSource<XappControlRow> {
     }
     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