Non-RT RIC Dashboard

First commit

Change-Id: I9e140d31d65d13df3ce07f6b87eac250ee952eab
Issue-ID: NONRTRIC-61
Signed-off-by: PatrikBuhr <patrik.buhr@est.tech>
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.animations.ts b/dashboard/webapp-frontend/src/app/app-control/app-control.animations.ts
new file mode 100644
index 0000000..c00f877
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.animations.ts
@@ -0,0 +1,28 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { animate, state, style, transition, trigger } from '@angular/animations';
+
+export const AppControlAnimations = {
+  messageTrigger: trigger('messageExpand', [
+    state('collapsed', style({ height: '0px', minHeight: '0', display: 'none' })),
+    state('expanded', style({ height: '*' })),
+  ])
+}
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.component.html b/dashboard/webapp-frontend/src/app/app-control/app-control.component.html
new file mode 100644
index 0000000..ec802f4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.component.html
@@ -0,0 +1,100 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+<div class="app-control__section">
+  <h3 class="rd-global-page-title">xApp Control</h3>
+
+  <table mat-table [dataSource]="dataSource" matSort multiTemplateDataRows class="app-control-table mat-elevation-z8">
+
+    <ng-container matColumnDef="xapp">
+      <mat-header-cell *matHeaderCellDef mat-sort-header> App Name </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.xapp}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="name">
+      <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 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 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 mat-sort-header> Port </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.instance.port}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="action">
+      <mat-header-cell *matHeaderCellDef> Action </mat-header-cell>
+      <!-- click on button should not expand/collapse the row -->
+      <mat-cell *matCellDef="let element" (click)="$event.stopPropagation()">
+      <button mat-icon-button (click)="controlApp(element)">
+          <mat-icon matTooltip="Adjust settings">settings</mat-icon>
+        </button>
+        <button mat-icon-button (click)="onUndeployApp(element)">
+          <mat-icon matTooltip="Undeploy app">cloud_download</mat-icon>
+        </button>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="expandedDetail">
+      <td mat-cell *matCellDef="let element" [attr.colspan]="displayedColumns.length">
+        <div [@messageExpand]="element == expandedElement ? 'expanded' : 'collapsed'">
+          <div>
+            txMessages:
+          </div>
+          <li *ngFor="let rxmessage of element.instance.rxMessages">
+            <span>{{rxmessage}}</span>
+          </li>
+          <div>
+            rxMessages:
+          </div>
+          <li *ngFor="let txmessage of element.instance.txMessages">
+            <span>{{txmessage}}</span>
+          </li>
+        </div>
+      </td>
+    </ng-container>
+
+    <ng-container matColumnDef="noRecordsFound">
+      <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let element; columns: displayedColumns;"
+      [class.example-expanded-row]="expandedElement === element"
+      (click)="expandedElement = expandedElement === element ? null : element"></mat-row>
+    <tr mat-row *matRowDef="let row; columns: ['expandedDetail']" class="message-row"></tr>
+    <mat-footer-row *matFooterRowDef="['noRecordsFound']" [ngClass]="{'display-none': dataSource.rowCount > 0}"></mat-footer-row>
+
+  </table>
+
+  <div class="spinner-container" *ngIf="dataSource.loading$ | async">
+    <mat-spinner diameter=50></mat-spinner>
+  </div>
+
+</div>
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.component.scss b/dashboard/webapp-frontend/src/app/app-control/app-control.component.scss
new file mode 100644
index 0000000..232562f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.component.scss
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+ .app-control__section {
+}
+
+
+.spinner-container {
+  height: 100px;
+  width: 100px;
+}
+
+.spinner-container mat-spinner {
+  margin: 0 auto 0 auto;
+}
+
+.app-control-table {
+  width: 100%;
+  min-height: 150px;
+  margin-top: 10px;
+  background-color: transparent;
+}
+
+tr.message-row {
+  height: 0;
+}
+
+.display-none {
+  display: none;
+}
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.component.spec.ts b/dashboard/webapp-frontend/src/app/app-control/app-control.component.spec.ts
new file mode 100644
index 0000000..6648d81
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { AppControlComponent } from './app-control.component';
+
+describe('AppControlComponent', () => {
+  let component: AppControlComponent;
+  let fixture: ComponentFixture<AppControlComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AppControlComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AppControlComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.component.ts b/dashboard/webapp-frontend/src/app/app-control/app-control.component.ts
new file mode 100644
index 0000000..07b931d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.component.ts
@@ -0,0 +1,103 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { MatSort } from '@angular/material/sort';
+import { Router } from '@angular/router';
+import { XappControlRow } from '../interfaces/app-mgr.types';
+import { AppMgrService } from '../services/app-mgr/app-mgr.service';
+import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { LoadingDialogService } from '../services/ui/loading-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
+import { AppControlAnimations } from './app-control.animations';
+import { AppControlDataSource } from './app-control.datasource';
+import { finalize } from 'rxjs/operators';
+
+@Component({
+  selector: 'rd-app-control',
+  templateUrl: './app-control.component.html',
+  styleUrls: ['./app-control.component.scss'],
+  animations: [AppControlAnimations.messageTrigger]
+})
+export class AppControlComponent implements OnInit {
+
+  displayedColumns: string[] = ['xapp', 'name', 'status', 'ip', 'port', 'action'];
+  dataSource: AppControlDataSource;
+  @ViewChild(MatSort, {static: true}) sort: MatSort;
+
+  constructor(
+    private appMgrSvc: AppMgrService,
+    private router: Router,
+    private confirmDialogService: ConfirmDialogService,
+    private errorDialogService: ErrorDialogService,
+    private loadingDialogService: LoadingDialogService,
+    private notificationService: NotificationService) { }
+
+  ngOnInit() {
+    this.dataSource = new AppControlDataSource(this.appMgrSvc, this.sort, this.notificationService);
+    this.dataSource.loadTable();
+  }
+
+  controlApp(app: XappControlRow): void {
+    // TODO: identify apps without hardcoding to names
+    const acAppPattern0 =  /[Aa][Dd][Mm][Ii][Nn]/;
+    const acAppPattern1 =  /[Aa][Dd][Mm][Ii][Ss]{2}[Ii][Oo][Nn]/;
+    const anrAppPattern0 = /ANR/;
+    const anrAppPattern1 = /[Aa][Uu][Tt][Oo][Mm][Aa][Tt][Ii][Cc]/;
+    const anrAppPattern2 = /[Nn][Ee][Ii][Gg][Hh][Bb][Oo][Rr]/;
+    if (acAppPattern0.test(app.xapp) || acAppPattern1.test(app.xapp)) {
+      this.router.navigate(['/ac']);
+    } else if (anrAppPattern0.test(app.xapp) || (anrAppPattern1.test(app.xapp) && anrAppPattern2.test(app.xapp))) {
+      this.router.navigate(['/anr']);
+    } else {
+      this.errorDialogService.displayError('No control available for ' + app.xapp + ' (yet)');
+    }
+  }
+
+  onUndeployApp(app: XappControlRow): void {
+    this.confirmDialogService.openConfirmDialog('Are you sure you want to undeploy App ' + app.xapp + '?')
+      .afterClosed().subscribe( (res: boolean) => {
+        if (res) {
+          this.loadingDialogService.startLoading("Undeploying " + app.xapp);
+          this.appMgrSvc.undeployXapp(app.xapp)
+            .pipe(
+              finalize(() => this.loadingDialogService.stopLoading())
+            )
+            .subscribe(
+            ( httpResponse: HttpResponse<Object>) => {
+              // Answers 204/No content on success
+              this.notificationService.success('App undeployed successfully!');
+              this.dataSource.loadTable();
+            },
+            ( (her: HttpErrorResponse) => {
+              // the error field should have an ErrorTransport object
+              let msg = her.message;
+              if (her.error && her.error.message) {
+                msg = her.error.message;
+              }
+              this.notificationService.warn('App undeploy failed: ' + msg);
+            })
+          );
+        }
+      });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/app-control/app-control.datasource.ts b/dashboard/webapp-frontend/src/app/app-control/app-control.datasource.ts
new file mode 100644
index 0000000..e97dc63
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/app-control/app-control.datasource.ts
@@ -0,0 +1,134 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { HttpErrorResponse } from '@angular/common/http';
+import { MatSort } from '@angular/material/sort';
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { merge } from 'rxjs';
+import { of } from 'rxjs/observable/of';
+import { catchError, finalize, map } from 'rxjs/operators';
+import { XappControlRow, XMDeployedApp, XMXappInstance } from '../interfaces/app-mgr.types';
+import { AppMgrService } from '../services/app-mgr/app-mgr.service';
+import { NotificationService } from '../services/ui/notification.service';
+
+export class AppControlDataSource extends DataSource<XappControlRow> {
+
+  private appControlSubject = new BehaviorSubject<XappControlRow[]>([]);
+
+  private loadingSubject = new BehaviorSubject<boolean>(false);
+
+  public loading$ = this.loadingSubject.asObservable();
+
+  public rowCount = 1; // hide footer during intial load
+
+  private emptyInstances: XMXappInstance =
+    { ip: null,
+      name: null,
+      port: null,
+      status: null,
+      rxMessages: [],
+      txMessages: [],
+    };
+
+  constructor(private appMgrSvc: AppMgrService,
+    private sort: MatSort,
+    private notificationService: NotificationService) {
+    super();
+  }
+
+  loadTable() {
+    this.loadingSubject.next(true);
+    this.appMgrSvc.getDeployed()
+      .pipe(
+        catchError( (her: HttpErrorResponse) => {
+          console.log('AppControlDataSource failed: ' + her.message);
+          this.notificationService.error('Failed to get applications: ' + her.message);
+          return of([]);
+        }),
+        finalize(() => this.loadingSubject.next(false))
+      )
+      .subscribe( (xApps: XMDeployedApp[]) => {
+        this.rowCount = xApps.length;
+        const flattenedApps = this.flatten(xApps);
+        this.appControlSubject.next(flattenedApps);
+      });
+  }
+
+  connect(collectionViewer: CollectionViewer): Observable<XappControlRow[]> {
+    const dataMutations = [
+      this.appControlSubject.asObservable(),
+      this.sort.sortChange
+    ];
+    return merge(...dataMutations).pipe(map(() => {
+      return this.getSortedData([...this.appControlSubject.getValue()]);
+    }));
+  }
+
+  disconnect(collectionViewer: CollectionViewer): void {
+    this.appControlSubject.complete();
+    this.loadingSubject.complete();
+  }
+
+  private flatten(allxappdata: XMDeployedApp[]): XappControlRow[]  {
+    const xAppInstances: XappControlRow[] = [];
+    for (const xapp of allxappdata) {
+      if (!xapp.instances) {
+        const row: XappControlRow = {
+          xapp: xapp.name,
+          instance: this.emptyInstances
+        };
+        xAppInstances.push(row);
+      } else {
+        for (const ins of xapp.instances) {
+          const row: XappControlRow = {
+            xapp: xapp.name,
+            instance: ins
+          };
+          xAppInstances.push(row);
+        }
+      }
+    }
+    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: any, b: any, isAsc: boolean) {
+  return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+}
diff --git a/dashboard/webapp-frontend/src/app/control/control.component.html b/dashboard/webapp-frontend/src/app/control/control.component.html
new file mode 100644
index 0000000..e3258b6
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/control/control.component.html
@@ -0,0 +1,24 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<div class="control__section">
+  <rd-ran-control></rd-ran-control>
+  <hr>
+  <rd-app-control></rd-app-control>
+</div>
diff --git a/dashboard/webapp-frontend/src/app/control/control.component.scss b/dashboard/webapp-frontend/src/app/control/control.component.scss
new file mode 100644
index 0000000..f06d0ce
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/control/control.component.scss
@@ -0,0 +1,22 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.control__section {
+  background-color: transparent;
+}
diff --git a/dashboard/webapp-frontend/src/app/control/control.component.spec.ts b/dashboard/webapp-frontend/src/app/control/control.component.spec.ts
new file mode 100644
index 0000000..eb7d064
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/control/control.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ControlComponent } from './control.component';
+
+describe('ControlComponent', () => {
+  let component: ControlComponent;
+  let fixture: ComponentFixture<ControlComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ControlComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ControlComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/control/control.component.ts b/dashboard/webapp-frontend/src/app/control/control.component.ts
new file mode 100644
index 0000000..18545af
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/control/control.component.ts
@@ -0,0 +1,34 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'rd-control',
+  templateUrl: './control.component.html',
+  styleUrls: ['./control.component.scss']
+})
+export class ControlComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() {
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/footer/footer.component.html b/dashboard/webapp-frontend/src/app/footer/footer.component.html
new file mode 100644
index 0000000..5dd1c36
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/footer/footer.component.html
@@ -0,0 +1,24 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<div class="copyright__text" [ngClass]="{'footer-dark': darkMode}">
+  Copyright (C) 2019 AT&T Intellectual Property. Licensed under the Apache License, Version 2.0.
+  <br/>
+  Version {{dashboardVersion}}
+</div>
diff --git a/dashboard/webapp-frontend/src/app/footer/footer.component.scss b/dashboard/webapp-frontend/src/app/footer/footer.component.scss
new file mode 100644
index 0000000..e2456d7
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/footer/footer.component.scss
@@ -0,0 +1,28 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.copyright__text {
+  color: gray;
+  letter-spacing: 0.1rem;
+  font-size: 12px;
+}
+
+.footer-dark {
+  color: white;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/footer/footer.component.spec.ts b/dashboard/webapp-frontend/src/app/footer/footer.component.spec.ts
new file mode 100644
index 0000000..6f80297
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/footer/footer.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { FooterComponent } from './footer.component';
+
+describe('FooterComponent', () => {
+  let component: FooterComponent;
+  let fixture: ComponentFixture<FooterComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ FooterComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(FooterComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/footer/footer.component.ts b/dashboard/webapp-frontend/src/app/footer/footer.component.ts
new file mode 100644
index 0000000..e119d70
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/footer/footer.component.ts
@@ -0,0 +1,49 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit } from '@angular/core';
+import { DashboardSuccessTransport } from '../interfaces/dashboard.types';
+import { DashboardService } from '../services/dashboard/dashboard.service';
+import { UiService } from '../services/ui/ui.service';
+
+@Component({
+  selector: 'rd-footer',
+  templateUrl: './footer.component.html',
+  styleUrls: ['./footer.component.scss']
+})
+
+/**
+ * Fetches the version on load for display in the footer
+ */
+export class FooterComponent implements OnInit {
+  darkMode: boolean;
+  dashboardVersion: string;
+
+  // Inject the service
+  constructor(private dashboardService: DashboardService,
+              public ui: UiService ) { }
+
+  ngOnInit() {
+    this.dashboardService.getVersion().subscribe((res: DashboardSuccessTransport) => this.dashboardVersion = res.data);
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/ac-xapp.types.ts b/dashboard/webapp-frontend/src/app/interfaces/ac-xapp.types.ts
new file mode 100644
index 0000000..125f72f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/ac-xapp.types.ts
@@ -0,0 +1,33 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by the AC xApp
+
+export interface ACAdmissionIntervalControl {
+  enforce: boolean;
+  window_length: number;
+  blocking_rate: number;
+  trigger_threshold: number;
+}
+
+export interface ACAdmissionIntervalControlAck {
+  status: string;
+  message: string;
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/anr-xapp.types.ts b/dashboard/webapp-frontend/src/app/interfaces/anr-xapp.types.ts
new file mode 100644
index 0000000..6b7db25
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/anr-xapp.types.ts
@@ -0,0 +1,47 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by the ANR xApp
+
+export interface ANRGgNodeBTable {
+  gNodeBIds: Array<string>;
+}
+
+export interface ANRNeighborCellRelationTable {
+  ncrtRelations: Array<ANRNeighborCellRelation>;
+}
+
+export interface ANRNeighborCellRelation {
+  servingCellNrcgi: string;
+  neighborCellNrpci: string;
+  neighborCellNrcgi: string;
+  flagNoHo: boolean;
+  flagNoXn: boolean;
+  flagNoRemove: boolean;
+}
+
+export interface ANRNeighborCellRelationMod {
+  servingCellNrcgi: string;
+  neighborCellNrpci: string;
+  neighborCellNrcgi: string;
+  flagNoHo: boolean;
+  flagNoXn: boolean;
+  flagNoRemove: boolean;
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/app-mgr.types.ts b/dashboard/webapp-frontend/src/app/interfaces/app-mgr.types.ts
new file mode 100644
index 0000000..064967c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/app-mgr.types.ts
@@ -0,0 +1,67 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by the App Manager
+
+export interface XMSubscription {
+  eventType: string;
+  id: string;
+  maxRetries: number;
+  retryTimer: number;
+  targetUrl: string;
+}
+
+/**
+ * Name is the only required field
+ */
+export interface XMXappInfo {
+  name: string;
+  configName?: string;
+  namespace?: string;
+  serviceName?: string;
+  imageRepo?: string;
+  hostname?: string;
+}
+
+export interface XMXappInstance {
+  ip: string;
+  name: string;
+  port: number;
+  status: string;
+  rxMessages: Array<string>;
+  txMessages: Array<string>;
+}
+
+export interface XMDeployableApp {
+  name: string;
+  version: string;
+}
+
+export interface XMDeployedApp {
+  name: string;
+  status: string;
+  version: string;
+  instances: Array<XMXappInstance>;
+}
+
+export interface XappControlRow {
+  xapp: string;
+  instance: XMXappInstance;
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/dashboard.types.ts b/dashboard/webapp-frontend/src/app/interfaces/dashboard.types.ts
new file mode 100644
index 0000000..90dfd15
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/dashboard.types.ts
@@ -0,0 +1,57 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by Dashboard admin services
+
+export interface DashboardSuccessTransport {
+  status: number;
+  data: string;
+}
+
+export interface EcompRoleFunction {
+  name: string;
+  code: string;
+  type: string;
+  action: string;
+}
+
+export interface EcompRole {
+  id: number;
+  name: string;
+  [position: number]: EcompRoleFunction;
+}
+
+export interface EcompUser {
+  orgId?: number;
+  managerId?: string;
+  firstName?: string;
+  middleInitial?: string;
+  lastName?: string;
+  phone?: string;
+  email?: string;
+  hrid?: string;
+  orgUserId?: string;
+  orgCode?: string;
+  orgManagerUserId?: string;
+  jobTitle?: string;
+  loginId: string;
+  active: boolean;
+  [position: number]: EcompRole;
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/e2-mgr.types.ts b/dashboard/webapp-frontend/src/app/interfaces/e2-mgr.types.ts
new file mode 100644
index 0000000..f303c14
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/e2-mgr.types.ts
@@ -0,0 +1,66 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by the E2 Manager
+
+export interface E2SetupRequest {
+  ranName: string;
+  ranIp: string;
+  ranPort: string;
+}
+
+export interface E2ErrorResponse {
+  errorCode: string;
+  errorMessage: string;
+}
+
+export interface E2NodebIdentityGlobalNbId {
+  nbId: string;
+  plmnId: string;
+}
+
+export interface E2NodebIdentity {
+  inventoryName: string;
+  globalNbId: E2NodebIdentityGlobalNbId;
+}
+
+export interface E2GetNodebResponse {
+  connectionStatus: string; // actually one-of, but model as string
+  enb: object; // don't model this until needed
+  failureType: string; // actually one-of, but model as string
+  gnb: object; // don't model this until needed
+  ip: string;
+  nodeType: string; // actually one-of, but model as string
+  port: number; // actually integer
+  ranName: string;
+  setupFailure: object; // don't model this until needed
+}
+
+export interface E2RanDetails {
+  nodebIdentity: E2NodebIdentity;
+  nodebStatus: E2GetNodebResponse;
+}
+
+export interface RanDialogFormData {
+  ranIp: string;
+  ranName: string;
+  ranPort: string;
+  ranType: string;
+}
diff --git a/dashboard/webapp-frontend/src/app/interfaces/policy.types.ts b/dashboard/webapp-frontend/src/app/interfaces/policy.types.ts
new file mode 100644
index 0000000..bc94af9
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/interfaces/policy.types.ts
@@ -0,0 +1,38 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+// Models of data used by the Policy Control
+
+export interface PolicyType {
+  policy_type_id: number;
+  name: string;
+  description: string;
+  create_schema: string;
+}
+
+export interface PolicyInstance {
+  instanceId: string;
+  instance: string;
+}
+
+export interface PolicyInstanceAck {
+  status: string;
+  message: string;
+}
diff --git a/dashboard/webapp-frontend/src/app/main/main.component.html b/dashboard/webapp-frontend/src/app/main/main.component.html
new file mode 100644
index 0000000..f05fd50
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/main/main.component.html
@@ -0,0 +1,23 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  Modifications Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<div class = "main__container">
+  <rd-policy-card></rd-policy-card>
+</div>
diff --git a/dashboard/webapp-frontend/src/app/main/main.component.scss b/dashboard/webapp-frontend/src/app/main/main.component.scss
new file mode 100644
index 0000000..aeb3b5d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/main/main.component.scss
@@ -0,0 +1,27 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.main__container {
+  display: grid;
+  grid-template-columns: repeat(3, 1fr);
+  grid-template-rows: repeat(auto-fill, 1fr);
+  align-items: center;
+  justify-items: center;
+  height: 100%;
+}
diff --git a/dashboard/webapp-frontend/src/app/main/main.component.spec.ts b/dashboard/webapp-frontend/src/app/main/main.component.spec.ts
new file mode 100644
index 0000000..47f86b4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/main/main.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { MainComponent } from './main.component';
+
+describe('MainComponent', () => {
+  let component: MainComponent;
+  let fixture: ComponentFixture<MainComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ MainComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(MainComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/main/main.component.ts b/dashboard/webapp-frontend/src/app/main/main.component.ts
new file mode 100644
index 0000000..8967a42
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/main/main.component.ts
@@ -0,0 +1,33 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit } from '@angular/core';
+
+@Component({
+  selector: 'rd-main',
+  templateUrl: './main.component.html',
+  styleUrls: ['./main.component.scss']
+})
+export class MainComponent implements OnInit {
+
+  constructor() { }
+
+  ngOnInit() { }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.html b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.html
new file mode 100644
index 0000000..d91c4a9
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.html
@@ -0,0 +1,33 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  Modifications Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+<!-- browse icons at https://material.io/tools/icons/?style=baseline -->
+<mat-nav-list [ngClass]="{'dark': darkMode}">
+  <a mat-list-item routerLink="/" (click)="onSidenavClose()">
+    <mat-icon>home</mat-icon> <span class="nav-caption">Home</span>
+  </a>  
+  <a mat-list-item routerLink="/control" (click)="onSidenavClose()">
+    <mat-icon>settings</mat-icon><span class="nav-caption">Control</span>
+  </a>  
+  <a mat-list-item routerLink="/policy" (click)="onSidenavClose()">
+      <mat-icon>assignment</mat-icon> <span class="nav-caption">Policy</span>
+  </a>    
+</mat-nav-list>
diff --git a/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.scss b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.scss
new file mode 100644
index 0000000..72c724e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.scss
@@ -0,0 +1,36 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+a {
+    text-decoration: none;
+    color: black;
+}
+
+.dark a {
+  color: white;
+}
+
+a:hover, a:active{
+    color: lightgray;
+}
+ 
+.nav-caption{
+    display: inline-block;
+    padding-left: 6px;
+}
diff --git a/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.ts b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.ts
new file mode 100644
index 0000000..c0f05af
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/navigation/sidenav-list/sidenav-list.component.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit, Output, EventEmitter } from '@angular/core';
+import { UiService } from '../../services/ui/ui.service';
+
+@Component({
+  selector: 'rd-sidenav-list',
+  templateUrl: './sidenav-list.component.html',
+  styleUrls: ['./sidenav-list.component.scss']
+})
+export class SidenavListComponent implements OnInit {
+  darkMode: boolean;
+  @Output() sidenavClose = new EventEmitter();
+
+  constructor(public ui: UiService) { }
+
+  ngOnInit() {
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+  public onSidenavClose = () => {
+    this.sidenavClose.emit();
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.html b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.html
new file mode 100644
index 0000000..04d440c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.html
@@ -0,0 +1,82 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+<div>
+    <h3 class="rd-global-page-title">Policy Control</h3>
+
+    <table mat-table [dataSource]="policyTypesDataSource" matSort multiTemplateDataRows
+        class="policy-type-table mat-elevation-z8">
+
+        <ng-container matColumnDef="name">
+            <mat-header-cell *matHeaderCellDef mat-sort-header>Policy Type</mat-header-cell>
+            <mat-cell *matCellDef="let policyType"> 
+                 <mat-icon matTooltip="Properties">{{isInstancesShown(policyType)  ? 'expand_less' : 'expand_more'}}</mat-icon>
+                 {{getPolicyTypeName(policyType)}}
+            </mat-cell>
+        </ng-container>
+
+        <ng-container matColumnDef="description">
+            <mat-header-cell *matHeaderCellDef> Description </mat-header-cell>
+            <mat-cell *matCellDef="let policyType"> {{policyType.description}} </mat-cell>
+        </ng-container>
+
+        <ng-container matColumnDef="action">
+            <mat-header-cell class="action-cell" *matHeaderCellDef>Action </mat-header-cell>
+            <mat-cell class="action-cell" *matCellDef="let policyType" (click)="$event.stopPropagation()">               
+                <button mat-icon-button (click)="createPolicyInstance(policyType)">
+                    <mat-icon matTooltip="Create instance">add_box</mat-icon>
+                </button>
+            </mat-cell>
+        </ng-container>
+
+        <!-- =================== Policy instances for one type ======================== -->
+        <ng-container matColumnDef="instanceTableContainer">
+            <mat-cell *matCellDef="let policyType">
+                <rd-policy-instance 
+                [policyType]=policyType 
+                [expanded]=getObservable(policyType)>
+            </rd-policy-instance>
+            </mat-cell>
+        </ng-container>
+        <!-- ======= -->
+
+        <ng-container matColumnDef="noRecordsFound">
+            <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
+        </ng-container>
+
+        <mat-header-row *matHeaderRowDef="['name', 'description', 'action']"></mat-header-row>
+        <mat-row *matRowDef="let policyType; columns: ['name', 'description', 'action']"
+            (click)="toggleListInstances(policyType)">
+        </mat-row>
+
+        <mat-row *matRowDef="let policyType; columns: ['instanceTableContainer'];"
+            [@detailExpand]="isInstancesShown(policyType) ? 'expanded' : 'collapsed'" style="overflow: hidden">
+        </mat-row>
+
+        <mat-footer-row *matFooterRowDef="['noRecordsFound']"
+            [ngClass]="{'display-none': policyTypesDataSource.rowCount > 0}">
+        </mat-footer-row>
+
+    </table>
+
+    <div class="spinner-container" *ngIf="policyTypesDataSource.loading$ | async">
+        <mat-spinner diameter="50"></mat-spinner>
+    </div>
+</div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.scss b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.scss
new file mode 100644
index 0000000..f93e4ff
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.scss
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+.spinner-container {
+  height: 100px;
+  width: 100px;
+}
+
+.spinner-container mat-spinner {
+  margin: 0 auto 0 auto;
+}
+
+.policy-type-table {
+  width: 100%;
+  min-height: 150px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+  background-color: transparent;
+}
+
+.action-cell {
+      display: flex;
+      justify-content: flex-end;
+}
+
+.display-none {
+  display: none;
+}
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.spec.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.spec.ts
new file mode 100644
index 0000000..7c8643a
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { PolicyControlComponent } from './policy-control.component';
+
+describe('PolicyControlComponent', () => {
+  let component: PolicyControlComponent;
+  let fixture: ComponentFixture<PolicyControlComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ PolicyControlComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PolicyControlComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.ts
new file mode 100644
index 0000000..70b8c45
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-control.component.ts
@@ -0,0 +1,115 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
+import { MatSort } from '@angular/material/sort';
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
+
+import { PolicyService } from '../services/policy/policy.service';
+import { PolicyType } from '../interfaces/policy.types';
+import { PolicyTypeDataSource } from './policy-type.datasource';
+import { PolicyInstanceDataSource } from './policy-instance.datasource';
+import { getPolicyDialogProperties } from './policy-instance-dialog.component';
+import { PolicyInstanceDialogComponent } from './policy-instance-dialog.component';
+import { PolicyInstance } from '../interfaces/policy.types';
+import { NotificationService } from '../services/ui/notification.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
+import { Subject } from 'rxjs';
+
+class PolicyTypeInfo {
+    constructor(public type: PolicyType, public isExpanded: boolean) { }
+
+    isExpandedObservers: Subject<boolean> = new Subject<boolean>();
+};
+
+@Component({
+    selector: 'rd-policy-control',
+    templateUrl: './policy-control.component.html',
+    styleUrls: ['./policy-control.component.scss'],
+    animations: [
+        trigger('detailExpand', [
+            state('collapsed', style({ height: '0px', minHeight: '0', visibility: 'hidden' })),
+            state('expanded', style({ height: '*', visibility: 'visible' })),
+            transition('expanded <=> collapsed', animate('225ms cubic-bezier(0.4, 0.0, 0.2, 1)')),
+        ]),
+    ],
+})
+export class PolicyControlComponent implements OnInit {
+
+    policyTypesDataSource: PolicyTypeDataSource;
+    @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+    expandedTypes = new Map<string, PolicyTypeInfo>();
+
+    constructor(
+        private policySvc: PolicyService,
+        private dialog: MatDialog,
+        private errorDialogService: ErrorDialogService,
+        private notificationService: NotificationService,
+        private confirmDialogService: ConfirmDialogService) { }
+
+    ngOnInit() {
+        this.policyTypesDataSource = new PolicyTypeDataSource(this.policySvc, this.sort, this.notificationService);
+        this.policyTypesDataSource.loadTable();
+    }
+
+    createPolicyInstance(policyType: PolicyType): void {
+        const dialogRef = this.dialog.open(PolicyInstanceDialogComponent, getPolicyDialogProperties(policyType, null));
+        const info: PolicyTypeInfo = this.getPolicyTypeInfo(policyType);
+        dialogRef.afterClosed().subscribe(
+            (result: any) => {
+                info.isExpandedObservers.next(info.isExpanded);
+            }
+        );
+    }
+
+    toggleListInstances(policyType: PolicyType): void {
+        let info = this.getPolicyTypeInfo(policyType);
+        info.isExpanded = !info.isExpanded;
+        info.isExpandedObservers.next(info.isExpanded);
+    }
+
+    getPolicyTypeInfo(policyType: PolicyType): PolicyTypeInfo {
+        let info: PolicyTypeInfo = this.expandedTypes.get(policyType.name);
+        if (!info) {
+            info = new PolicyTypeInfo(policyType, false);
+            this.expandedTypes.set(policyType.name, info);
+        }
+        return info;
+    }
+
+    isInstancesShown(policyType: PolicyType): boolean {
+        return this.getPolicyTypeInfo(policyType).isExpanded;
+    }
+
+    getPolicyTypeName(type: PolicyType): string {
+        const schema = JSON.parse(type.create_schema);
+        if (schema.title) {
+            return schema.title;
+        }
+        return type.name;
+    }
+
+    getObservable(policyType: PolicyType): Subject<boolean> {
+        return this.getPolicyTypeInfo(policyType).isExpandedObservers;
+    }
+}
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.html b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.html
new file mode 100644
index 0000000..ad7ea49
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.html
@@ -0,0 +1,90 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<div class="text-muted logo" fxLayout="row" fxLayoutGap="50px">
+    <div *ngIf="policyInstanceId">{{policyInstanceId}}</div>
+</div>
+<div class="mat-elevation-z8 header row logo">
+    <div class="logo">
+        <img src="../../assets/oran-logo.png" width="30px" height="30px" style="position: relative; z-index: 50" />
+        <svg class="logo__icon" viewBox="150.3 22.2 400 50">
+            <text [ngClass]="{'logo__text-dark': darkModeActive}" class="logo__text" fill="#432c85" font-size="30"
+                font-weight="600" letter-spacing=".1em" transform="translate(149 56)">
+                <tspan>Policy editor</tspan>
+                <tspan *ngIf="jsonSchemaObject.title"> {{this.jsonSchemaObject.title}}</tspan>
+                <tspan *ngIf="!jsonSchemaObject.title"> {{this.policyTypeName}}</tspan>
+            </text>
+        </svg>
+    </div>
+</div>
+
+<!--<div class="text-muted" *ngIf="jsonSchemaObject.description">{{jsonSchemaObject.description}}</div>-->
+
+<div fxLayout="row" fxLayoutAlign="space-around start" fxLayout.lt-sm="column" fxLayoutAlign.lt-sm="flex-start center">
+    <mat-card class="card">
+        <h4 class="default-cursor" (click)="toggleVisible('form')">
+            <mat-icon matTooltip="Properties">{{isVisible.form ? 'expand_less' : 'expand_more'}}</mat-icon>
+            Properties
+        </h4>
+        <div *ngIf="isVisible.form" class="json-schema-form" [@expandSection]="true">
+            <div *ngIf="!formActive">{{jsonFormStatusMessage}}</div>
+
+            <json-schema-form *ngIf="formActive" loadExternalAssets="true" [form]="jsonSchemaObject"
+                [(data)]="jsonObject" [options]="jsonFormOptions" [framework]="'material-design'" [language]="'en'"
+                (onChanges)="onChanges($event)" (onSubmit)="onSubmit($event)" (isValid)="isValid($event)"
+                (validationErrors)="validationErrors($event)">
+            </json-schema-form>
+        </div>
+        <hr />
+        <button mat-raised-button (click)="this.onSubmit()" [disabled]="!this.formIsValid" class="submitBtn"
+            style="margin-right:10px">Submit</button>
+        <button mat-raised-button (click)="this.onClose()">Close</button>
+        <hr />
+        <h4 [class.text-danger]="!formIsValid && !isVisible.json" [class.default-cursor]="formIsValid || isVisible.json"
+            (click)="toggleVisible('json')">
+            <mat-icon matTooltip="Json">{{isVisible.json ? 'expand_less' : 'expand_more'}}</mat-icon>
+            Json
+        </h4>
+        <div *ngIf="isVisible.json" fxLayout="column" [@expandSection]="true">
+            <div>
+                <strong *ngIf="formIsValid || prettyValidationErrors" [class.text-muted]="formIsValid"
+                    [class.text-danger]="!formIsValid">
+                    {{formIsValid ? 'Json' : 'Not valid'}}
+                </strong>
+                <span *ngIf="!formIsValid && !prettyValidationErrors">Invalid form</span>
+                <span *ngIf="prettyValidationErrors">— errors:</span>
+                <div *ngIf="prettyValidationErrors" class="text-danger" [innerHTML]="prettyValidationErrors"></div>
+            </div>
+            <div>
+                <pre [class.data-good]="!prettyValidationErrors && prettyLiveFormData !== '{}'"
+                    [class.data-bad]="prettyValidationErrors">{{prettyLiveFormData}}
+                </pre>
+            </div>
+        </div>
+
+        <h4 class="default-cursor" (click)="toggleVisible('schema')">
+            <mat-icon matTooltip="Json Schema">{{isVisible.schema ? 'expand_less' : 'expand_more'}}</mat-icon>
+            Json Schema
+        </h4>
+        <div *ngIf="isVisible.schema" fxLayout="column" [@expandSection]="true">
+            <strong class="text-muted">Schema</strong>
+            <pre>{{schemaAsString}}</pre>
+        </div>
+    </mat-card>
+</div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.scss b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.scss
new file mode 100644
index 0000000..7050020
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.scss
@@ -0,0 +1,56 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+.header {
+    color: black;
+    background: linear-gradient(to right, white 0%, rgb(217, 216, 231) 100%);
+    font-size: 40px;
+    font-weight: 400;
+    margin-top: 10px;
+    margin-bottom: 10px;
+}
+
+.logo {
+    margin-left: 10px;
+}
+
+.logo__text {
+    fill: #2B244D;
+}
+  
+.logo__text-dark {
+    fill: #ffffff;
+}
+
+.logo__icon {
+    height: 2rem;
+    margin-left: 1rem;
+}
+
+.submitBtn {
+    background-color: #4CAF50; /* Green */
+}
+
+.card {
+    height: 100%;
+    width: 100%;  
+    margin-left: 10px;
+    margin-right: 1px;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.ts
new file mode 100644
index 0000000..0f483d4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance-dialog.component.ts
@@ -0,0 +1,214 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit, ViewChild, Inject, AfterViewInit, Self } from '@angular/core';
+import { MatMenuTrigger } from '@angular/material/menu';
+import { MatDialog, MatDialogConfig } from '@angular/material/dialog';
+import { trigger, state, style, animate, transition } from '@angular/animations';
+import * as uuid from 'uuid';
+
+import { JsonPointer } from 'angular6-json-schema-form';
+import { PolicyService } from '../services/policy/policy.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { NotificationService } from './../services/ui/notification.service';
+
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { PolicyType } from '../interfaces/policy.types';
+import { PolicyInstance } from '../interfaces/policy.types';
+
+@Component({
+    selector: 'rd-policy-instance-dialog',
+    templateUrl: './policy-instance-dialog.component.html',
+    styleUrls: ['./policy-instance-dialog.component.scss'],
+    animations: [
+        trigger('expandSection', [
+            state('in', style({ height: '*' })),
+            transition(':enter', [
+                style({ height: 0 }), animate(100),
+            ]),
+            transition(':leave', [
+                style({ height: '*' }),
+                animate(100, style({ height: 0 })),
+            ]),
+        ]),
+    ],
+})
+export class PolicyInstanceDialogComponent implements OnInit, AfterViewInit {
+
+    formActive = false;
+    isVisible = {
+        form: true,
+        json: false,
+        schema: false
+    };
+
+    jsonFormStatusMessage = 'Loading form...';
+    jsonSchemaObject: any = {};
+    jsonObject: any = {};
+
+
+    jsonFormOptions: any = {
+        addSubmit: false, // Add a submit button if layout does not have one
+        debug: false, // Don't show inline debugging information
+        loadExternalAssets: true, // Load external css and JavaScript for frameworks
+        returnEmptyFields: false, // Don't return values for empty input fields
+        setSchemaDefaults: true, // Always use schema defaults for empty fields
+        defautWidgetOptions: { feedback: true }, // Show inline feedback icons
+    };
+
+    liveFormData: any = {};
+    formValidationErrors: any;
+    formIsValid = false;
+
+
+    @ViewChild(MatMenuTrigger, { static: true }) menuTrigger: MatMenuTrigger;
+
+    public policyInstanceId: string;
+    public policyTypeName: string;
+    private policyTypeId: number;
+
+    constructor(
+        private dataService: PolicyService,
+        private errorService: ErrorDialogService,
+        private notificationService: NotificationService,
+        @Inject(MAT_DIALOG_DATA) private data,
+        private dialogRef: MatDialogRef<PolicyInstanceDialogComponent>) {
+        this.formActive = false;
+        this.policyInstanceId = this.data.instanceId;
+        this.policyTypeName = this.data.name;
+        this.policyTypeId = this.data.policyTypeId;
+        this.parseJson(data.createSchema, data.instanceJson);
+    }
+
+    ngOnInit() {
+        this.jsonFormStatusMessage = 'Init';
+        this.formActive = true;
+    }
+
+    ngAfterViewInit() {
+    }
+
+    onSubmit() {
+        if (this.policyInstanceId == null) {
+            this.policyInstanceId = uuid.v4();
+        }
+        const policyJson: string = this.prettyLiveFormData;
+        const self: PolicyInstanceDialogComponent = this;
+        this.dataService.putPolicy(this.policyTypeId, this.policyInstanceId, policyJson).subscribe(
+            {
+                next(value) {
+                    self.notificationService.success('Policy ' + self.policyTypeName + ':' + self.policyInstanceId + ' submitted');
+                },
+                error(error) {
+                    self.errorService.displayError('updatePolicy failed: ' + error.message);
+                },
+                complete() { }
+            });
+    }
+
+    onClose() {
+        this.dialogRef.close();
+    }
+
+    public onChanges(data: any) {
+        this.liveFormData = data;
+    }
+
+    get prettyLiveFormData() {
+        return JSON.stringify(this.liveFormData, null, 2);
+    }
+
+    get schemaAsString() {
+        return JSON.stringify(this.jsonSchemaObject, null, 2);
+    }
+
+    get jsonAsString() {
+        return JSON.stringify(this.jsonObject, null, 2);
+    }
+
+    isValid(isValid: boolean): void {
+        this.formIsValid = isValid;
+    }
+
+    validationErrors(data: any): void {
+        this.formValidationErrors = data;
+    }
+
+    get prettyValidationErrors() {
+        if (!this.formValidationErrors) { return null; }
+        const errorArray = [];
+        for (const error of this.formValidationErrors) {
+            const message = error.message;
+            const dataPathArray = JsonPointer.parse(error.dataPath);
+            if (dataPathArray.length) {
+                let field = dataPathArray[0];
+                for (let i = 1; i < dataPathArray.length; i++) {
+                    const key = dataPathArray[i];
+                    field += /^\d+$/.test(key) ? `[${key}]` : `.${key}`;
+                }
+                errorArray.push(`${field}: ${message}`);
+            } else {
+                errorArray.push(message);
+            }
+        }
+        return errorArray.join('<br>');
+    }
+
+    private parseJson(createSchema: string, instanceJson: string): void {
+        try {
+            this.jsonSchemaObject = JSON.parse(createSchema);
+            if (this.data.instanceJson != null) {
+                this.jsonObject = JSON.parse(instanceJson);
+            }
+        } catch (jsonError) {
+            this.jsonFormStatusMessage =
+                'Invalid JSON\n' +
+                'parser returned:\n\n' + jsonError;
+            return;
+        }
+    }
+
+    public toggleVisible(item: string) {
+        this.isVisible[item] = !this.isVisible[item];
+    }
+}
+
+export function getPolicyDialogProperties(policyType: PolicyType, instance: PolicyInstance): MatDialogConfig {
+    const policyTypeId = policyType.policy_type_id;
+    const createSchema = policyType.create_schema;
+    const instanceId = instance ? instance.instanceId : null;
+    const instanceJson = instance ? instance.instance : null;
+    const name = policyType.name;
+
+    return {
+        maxWidth: '1200px',
+        height: '1200px',
+        width: '900px',
+        role: 'dialog',
+        disableClose: false,
+        data: {
+            policyTypeId,
+            createSchema,
+            instanceId,
+            instanceJson,
+            name
+        }
+    };
+}
+
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.html b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.html
new file mode 100644
index 0000000..60bfab2
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.html
@@ -0,0 +1,57 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<table #table mat-table class="instances-table mat-elevation-z8" matSort  multiTemplateDataRows [dataSource]="instanceDataSource">
+
+    <ng-container matColumnDef="instanceId">
+        <mat-header-cell mat-sort-header *matHeaderCellDef >Instance</mat-header-cell>
+        <mat-cell *matCellDef="let element" (click)="modifyInstance(element)">{{element.instanceId}}
+        </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="action">
+        <mat-header-cell class="action-cell" *matHeaderCellDef>Action</mat-header-cell>
+        <mat-cell class="action-cell" *matCellDef="let instance">
+            <button mat-icon-button (click)="modifyInstance(instance)">
+                <mat-icon>edit</mat-icon>
+            </button>
+            <button mat-icon-button color="warn" (click)="deleteInstance(instance)">
+                <mat-icon>delete</mat-icon>
+            </button>
+        </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="noRecordsFound">
+        <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="['instanceId',  'action']"
+        [ngClass]="{'display-none': !this.hasInstances()}">
+    </mat-header-row>
+    <mat-row *matRowDef="let instance; columns: ['instanceId', 'action'];"></mat-row>
+
+    <mat-footer-row *matFooterRowDef="['noRecordsFound']" [ngClass]="{'display-none': this.hasInstances()}">
+    </mat-footer-row>
+
+</table>
+
+
+<div class="spinner-container" *ngIf="instanceDataSource.loading$ | async">
+    <mat-spinner diameter="50"></mat-spinner>
+</div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.scss b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.scss
new file mode 100644
index 0000000..5c1d7c3
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.scss
@@ -0,0 +1,41 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+.instances-table {
+  width: 60%; ;
+  min-height: 150px;
+  min-width: 600px;
+  margin-top: 10px;
+  margin-bottom: 10px;
+  background-color:rgb(233, 233, 240);   
+}
+
+.action-cell {
+      display: flex; 
+      justify-content: flex-end;
+}
+
+.display-none {
+  display: none;
+}
+
+.spinner-container mat-spinner {
+  margin: 0 auto 0 auto;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.ts
new file mode 100644
index 0000000..3544275
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.component.ts
@@ -0,0 +1,113 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { MatSort } from '@angular/material';
+import { Component, OnInit, ViewChild, Input, AfterViewInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { PolicyType } from '../interfaces/policy.types';
+import { PolicyInstanceDataSource } from './policy-instance.datasource';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
+import { PolicyService } from '../services/policy/policy.service';
+import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
+import { PolicyInstance } from '../interfaces/policy.types';
+import { PolicyInstanceDialogComponent } from './policy-instance-dialog.component';
+import { getPolicyDialogProperties } from './policy-instance-dialog.component';
+import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
+import { Observable } from 'rxjs';
+
+@Component({
+    selector: 'rd-policy-instance',
+    templateUrl: './policy-instance.component.html',
+    styleUrls: ['./policy-instance.component.scss']
+})
+
+
+export class PolicyInstanceComponent implements OnInit, AfterViewInit {
+    instanceDataSource: PolicyInstanceDataSource;
+    @Input() policyType: PolicyType;
+    @Input() expanded: Observable<boolean>;
+    @ViewChild(MatSort, { static: true }) sort: MatSort;
+
+    constructor(
+        private policySvc: PolicyService,
+        private dialog: MatDialog,
+        private errorDialogService: ErrorDialogService,
+        private notificationService: NotificationService,
+        private confirmDialogService: ConfirmDialogService) {
+    }
+   
+    ngOnInit() {
+        this.instanceDataSource = new PolicyInstanceDataSource(this.policySvc, this.sort, this.notificationService, this.policyType);
+        this.expanded.subscribe((isExpanded: boolean) => this.onExpand(isExpanded));
+    }
+    
+    ngAfterViewInit() {
+        this.instanceDataSource.sort = this.sort;
+    }
+
+    private onExpand(isExpanded: boolean) {
+        if (isExpanded) {
+            this.instanceDataSource.loadTable();
+        }
+    }
+
+    modifyInstance(instance: PolicyInstance): void {
+        this.policySvc.getPolicy(this.policyType.policy_type_id, instance.instanceId).subscribe(
+            (refreshedJson: any) => {
+                instance.instance = JSON.stringify(refreshedJson);
+                this.dialog.open(PolicyInstanceDialogComponent, getPolicyDialogProperties(this.policyType, instance));
+            },
+            (httpError: HttpErrorResponse) => {
+                this.notificationService.error('Could not refresh instance ' + httpError.message);
+                this.dialog.open(PolicyInstanceDialogComponent, getPolicyDialogProperties(this.policyType, instance));
+            }
+        );
+    }
+
+    hasInstances(): boolean {
+        return this.instanceDataSource.rowCount > 0;
+    }
+
+    deleteInstance(instance: PolicyInstance): void {
+        this.confirmDialogService
+            .openConfirmDialog('Are you sure you want to delete this policy instance?')
+            .afterClosed().subscribe(
+                (res: any) => {
+                    if (res) {
+                        this.policySvc.deletePolicy(this.policyType.policy_type_id, instance.instanceId)
+                            .subscribe(
+                                (response: HttpResponse<Object>) => {
+                                    switch (response.status) {
+                                        case 200:
+                                            this.notificationService.success('Delete succeeded!');
+                                            this.instanceDataSource.loadTable();
+                                            break;
+                                        default:
+                                            this.notificationService.warn('Delete failed.');
+                                    }
+                                },
+                                (error: HttpErrorResponse) => {
+                                    this.errorDialogService.displayError(error.message);
+                                });
+                    }
+                });
+    }
+}
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-instance.datasource.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.datasource.ts
new file mode 100644
index 0000000..c74c9ab
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-instance.datasource.ts
@@ -0,0 +1,100 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { DataSource } from '@angular/cdk/collections';
+import { HttpErrorResponse } from '@angular/common/http';
+import { MatSort } from '@angular/material';
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { merge } from 'rxjs';
+import { of } from 'rxjs/observable/of';
+import { catchError, finalize, map } from 'rxjs/operators';
+import { PolicyInstance } from '../interfaces/policy.types';
+import { PolicyService } from '../services/policy/policy.service';
+import { NotificationService } from '../services/ui/notification.service';
+import { PolicyType } from '../interfaces/policy.types';
+
+export class PolicyInstanceDataSource extends DataSource<PolicyInstance> {
+
+    private policyInstanceSubject = new BehaviorSubject<PolicyInstance[]>([]);
+
+    private loadingSubject = new BehaviorSubject<boolean>(false);
+
+    public loading$ = this.loadingSubject.asObservable();
+
+    public rowCount = 1; // hide footer during intial load
+
+    constructor(
+        private policySvc: PolicyService,    
+        public sort: MatSort,
+        private notificationService: NotificationService, 
+        private policyType: PolicyType) {
+        super();
+    }
+
+    loadTable() {
+        this.loadingSubject.next(true);
+        this.policySvc.getPolicyInstances(this.policyType.policy_type_id)
+            .pipe(
+                catchError((her: HttpErrorResponse) => {
+                    this.notificationService.error('Failed to get policy instances: ' + her.message);
+                    return of([]);
+                }),
+                finalize(() => this.loadingSubject.next(false))
+            )
+            .subscribe((instances: PolicyInstance[]) => {
+                this.rowCount = instances.length;
+                this.policyInstanceSubject.next(instances);
+            });
+    }
+
+    connect(): Observable<PolicyInstance[]> {
+        const dataMutations = [
+            this.policyInstanceSubject.asObservable(),
+            this.sort.sortChange
+        ];
+        return merge(...dataMutations).pipe(map(() => {
+            return this.getSortedData([...this.policyInstanceSubject.getValue()]);
+        }));
+    }
+
+    disconnect(): void {
+        this.policyInstanceSubject.complete();
+        this.loadingSubject.complete();
+    }
+
+    private getSortedData(data: PolicyInstance[]) {
+        if (!this.sort || !this.sort.active || this.sort.direction === '') {
+            return data;
+        }
+
+        return data.sort((a, b) => {
+            const isAsc = this.sort.direction === 'asc';
+            switch (this.sort.active) {
+                case 'instanceId': return compare(a.instanceId, b.instanceId, isAsc);
+                default: return 0;
+            }
+        });
+    }
+}
+
+function compare(a: string, b: string, isAsc: boolean) {  
+    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+}
diff --git a/dashboard/webapp-frontend/src/app/policy-control/policy-type.datasource.ts b/dashboard/webapp-frontend/src/app/policy-control/policy-type.datasource.ts
new file mode 100644
index 0000000..1b2b93e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/policy-control/policy-type.datasource.ts
@@ -0,0 +1,97 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { HttpErrorResponse } from '@angular/common/http';
+import { MatSort } from '@angular/material';
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { merge } from 'rxjs';
+import { of } from 'rxjs/observable/of';
+import { catchError, finalize, map } from 'rxjs/operators';
+import { PolicyType } from '../interfaces/policy.types';
+import { PolicyService } from '../services/policy/policy.service';
+import { NotificationService } from '../services/ui/notification.service';
+
+export class PolicyTypeDataSource extends DataSource<PolicyType> {
+
+    private policyTypeSubject = new BehaviorSubject<PolicyType[]>([]);
+
+    private loadingSubject = new BehaviorSubject<boolean>(false);
+
+    public loading$ = this.loadingSubject.asObservable();
+
+    public rowCount = 1; // hide footer during intial load
+
+    constructor(private policySvc: PolicyService,
+        private sort: MatSort,
+        private notificationService: NotificationService) {
+        super();
+    }
+
+    loadTable() {
+        this.loadingSubject.next(true);
+        this.policySvc.getPolicyTypes()
+            .pipe(
+                catchError((her: HttpErrorResponse) => {
+                    this.notificationService.error('Failed to get policy types: ' + her.message);
+                    return of([]);
+                }),
+                finalize(() => this.loadingSubject.next(false))
+            )
+            .subscribe((types: PolicyType[]) => {
+                this.rowCount = types.length;
+                this.policyTypeSubject.next(types);
+            });
+    }
+
+    connect(collectionViewer: CollectionViewer): Observable<PolicyType[]> {
+        const dataMutations = [
+            this.policyTypeSubject.asObservable(),
+            this.sort.sortChange
+        ];
+        return merge(...dataMutations).pipe(map(() => {
+            return this.getSortedData([...this.policyTypeSubject.getValue()]);
+        }));
+    }
+
+    disconnect(collectionViewer: CollectionViewer): void {
+        this.policyTypeSubject.complete();
+        this.loadingSubject.complete();
+    }
+
+    private getSortedData(data: PolicyType[]) {
+        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);
+                default: return 0;
+            }
+        });
+    }
+}
+
+function compare(a: any, b: any, isAsc: boolean) {
+    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+}
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html
new file mode 100644
index 0000000..0642baa
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.html
@@ -0,0 +1,54 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+<div mat-dialog-title>
+    Setup RAN Connection
+</div>
+<form [formGroup]="ranDialogForm" novalidate autocomplete="off" (ngSubmit)="setupConnection(ranDialogForm.value)">
+  <div mat-dialog-content>
+    <div name="rantype">
+      <label id="request-type-radio-group-label">RAN type:</label>
+      <mat-radio-group aria-label="RAN Type" formControlName="ranType">
+        <mat-radio-button class="ran-type-radio-button" value="endc">EN-DC</mat-radio-button>
+        <mat-radio-button class="ran-type-radio-button" value="x2">X2</mat-radio-button>
+      </mat-radio-group>
+    </div>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="RAN Name" formControlName="ranName">
+      <mat-hint align="end">Example: ABCD123456</mat-hint>
+      <mat-error *ngIf="validateControl('ranName') && hasError('ranName', 'required')">Name is required</mat-error>
+      <mat-error *ngIf="hasError('ranName', 'length')">Valid name is required</mat-error>
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="IP" formControlName="ranIp">
+      <mat-error *ngIf="validateControl('ranIp') && hasError('ranIp', 'required')">IP is required</mat-error>
+      <mat-error *ngIf="hasError('ranIp', 'pattern')">Valid IP is required</mat-error>
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Port" formControlName="ranPort">
+      <mat-error *ngIf="validateControl('ranPort') && hasError('ranPort', 'required')">Port is required</mat-error>
+      <mat-error *ngIf="hasError('ranPort', 'pattern')">Valid port number is required</mat-error>
+    </mat-form-field>
+  </div>
+  <div mat-dialog-actions class="modal-footer justify-content-center">
+    <button class="mat-raised-button" (click)="onCancel()">Cancel</button>
+    <button class="mat-raised-button mat-primary" [disabled]="!ranDialogForm.valid || processing">Connect</button>
+  </div>
+</form>
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.scss b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.scss
new file mode 100644
index 0000000..484ceb9
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.scss
@@ -0,0 +1,29 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+ /* used to place form fields on separate lines/rows in dialog */
+.input-display-block {
+  display: block;
+}
+
+/* leave a bit of space */
+.ran-type-radio-button {
+  margin-left: 5px;
+}
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts
new file mode 100644
index 0000000..ad87121
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-connection-dialog.component.ts
@@ -0,0 +1,124 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
+import { Component, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { MatDialogRef } from '@angular/material/dialog';
+import { Observable } from 'rxjs';
+import { finalize } from 'rxjs/operators';
+import { E2SetupRequest, RanDialogFormData } from '../interfaces/e2-mgr.types';
+import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { LoadingDialogService } from '../services/ui/loading-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
+
+@Component({
+  selector: 'rd-ran-control-connect-dialog',
+  templateUrl: './ran-connection-dialog.component.html',
+  styleUrls: ['./ran-connection-dialog.component.scss']
+})
+
+export class RanControlConnectDialogComponent implements OnInit {
+
+  public ranDialogForm: FormGroup;
+  public processing = false;
+
+  constructor(
+    private dialogRef: MatDialogRef<RanControlConnectDialogComponent>,
+    private service: E2ManagerService,
+    private errorService: ErrorDialogService,
+    private loadingDialogService: LoadingDialogService,
+    private notifService: NotificationService) {
+    // opens with empty fields; accepts no data to display
+  }
+
+  ngOnInit() {
+    const namePattern = /^([A-Z0-9])+$/;
+    // tslint:disable-next-line:max-line-length
+    const ipPattern = /((((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))$)|(^((([0-9A-Fa-f]{1,4}:){7}([0-9A-Fa-f]{1,4}|:))|(([0-9A-Fa-f]{1,4}:){6}(:[0-9A-Fa-f]{1,4}|((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){5}(((:[0-9A-Fa-f]{1,4}){1,2})|:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3})|:))|(([0-9A-Fa-f]{1,4}:){4}(((:[0-9A-Fa-f]{1,4}){1,3})|((:[0-9A-Fa-f]{1,4})?:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){3}(((:[0-9A-Fa-f]{1,4}){1,4})|((:[0-9A-Fa-f]{1,4}){0,2}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){2}(((:[0-9A-Fa-f]{1,4}){1,5})|((:[0-9A-Fa-f]{1,4}){0,3}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(([0-9A-Fa-f]{1,4}:){1}(((:[0-9A-Fa-f]{1,4}){1,6})|((:[0-9A-Fa-f]{1,4}){0,4}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:))|(:(((:[0-9A-Fa-f]{1,4}){1,7})|((:[0-9A-Fa-f]{1,4}){0,5}:((25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}))|:)))(%.+)?$))/;
+    const portPattern = /^([0-9]{1,4}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])$/;
+    this.ranDialogForm = new FormGroup({
+      ranType: new FormControl('endc'),
+      ranName: new FormControl('', [Validators.required, Validators.pattern(namePattern)]),
+      ranIp: new FormControl('', [Validators.required, Validators.pattern(ipPattern)]),
+      ranPort: new FormControl('', [Validators.required, Validators.pattern(portPattern)])
+    });
+  }
+
+  onCancel() {
+    this.dialogRef.close(false);
+  }
+
+  setupConnection = (ranFormValue: RanDialogFormData) => {
+    if (!this.ranDialogForm.valid) {
+      // should never happen
+      return;
+    }
+    this.processing = true;
+    const setupRequest: E2SetupRequest = {
+      ranName: ranFormValue.ranName.trim(),
+      ranIp: ranFormValue.ranIp.trim(),
+      ranPort: ranFormValue.ranPort.trim()
+    };
+    this.loadingDialogService.startLoading('Setting up connection');
+    let observable: Observable<HttpResponse<Object>>;
+    if (ranFormValue.ranType === 'endc') {
+      observable = this.service.endcSetup(setupRequest);
+    } else {
+      observable = this.service.x2Setup(setupRequest);
+    }
+    observable
+      .pipe(
+        finalize(() => this.loadingDialogService.stopLoading())
+      )
+      .subscribe(
+        (response: any) => {
+          this.processing = false;
+          this.notifService.success('Connect request sent!');
+          this.dialogRef.close(true);
+        },
+        ((her: HttpErrorResponse) => {
+          this.processing = false;
+          // the error field carries the server's response
+          let msg = her.message;
+          if (her.error && her.error.message) {
+            msg = her.error.message;
+          }
+          this.errorService.displayError('Connect request failed: ' + msg);
+          // keep the dialog open
+        })
+      );
+  }
+
+  hasError(controlName: string, errorName: string) {
+    if (this.ranDialogForm.controls[controlName].hasError(errorName)) {
+      return true;
+    }
+    return false;
+  }
+
+  validateControl(controlName: string) {
+    if (this.ranDialogForm.controls[controlName].invalid && this.ranDialogForm.controls[controlName].touched) {
+      return true;
+    }
+    return false;
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.html b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.html
new file mode 100644
index 0000000..01dd292
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.html
@@ -0,0 +1,89 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+-->
+
+<div class="ran-control__section">
+  <h3 class="rd-global-page-title">RAN Connections</h3>
+
+  <button mat-raised-button (click)="setupRANConnection()">Setup Connection..</button>
+  <button mat-raised-button color="warn" class="disconnect-all-button"
+    (click)="disconnectAllRANConnections()">Disconnect All</button>
+
+  <table mat-table class="ran-control-table mat-elevation-z8" [dataSource]="dataSource">
+
+    <ng-template #noValue></ng-template>
+
+    <ng-container matColumnDef="nbId">
+      <mat-header-cell *matHeaderCellDef>Nodeb ID</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebIdentity.globalNbId; else noValue">{{ran.nodebIdentity.globalNbId.nbId}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="nodeType">
+      <mat-header-cell *matHeaderCellDef>Node Type</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebStatus; else noValue">{{ran.nodebStatus.nodeType}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="ranName">
+      <mat-header-cell *matHeaderCellDef>RAN Name</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebIdentity; else noValue">{{ran.nodebIdentity.inventoryName}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="ranIp">
+      <mat-header-cell *matHeaderCellDef>IP</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebStatus; else noValue">{{ran.nodebStatus.ip}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="ranPort">
+      <mat-header-cell *matHeaderCellDef>Port</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebStatus; else noValue">{{ran.nodebStatus.port}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="connectionStatus">
+      <mat-header-cell *matHeaderCellDef>Connection Status</mat-header-cell>
+      <mat-cell *matCellDef="let ran">
+        <div *ngIf="ran.nodebStatus; else noValue">{{ran.nodebStatus.connectionStatus}}</div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="noRecordsFound">
+      <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns"></mat-row>
+    <mat-footer-row *matFooterRowDef="['noRecordsFound']" [ngClass]="{'display-none': dataSource.rowCount > 0}">
+    </mat-footer-row>
+
+  </table>
+
+  <div class="spinner-container" *ngIf="dataSource.loading$ | async">
+    <mat-spinner diameter=50></mat-spinner>
+  </div>
+
+</div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.scss b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.scss
new file mode 100644
index 0000000..c86d062
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.scss
@@ -0,0 +1,51 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+ .ran-control__section {
+}
+
+.disconnect-all-button {
+    float: right;
+}
+
+.ran-control-table {
+    width: 100%;
+    min-height: 100px;
+    margin-top: 10px;
+    background-color:transparent;
+}
+
+.spinner-container {
+    height: 100px;
+    width: 100px;
+}
+
+.spinner-container mat-spinner {
+    margin: 0 auto 0 auto;
+}
+
+.version__text {
+    color: gray;
+    letter-spacing: 0.1rem;
+    font-size: 10px;
+}
+
+.display-none {
+    display: none;
+}
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.spec.ts b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.spec.ts
new file mode 100644
index 0000000..aa0e8b8
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RanControlComponent } from './ran-control.component';
+
+describe('RanControlComponent', () => {
+  let component: RanControlComponent;
+  let fixture: ComponentFixture<RanControlComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ RanControlComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(RanControlComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.ts b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.ts
new file mode 100644
index 0000000..b5aba66
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-control.component.ts
@@ -0,0 +1,107 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { HttpErrorResponse } from '@angular/common/http';
+import { Component, OnInit } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { finalize } from 'rxjs/operators';
+import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
+import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { LoadingDialogService } from '../services/ui/loading-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
+import { RanControlConnectDialogComponent } from './ran-connection-dialog.component';
+import { RANControlDataSource } from './ran-control.datasource';
+import { UiService } from '../services/ui/ui.service';
+
+@Component({
+  selector: 'rd-ran-control',
+  templateUrl: './ran-control.component.html',
+  styleUrls: ['./ran-control.component.scss']
+})
+export class RanControlComponent implements OnInit {
+
+  darkMode: boolean;
+  panelClass: string = "";
+  displayedColumns: string[] = ['nbId', 'nodeType', 'ranName', 'ranIp', 'ranPort', 'connectionStatus'];
+  dataSource: RANControlDataSource;
+
+  constructor(private e2MgrSvc: E2ManagerService,
+    private errorDialogService: ErrorDialogService,
+    private confirmDialogService: ConfirmDialogService,
+    private notificationService: NotificationService,
+    private loadingDialogService: LoadingDialogService,
+    public dialog: MatDialog,
+    public ui: UiService) { }
+
+  ngOnInit() {
+    this.dataSource = new RANControlDataSource(this.e2MgrSvc, this.notificationService);
+    this.dataSource.loadTable();
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+  setupRANConnection() {
+    if (this.darkMode) {
+      this.panelClass = "dark-theme";
+    } else {
+      this.panelClass = "";
+    }
+    const dialogRef = this.dialog.open(RanControlConnectDialogComponent, {
+      panelClass: this.panelClass,
+      width: '450px'
+    });
+    dialogRef.afterClosed()
+      .subscribe((result: boolean) => {
+      if (result) {
+        this.dataSource.loadTable();
+      }
+    });
+  }
+
+  disconnectAllRANConnections() {
+    const aboutError = 'Disconnect all RAN Connections Failed: ';
+    this.confirmDialogService.openConfirmDialog('Are you sure you want to disconnect all RAN connections?')
+      .afterClosed().subscribe( (res: boolean) => {
+        if (res) {
+          this.loadingDialogService.startLoading("Disconnecting");
+          this.e2MgrSvc.nodebPut()
+            .pipe(
+              finalize(() => this.loadingDialogService.stopLoading())
+            )
+            .subscribe(
+            ( body: any ) => {
+              this.notificationService.success('Disconnect succeeded!');
+              this.dataSource.loadTable();
+            },
+            (her: HttpErrorResponse) => {
+              // the error field should have an ErrorTransport object
+              let msg = her.message;
+              if (her.error && her.error.message) {
+                msg = her.error.message;
+              }
+              this.errorDialogService.displayError('Disconnect failed: ' + msg);
+            }
+          );
+        }
+      });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/ran-control/ran-control.datasource.ts b/dashboard/webapp-frontend/src/app/ran-control/ran-control.datasource.ts
new file mode 100644
index 0000000..b23a3cd
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ran-control/ran-control.datasource.ts
@@ -0,0 +1,72 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { HttpErrorResponse } from '@angular/common/http';
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { of } from 'rxjs/observable/of';
+import { catchError, finalize } from 'rxjs/operators';
+import { E2RanDetails } from '../interfaces/e2-mgr.types';
+import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
+import { NotificationService } from '../services/ui/notification.service';
+
+export class RANControlDataSource extends DataSource<E2RanDetails> {
+
+  private ranControlSubject = new BehaviorSubject<E2RanDetails[]>([]);
+
+  private loadingSubject = new BehaviorSubject<boolean>(false);
+
+  public loading$ = this.loadingSubject.asObservable();
+
+  public rowCount = 1; // hide footer during intial load
+
+  constructor(private e2MgrSvcservice: E2ManagerService,
+    private notificationService: NotificationService) {
+    super();
+  }
+
+  loadTable() {
+    this.loadingSubject.next(true);
+    this.e2MgrSvcservice.getRan()
+      .pipe(
+        catchError( (her: HttpErrorResponse) => {
+          console.log('RANControlDataSource failed: ' + her.message);
+          this.notificationService.error('Failed to get RAN details: ' + her.message);
+          return of([]);
+        }),
+        finalize( () =>  this.loadingSubject.next(false) )
+      )
+      .subscribe( (ranControl: E2RanDetails[] ) => {
+        this.rowCount = ranControl.length;
+        this.ranControlSubject.next(ranControl);
+      });
+  }
+
+  connect(collectionViewer: CollectionViewer): Observable<E2RanDetails[]> {
+    return this.ranControlSubject.asObservable();
+  }
+
+  disconnect(collectionViewer: CollectionViewer): void {
+    this.ranControlSubject.complete();
+    this.loadingSubject.complete();
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/rd-routing.module.ts b/dashboard/webapp-frontend/src/app/rd-routing.module.ts
new file mode 100644
index 0000000..520f9a5
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd-routing.module.ts
@@ -0,0 +1,43 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * Modifications Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Routes, RouterModule } from '@angular/router';
+import { MainComponent } from './main/main.component';
+import { PolicyControlComponent} from './policy-control/policy-control.component';
+
+
+const routes: Routes = [
+    {path: '', component: MainComponent},  
+    {path: 'policy', component: PolicyControlComponent}
+];
+
+@NgModule({
+  imports: [
+      CommonModule,
+      RouterModule.forRoot(routes)],
+  exports: [
+      RouterModule
+    ],
+    declarations: []
+})
+
+export class RdRoutingModule { }
diff --git a/dashboard/webapp-frontend/src/app/rd.component.html b/dashboard/webapp-frontend/src/app/rd.component.html
new file mode 100644
index 0000000..aef2941
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd.component.html
@@ -0,0 +1,126 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<!-- Slide Menu-->
+<mat-drawer-container autosize >
+  <mat-drawer #drawer mode="push" [ngClass]="{'side-menu__dark': darkModeActive}">
+  <section class="menu-header" [ngClass]="{'menu-header__dark': darkModeActive}">
+
+    <div class="left__section3Col" *ngIf="drawer.opened"  [ngClass]="{'menumargin-top': drawer.opened}">
+      <svg (click)="drawer.toggle()" class="hamburger__icon" id="Menu_Burger_Icon" data-name="Menu Burger Icon"
+           viewBox="31.5 30 49.9 32">
+        <rect id="Rectangle_9" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 9" rx="2"
+              transform="translate(31.5 58)"/>
+        <rect id="Rectangle_10" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 10" rx="2"
+              transform="translate(31.5 44)"/>
+        <rect id="Rectangle_11" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 11" rx="2"
+              transform="translate(31.5 30)"/>
+      </svg>
+      <img src="../../assets/oran-logo.png" width="180%" height="100%" style="position: relative; z-index: 50"/>
+      <svg class="logo__icon" viewBox="150.3 22.2 400 50">
+        <text [ngClass]="{'logo__text-dark': darkModeActive}" class="logo__text" fill="#432c85"
+              font-size="30" font-weight="600"
+              letter-spacing=".1em" transform="translate(149 56)">
+          <tspan x="0" y="0">Non RT RIC Dashboard</tspan>
+        </text>
+      </svg>
+
+    </div>
+
+      <div class="profile-image__container">
+        <img src="assets/profile_default.png" alt="profile-image"
+             class="profile__image">
+      </div>
+      <div class="account-details">
+        <span class="name__text">Demo</span>
+        <span class="email__text">demo@o-ran-sc.org</span>
+      </div>
+    </section>
+    <section #sidenav class="menu-body" >
+       <rd-sidenav-list ></rd-sidenav-list>
+    </section>
+    <section class="menu-footer">
+
+    </section>
+</mat-drawer>
+
+<mat-drawer-content>
+<div class="root__container">
+
+  <header [ngClass]="{'main__header-dark': darkModeActive}" class="main__header">
+
+    <div class="left__section3Col" *ngIf="!drawer.opened">
+      <svg (click)="drawer.toggle()" class="hamburger__icon" id="Menu_Burger_Icon" data-name="Menu Burger Icon"
+           viewBox="31.5 30 49.9 32">
+        <rect id="Rectangle_9" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 9" rx="2"
+              transform="translate(31.5 58)"/>
+        <rect id="Rectangle_10" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 10" rx="2"
+              transform="translate(31.5 44)"/>
+        <rect id="Rectangle_11" width="49.9" height="4" [ngClass]="{'hamburger__icon__fill-dark': darkModeActive}"
+              class="hamburger__icon__fill" data-name="Rectangle 11" rx="2"
+              transform="translate(31.5 30)"/>
+      </svg>
+      <img src="../../assets/oran-logo.png" width="180%" height="100%" style="position: relative; z-index: 50"/>
+      <svg class="logo__icon" viewBox="150.3 22.2 400 50">
+        <text [ngClass]="{'logo__text-dark': darkModeActive}" class="logo__text" fill="#432c85"
+              font-size="30" font-weight="600"
+              letter-spacing=".1em" transform="translate(149 56)">
+          <tspan x="0" y="0">Non RT RIC Dashboard</tspan>
+        </text>
+      </svg>
+
+    </div>
+
+    <h3 class="date__text"></h3>
+
+    <div class="mode-toggle__container">
+      <span class="mode-toggle__text">Light</span>
+      <label class="toggle-button__container">
+        <input (click)="modeToggleSwitch()" type="checkbox" class="mode-toggle__input"/>
+        <span [ngClass]="{'mode-toggle__bg-checked': darkModeActive}" class="mode-toggle__bg"></span>
+        <span [ngClass]="{'mode-toggle__circle-checked': darkModeActive}" class="mode-toggle__circle"></span>
+      </label>
+      <span class="mode-toggle__text">Dark</span>
+    </div>
+
+  </header>
+
+  <!-- Main Content -->
+  <main class="main__container" [ngClass]="{'main-container__bg-dark': darkModeActive}" >
+    <div class = main__container__body [ngClass]="{'dark-theme': darkModeActive}">
+      <div class="main-container__bg"></div>
+      <router-outlet></router-outlet>
+    </div>
+  </main>
+
+  <!-- Footer -->
+  <footer class="main__footer" [ngClass]="{'main-footer__bg-dark': darkModeActive}">
+    <div class="main-footer__bg">
+      <rd-footer></rd-footer>
+    </div>
+  </footer>
+
+</div>
+</mat-drawer-content>
+</mat-drawer-container>
diff --git a/dashboard/webapp-frontend/src/app/rd.component.scss b/dashboard/webapp-frontend/src/app/rd.component.scss
new file mode 100644
index 0000000..f9e4735
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd.component.scss
@@ -0,0 +1,376 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.root__container {
+  width: 100vw;
+  height: 100vh;
+  display: grid;
+  grid-template-columns: auto;
+  grid-template-rows: 0.5fr auto;
+  position: relative;
+}
+
+/*
+================
+    Header
+================
+*/
+mat-sidenav-container, mat-sidenav-content, mat-sidenav {
+    height: 100%;
+}
+
+mat-sidenav {
+    width: 250px;
+}
+
+main {
+    padding: 10px;
+}
+
+/*
+    Slide Menu
+= = = = = = = = =
+*/
+.side-menu__dark {
+  color: white;
+  background: gray;
+}
+
+.side-menu__container {
+  position: fixed;
+  left: 0;
+  top: 0;
+  width: 100%;
+  height: 100%;
+  overflow: hidden;
+  pointer-events: none;
+  z-index: 25;
+}
+
+.side-menu__container-active {
+  pointer-events: auto;
+}
+
+.side-menu__container::before {
+  content: '';
+  cursor: pointer;
+  position: absolute;
+  display: block;
+  top: 0;
+  left: 0;
+  height: 100%;
+  width: 100%;
+  background-color: #0c1066;
+  opacity: 0;
+  transition: opacity 300ms linear;
+  will-change: opacity;
+}
+
+.side-menu__container-active::before {
+  opacity: 0.3;
+}
+
+.slide-menu {
+  box-sizing: border-box;
+  transform: translateX(-103%);
+  position: relative;
+  top: 0;
+  left: 0;
+  z-index: 10;
+  height: 100%;
+  width: 90%;
+  max-width: 26rem;
+  background-color: white;
+  box-shadow: 0 0 2rem rgba(0, 0, 255, 0.1);
+  display: grid;
+  grid-template-columns: 1fr;
+  grid-template-rows: 2fr 4fr 1fr;
+  grid-gap: 1rem;
+  transition: transform 300ms linear;
+  will-change: transform;
+}
+
+.slide-menu-active {
+  transform: none;
+}
+.menu-header.menu-header__dark {
+  background: #2B244D;
+}
+
+.menu-header {
+  background: linear-gradient(to right, rgb(181, 199, 192), #82bbb6);
+  display: grid;
+  grid-template-rows: 1fr 4fr;
+  grid-template-columns: 1fr 4fr;
+  grid-template-areas: "greeting greeting" "image details";
+  box-sizing: border-box;
+  width: 100%;
+  align-content: center;
+  color: white;
+  box-shadow: 0 0.5rem 2rem rgba(0, 0, 255, 0.2);
+}
+
+mat-drawer {
+  width: 340px;
+}
+
+mat-drawer-content {
+  overflow: overlay;
+}
+
+.menumargin-top {
+    margin-top: 10px;
+}
+
+.greeting__text {
+  grid-area: greeting;
+  font-size: 1.25rem;
+  letter-spacing: 0.15rem;
+  text-transform: uppercase;
+  margin-top: 1rem;
+  justify-self: center;
+  align-self: center;
+}
+
+.account-details {
+  grid-area: details;
+  display: flex;
+  flex-flow: column;
+  margin-left: 1rem;
+  align-self: center;
+}
+
+.name__text {
+  font-size: 1.15rem;
+  margin-bottom: 0.5rem;
+}
+
+.email__text {
+  font-size: 0.9rem;
+  letter-spacing: 0.1rem;
+}
+
+.menu-body {
+  display: grid;
+  width: 100%;
+}
+
+.profile-image__container {
+  grid-area: image;
+  margin-right: 0.5rem;
+  border-radius: 50%;
+  height: 4rem;
+  width: 4rem;
+  overflow: hidden;
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  background-color: white;
+  align-self: center;
+  margin-left: 2rem;
+}
+
+.profile__image {
+  max-width: 4rem;
+}
+
+.home_bg_image{
+    height:40em;
+    background-size:cover;
+    width:auto;
+    background-image:url('../assets/intelligence.png');
+    background-position:50% 50%;
+}
+
+/*Header*/
+.main__header {
+  width: 100%;
+  display: grid;
+  grid-template-columns: 1fr 1fr 0.25fr;
+  grid-template-rows: 1fr;
+  box-shadow: 0 0 2rem rgba(0, 0, 255, 0.1);
+  height: 4rem;
+  margin: 0;
+  align-items: center;
+  transition: background-color 500ms linear;
+  animation: fadein 1s ease-in-out 0ms 1;
+}
+
+.main__header-dark {
+  background-color: #2B244D;
+  color: white;
+}
+
+.toggle-button__container {
+  cursor: pointer;
+  position: relative;
+  margin: 0 0.5rem;
+}
+
+.mode-toggle__input {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+}
+
+.mode-toggle__bg {
+  height: 1rem;
+  width: 2rem;
+  border-radius: 0.5rem;
+  background-color: rgba(0, 0, 0, 0.5);
+  display: inline-block;
+  transition: background-color 300ms linear;
+}
+
+.mode-toggle__circle {
+  height: 1.30rem;
+  width: 1.30rem;
+  background-color: #2B244D;
+  position: absolute;
+  top: -0.2rem;
+  border-radius: 50%;
+  box-shadow: 0 0 0 rgba(0, 0, 255, 0.5);
+  transition: left 300ms linear;
+  left: 0.1rem;
+}
+
+.mode-toggle__circle-checked {
+  background-color: white;
+  left: 1.75rem;
+}
+
+.mode-toggle__bg-checked {
+  background-color: #FF0070;
+}
+
+.mode-toggle__text {
+  font-size: 0.75rem;
+  text-transform: uppercase;
+  letter-spacing: 0.1rem;
+}
+
+/*Content*/
+.left__section {
+  display: grid;
+  grid-template-rows: 1fr;
+  grid-template-columns: 1fr 1fr;
+  max-width: 5rem;
+}
+
+.left__section3Col {
+  display: grid;
+  grid-template-rows: 1fr;
+  grid-template-columns: 1fr 1fr 1fr;
+  max-width: 6rem;
+}
+
+.date__text {
+  text-transform: uppercase;
+  letter-spacing: 0.1rem;
+  display: inline;
+  margin: 0.5rem 0;
+}
+
+/*SVGs*/
+.hamburger__icon {
+  position: relative;
+  z-index: 35;
+  height: 2rem;
+  padding: 0.5rem 1.5rem;
+  margin-right: 1rem;
+  cursor: pointer;
+}
+
+.logo__icon {
+  height: 2rem;
+  margin-left: 1rem;
+}
+
+.logo__text {
+  fill: #2B244D;
+}
+
+.logo__text-dark {
+  fill: #ffffff;
+}
+
+.hamburger__icon__fill {
+  fill: #2B244D;
+}
+
+.hamburger__icon__fill-dark {
+  fill: #ffffff;
+}
+
+/*
+================
+    Body
+================
+*/
+
+.main__container {
+  height: 100%;
+  width: 100%;
+}
+
+.main__container__body {
+  min-height: calc(100vh - 140px);
+}
+
+.main-container__bg {
+  position: absolute;
+  top: 0;
+  left: 0;
+  z-index: -2;
+  opacity: 0;
+  background: white;
+  transition: opacity 300ms linear;
+}
+
+.main-container__bg-dark {
+  opacity: 1;
+  background: linear-gradient(to bottom, #B290FF, #2E1D65);
+  transition: opacity 300ms linear;
+}
+
+/*
+================-
+    Footer
+================
+*/
+.main__footer {
+  background: transparent;
+  z-index: 100;
+}
+
+.main__footer-dark {
+  background-color: #2B244D;
+  color: white;
+}
+
+.main-footer__bg-dark {
+  opacity: 1;
+  background: linear-gradient(to bottom, #B290FF, #2E1D65);
+  transition: opacity 300ms linear;
+}
+
+@media only screen and (max-width: 300px) {
+  .slide-menu {
+    width: 100%;
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/rd.component.spec.ts b/dashboard/webapp-frontend/src/app/rd.component.spec.ts
new file mode 100644
index 0000000..852386c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd.component.spec.ts
@@ -0,0 +1,54 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed, async } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+import { AppComponent } from './app.component';
+
+describe('AppComponent', () => {
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      imports: [
+        RouterTestingModule
+      ],
+      declarations: [
+        AppComponent
+      ],
+    }).compileComponents();
+  }));
+
+  it('should create the app', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app).toBeTruthy();
+  });
+
+  it(`should have as title 'dashApp'`, () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    const app = fixture.debugElement.componentInstance;
+    expect(app.title).toEqual('dashApp');
+  });
+
+  it('should render title in a h1 tag', () => {
+    const fixture = TestBed.createComponent(AppComponent);
+    fixture.detectChanges();
+    const compiled = fixture.debugElement.nativeElement;
+    expect(compiled.querySelector('h1').textContent).toContain('Welcome to dashApp!');
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/rd.component.ts b/dashboard/webapp-frontend/src/app/rd.component.ts
new file mode 100644
index 0000000..1673280
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd.component.ts
@@ -0,0 +1,49 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit } from '@angular/core';
+import { UiService } from './services/ui/ui.service';
+
+@Component({
+  selector: 'rd-root',
+  templateUrl: './rd.component.html',
+  styleUrls: ['./rd.component.scss']
+})
+export class RdComponent implements OnInit {
+  showMenu = false;
+  darkModeActive: boolean;
+
+  constructor(public ui: UiService) {
+  }
+
+  ngOnInit() {
+    this.ui.darkModeState.subscribe((value) => {
+      this.darkModeActive = value;
+    });
+  }
+
+  toggleMenu() {
+    this.showMenu = !this.showMenu;
+  }
+
+  modeToggleSwitch() {
+    this.ui.darkModeState.next(!this.darkModeActive);
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/rd.module.ts b/dashboard/webapp-frontend/src/app/rd.module.ts
new file mode 100644
index 0000000..378374a
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/rd.module.ts
@@ -0,0 +1,164 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * Modifications Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { BrowserModule } from '@angular/platform-browser';
+// tslint:disable-next-line:max-line-length
+import {MatButtonModule, MatButtonToggleModule, MatCardModule, MatCheckboxModule,
+    MatDialogModule, MatExpansionModule, MatFormFieldModule, MatGridListModule,
+    MatIconModule, MatInputModule, MatListModule, MatMenuModule, MatPaginatorModule,
+    MatProgressSpinnerModule, MatSelectModule, MatSidenavModule, MatSliderModule,
+    MatSlideToggleModule, MatSnackBarModule, MatSortModule, MatTableModule,
+    MatTabsModule,  MatToolbarModule} from '@angular/material';
+import { BrowserAnimationsModule} from '@angular/platform-browser/animations';
+import { HttpClientModule } from '@angular/common/http';
+import { NgModule } from '@angular/core';
+import { MatRadioModule } from '@angular/material/radio';
+import { MatTooltipModule } from '@angular/material/tooltip';
+import { ChartsModule } from 'ng2-charts';
+import { MDBBootstrapModule } from 'angular-bootstrap-md';
+import { FormsModule, ReactiveFormsModule } from '@angular/forms';
+import { ToastrModule } from 'ngx-toastr';
+
+import { AddDashboardUserDialogComponent } from './user/add-dashboard-user-dialog/add-dashboard-user-dialog.component';
+import { AppControlComponent } from './app-control/app-control.component';
+import { AppMgrService } from './services/app-mgr/app-mgr.service';
+import { ConfirmDialogComponent } from './ui/confirm-dialog/confirm-dialog.component';
+import { ControlComponent } from './control/control.component';
+import { DashboardService } from './services/dashboard/dashboard.service';
+import { E2ManagerService } from './services/e2-mgr/e2-mgr.service';
+import { EditDashboardUserDialogComponent } from './user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component';
+import { ErrorDialogComponent } from './ui/error-dialog/error-dialog.component';
+import { ErrorDialogService } from './services/ui/error-dialog.service';
+import { FlexLayoutModule } from '@angular/flex-layout';
+import { FooterComponent } from './footer/footer.component';
+import { LoadingDialogComponent } from './ui/loading-dialog/loading-dialog.component';
+import { MainComponent } from './main/main.component';
+import { MaterialDesignFrameworkModule } from 'angular6-json-schema-form';
+import { ModalEventComponent } from './ui/modal-event/modal-event.component';
+import { PolicyCardComponent } from './ui/policy-card/policy-card.component';
+import { PolicyControlComponent } from './policy-control/policy-control.component';
+import { PolicyInstanceComponent } from './policy-control/policy-instance.component';
+import { PolicyInstanceDialogComponent } from './policy-control/policy-instance-dialog.component';
+import { RanControlComponent } from './ran-control/ran-control.component';
+import { RanControlConnectDialogComponent } from './ran-control/ran-connection-dialog.component';
+import { RdComponent } from './rd.component';
+import { RdRoutingModule } from './rd-routing.module';
+import { SidenavListComponent } from './navigation/sidenav-list/sidenav-list.component';
+import { UiService } from './services/ui/ui.service';
+import { UserComponent } from './user/user.component';
+
+@NgModule({
+  declarations: [
+    AddDashboardUserDialogComponent,
+    AppControlComponent,
+    ConfirmDialogComponent,
+    ControlComponent,
+    EditDashboardUserDialogComponent,
+    ErrorDialogComponent,
+    FooterComponent,
+    LoadingDialogComponent,
+    MainComponent,
+    ModalEventComponent,
+    PolicyCardComponent,
+    PolicyControlComponent,
+    PolicyInstanceComponent,
+    PolicyInstanceDialogComponent,
+    RanControlComponent,
+    RanControlConnectDialogComponent,
+    RdComponent,
+    SidenavListComponent,   
+    UserComponent
+  ],
+  imports: [
+    BrowserModule,
+    BrowserAnimationsModule,
+    ChartsModule,
+    FlexLayoutModule,
+    FormsModule,
+    HttpClientModule,
+    MatButtonModule,
+    MatButtonToggleModule,
+    MatCardModule,
+    MatCheckboxModule,
+    MatDialogModule,
+    MaterialDesignFrameworkModule,
+    MatExpansionModule,
+    MatFormFieldModule,
+    MatGridListModule,
+    MatIconModule,
+    MatInputModule,
+    MatListModule,
+    MatMenuModule,
+    MatPaginatorModule,
+    MatProgressSpinnerModule,
+    MatRadioModule,
+    MatSelectModule,
+    MatSliderModule,
+    MatSidenavModule,
+    MatSlideToggleModule,
+    MatSnackBarModule,
+    MatSortModule,
+    MatTableModule,
+    MatTabsModule,
+    MatToolbarModule,
+    MatTooltipModule,
+    MDBBootstrapModule.forRoot(),
+    RdRoutingModule,
+    ReactiveFormsModule,
+    ToastrModule.forRoot()
+  ],
+  exports: [
+    ErrorDialogComponent,
+    FormsModule,
+    MatButtonModule,
+    MatButtonToggleModule,
+    MatCardModule,
+    MatDialogModule,
+    MatExpansionModule,
+    MatFormFieldModule,
+    MatGridListModule,
+    MatIconModule,
+    MatInputModule,
+    MatListModule,
+    MatSidenavModule,
+    MatSliderModule,
+    MatSlideToggleModule,
+    MatTabsModule,
+    RanControlConnectDialogComponent
+  ],
+  entryComponents: [
+    AddDashboardUserDialogComponent,
+    ConfirmDialogComponent,
+    EditDashboardUserDialogComponent,
+    ErrorDialogComponent,
+    LoadingDialogComponent,
+    PolicyInstanceDialogComponent,
+    RanControlConnectDialogComponent
+  ],
+  providers: [
+    AppMgrService,
+    DashboardService,
+    E2ManagerService,
+    ErrorDialogService,
+    UiService
+  ],
+  bootstrap: [RdComponent]
+})
+export class RdModule { }
diff --git a/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.spec.ts b/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.spec.ts
new file mode 100644
index 0000000..b3bf4d4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.spec.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed } from '@angular/core/testing';
+
+import { ACXappService } from './ac-xapp.service';
+
+describe('ACXappService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: ACXappService = TestBed.get(ACXappService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts b/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts
new file mode 100644
index 0000000..d25e9db
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ac-xapp/ac-xapp.service.ts
@@ -0,0 +1,83 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+ import { Injectable } from '@angular/core';
+ import { HttpClient } from '@angular/common/http';
+ import { Observable } from 'rxjs';
+ import { map } from 'rxjs/operators';
+import { ACAdmissionIntervalControl, ACAdmissionIntervalControlAck } from '../../interfaces/ac-xapp.types';
+import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
+
+/**
+ * Services for calling the Dashboard's A1 endpoints to get/put AC policies.
+ */
+@Injectable({
+  providedIn: 'root'
+})
+export class ACXappService {
+
+  private basePath = 'api/a1-p';
+  private policyPath = 'policies';
+  private acPolicyName = 'admission_control_policy';
+
+  private buildPath(...args: any[]) {
+    let result = this.basePath;
+    args.forEach(part => {
+      result = result + '/' + part;
+    });
+    return result;
+  }
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+  /**
+   * Gets version details
+   * @returns Observable that should yield a String
+   */
+  getVersion(): Observable<string> {
+    const url = this.buildPath('version');
+    return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+      // Extract the string here
+      map(res => res['data'])
+    );
+  }
+
+  /**
+   * Gets admission control policy.
+   * @returns Observable that should yield an ACAdmissionIntervalControl
+   */
+  getPolicy(): Observable<ACAdmissionIntervalControl> {
+    const url = this.buildPath(this.policyPath, this.acPolicyName);
+    return this.httpClient.get<ACAdmissionIntervalControl>(url);
+  }
+
+  /**
+   * Puts admission control policy.
+   * @param policy an instance of ACAdmissionIntervalControl
+   * @returns Observable that should yield a response code, no data
+   */
+  putPolicy(policy: ACAdmissionIntervalControl): Observable<any> {
+    const url = this.buildPath(this.policyPath, this.acPolicyName);
+    return this.httpClient.put<ACAdmissionIntervalControlAck>(url, policy, { observe: 'response' });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.spec.ts b/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.spec.ts
new file mode 100644
index 0000000..c47dcd8
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.spec.ts
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+ import { TestBed } from '@angular/core/testing';
+
+import { ANRXappService } from './anr-xapp.service';
+
+describe('ANRXappService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: ANRXappService = TestBed.get(ANRXappService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts b/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts
new file mode 100644
index 0000000..e06b708
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/anr-xapp/anr-xapp.service.ts
@@ -0,0 +1,136 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpParams } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
+import { ANRNeighborCellRelation, ANRNeighborCellRelationMod } from '../../interfaces/anr-xapp.types';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ANRXappService {
+
+  // Trailing slashes are confusing so omit them here
+  private basePath = 'api/xapp/anr';
+  private ncrtPath = 'ncrt';
+  private servingPath = 'servingcells';
+  private neighborPath = 'neighborcells';
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+  private buildPath(...args: any[]) {
+    let result = this.basePath;
+    args.forEach(part => {
+      result = result + '/' + part;
+    });
+    return result;
+  }
+
+  /**
+   * Gets ANR xApp client version details
+   * @returns Observable that should yield a String
+   */
+  getVersion(): Observable<string> {
+    const url = this.buildPath('version');
+    return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+      // Extract the string here
+      map(res => res['data'])
+    );
+  }
+
+  /**
+   * Performs a liveness probe
+   * @returns Observable that should yield a response code (no data)
+   */
+  getHealthAlive(): Observable<any> {
+    const url = this.buildPath('health/alive');
+    return this.httpClient.get(url, { observe: 'response' });
+  }
+
+  /**
+   * Performs a readiness probe
+   * @returns Observable that should yield a response code (no data)
+   */
+  getHealthReady(): Observable<any> {
+    const url = this.buildPath('health/ready');
+    return this.httpClient.get(url, { observe: 'response' });
+  }
+
+/**
+ * Gets array of gNodeB IDs
+ * @returns Observable that should yield a string array
+ */
+  getgNodeBs(): Observable<string[]> {
+    const url = this.buildPath('gnodebs');
+    return this.httpClient.get<string[]>(url).pipe(
+      // Extract the array of IDs here
+      map(res => res['gNodeBIds'])
+    );
+  }
+
+  /**
+   * Gets the neighbor cell relation table for all gNodeBs or based on query parameters
+   * @param ggnbId Optional parameter for the gNB ID
+   * @param servingCellNrcgi Serving cell NRCGI
+   * @param neighborCellNrpci Neighbor cell NRPCI
+   * @returns Observable of ANR neighbor cell relation array
+   */
+  getNcrtInfo(ggnodeb: string = '', servingCellNrcgi: string = '', neighborCellNrpci: string = ''): Observable<ANRNeighborCellRelation[]> {
+    const url = this.buildPath(this.ncrtPath);
+    return this.httpClient.get<ANRNeighborCellRelation[]>(url, {
+      params: new HttpParams()
+        .set('ggnodeb', ggnodeb)
+        .set('servingCellNrcgi', servingCellNrcgi)
+        .set('neighborCellNrpci', neighborCellNrpci)
+    }).pipe(
+      // Extract the array of relations here
+      map(res => res['ncrtRelations'])
+    );
+  }
+
+  /**
+   * Modify neighbor cell relation based on Serving Cell NRCGI and Neighbor Cell NRPCI
+   * @param servingCellNrcgi Serving cell NRCGI
+   * @param neighborCellNrpci Neighbor cell NRPCI
+   * @param mod Values to store in the specified relation
+   * @returns Observable that yields a response code only, no data
+   */
+  modifyNcr(servingCellNrcgi: string, neighborCellNrpci: string, mod: ANRNeighborCellRelationMod): Observable<Object> {
+    const url = this.buildPath(this.ncrtPath, this.servingPath, servingCellNrcgi, this.neighborPath, neighborCellNrpci);
+    return this.httpClient.put(url, mod, { observe: 'response' });
+  }
+
+  /**
+   * Deletes neighbor cell relation based on Serving Cell NRCGI and Neighbor Cell NRPCI
+   * @param servingCellNrcgi Serving cell NRCGI
+   * @param neighborCellNrpci Neighbor cell NRPCI
+   * @returns Observable that yields a response code only, no data
+   */
+  deleteNcr(servingCellNrcgi: string, neighborCellNrpci: string): Observable<Object> {
+    const url = this.buildPath(this.ncrtPath, this.servingPath, servingCellNrcgi, this.neighborPath, neighborCellNrpci);
+    return this.httpClient.delete(url, { observe: 'response' });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.spec.ts b/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.spec.ts
new file mode 100644
index 0000000..fcc2aaa
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.spec.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+import { AppMgrService } from './app-mgr.service';
+
+describe('AppMgrService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: AppMgrService = TestBed.get(AppMgrService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts b/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts
new file mode 100644
index 0000000..afe7a65
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts
@@ -0,0 +1,61 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpResponse } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { XMXappInfo, XMDeployableApp, XMDeployedApp } from '../../interfaces/app-mgr.types';
+
+@Injectable()
+export class AppMgrService {
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+  private basePath = 'api/appmgr';
+
+  getDeployable(): Observable<XMDeployableApp[]> {
+    return this.httpClient.get<XMDeployableApp[]>(this.basePath + '/xapps/list');
+  }
+
+  getDeployed(): Observable<XMDeployedApp[]> {
+    return this.httpClient.get<XMDeployedApp[]>(this.basePath + '/xapps');
+  }
+
+  deployXapp(name: string): Observable<HttpResponse<Object>> {
+    const xappInfo: XMXappInfo = { name: name };
+    return this.httpClient.post((this.basePath + '/xapps'), xappInfo, { observe: 'response' });
+  }
+
+  undeployXapp(name: string): Observable<HttpResponse<Object>> {
+    return this.httpClient.delete((this.basePath + '/xapps'+ '/' + name), { observe: 'response' });
+  }
+
+  getConfig(): Observable<any[]>{
+    return this.httpClient.get<any[]>("/assets/mockdata/config.json");
+    //return this.httpClient.get<any[]>((this.basePath  + '/config'));
+  }
+
+  putConfig(config: any): Observable<HttpResponse<Object>> {
+    return this.httpClient.put((this.basePath + '/config' ), config, { observe: 'response' });
+  }
+
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.spec.ts b/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.spec.ts
new file mode 100644
index 0000000..9d007ad
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.spec.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed } from '@angular/core/testing';
+
+import { CaasIngressService } from './caas-ingress.service';
+
+describe('CaasIngressService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: CaasIngressService = TestBed.get(CaasIngressService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.ts b/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.ts
new file mode 100644
index 0000000..359a08f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/caas-ingress/caas-ingress.service.ts
@@ -0,0 +1,58 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { V1PodList } from '@kubernetes/client-node';
+import { Observable } from 'rxjs';
+
+/**
+* Services for calling the Dashboard's caas-ingress endpoints to get Kubernetes details.
+*/
+@Injectable({
+  providedIn: 'root'
+})
+export class CaasIngressService {
+
+  private basePath = 'api/caas-ingress';
+  private podsPath = 'pods';
+
+  private buildPath(...args: any[]) {
+    let result = this.basePath;
+    args.forEach(part => {
+      result = result + '/' + part;
+    });
+    return result;
+  }
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+  /**
+   * Gets list of pods
+   * @returns Observable that should yield a V1PodList
+   */
+  getPodList(cluster: string, namespace: string): Observable<V1PodList> {
+    const url = this.buildPath('pods', 'cluster', cluster, 'namespace', namespace);
+    return this.httpClient.get<V1PodList>(url);
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.spec.ts b/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.spec.ts
new file mode 100644
index 0000000..606adb3
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.spec.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed } from '@angular/core/testing';
+
+import { DashboardService } from './dashboard.service';
+
+describe('DashboardService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: DashboardService = TestBed.get(DashboardService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.ts b/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.ts
new file mode 100644
index 0000000..a9f2df6
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/dashboard/dashboard.service.ts
@@ -0,0 +1,64 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { DashboardSuccessTransport, EcompUser } from '../../interfaces/dashboard.types';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+/**
+ * Services to query the dashboard's admin endpoints.
+ */
+export class DashboardService {
+
+  private basePath = 'api/admin/';
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+ /**
+   * Checks app health
+   * @returns Observable that should yield a DashboardSuccessTransport
+   */
+  getHealth(): Observable<DashboardSuccessTransport> {
+    return this.httpClient.get<DashboardSuccessTransport>(this.basePath + 'health');
+  }
+
+  /**
+   * Gets Dashboard version details
+   * @returns Observable that should yield a DashboardSuccessTransport object
+   */
+  getVersion(): Observable<DashboardSuccessTransport> {
+    return this.httpClient.get<DashboardSuccessTransport>(this.basePath + 'version');
+  }
+
+  /**
+   * Gets Dashboard users
+   * @returns Observable that should yield a EcompUser array
+   */
+  getUsers(): Observable<EcompUser[]> {
+    return this.httpClient.get<EcompUser[]>(this.basePath + 'user');
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.spec.ts b/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.spec.ts
new file mode 100644
index 0000000..b9e009c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.spec.ts
@@ -0,0 +1,33 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed } from '@angular/core/testing';
+
+import { E2ManagerService } from './e2-mgr.service';
+
+describe('CatalogService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: E2ManagerService
+   = TestBed.get(E2ManagerService
+    );
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts b/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts
new file mode 100644
index 0000000..b3388cf
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/e2-mgr/e2-mgr.service.ts
@@ -0,0 +1,83 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Injectable } from '@angular/core';
+import { HttpClient, HttpResponse } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { E2RanDetails, E2SetupRequest } from '../../interfaces/e2-mgr.types';
+import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
+
+@Injectable({
+  providedIn: 'root'
+})
+
+export class E2ManagerService {
+
+  private basePath = 'api/e2mgr/nodeb/';
+
+  constructor(private httpClient: HttpClient) {
+    // injects to variable httpClient
+  }
+
+  /**
+   * Gets E2 client version details
+   * @returns Observable that should yield a String
+   */
+  getVersion(): Observable<string> {
+    const url = this.basePath + 'version';
+    return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+      // Extract the string here
+      map(res => res['data'])
+    );
+  }
+
+  /**
+   * Gets RAN details
+   * @returns Observable that should yield an array of objects
+   */
+  getRan(): Observable<Array<E2RanDetails>> {
+    return this.httpClient.get<Array<E2RanDetails>>(this.basePath + 'ran');
+  }
+
+  /**
+   * Sends a request to setup an ENDC/gNodeB connection
+   * @returns Observable. On success there is no data, only a code.
+   */
+  endcSetup(req: E2SetupRequest): Observable<HttpResponse<Object>> {
+    return this.httpClient.post(this.basePath + 'endc-setup', req, { observe: 'response' });
+  }
+
+  /**
+   * Sends a request to setup an X2/eNodeB connection
+   * @returns Observable. On success there is no data, only a code.
+   */
+  x2Setup(req: E2SetupRequest): Observable<HttpResponse<Object>> {
+    return this.httpClient.post(this.basePath + 'x2-setup', req, { observe: 'response' });
+  }
+
+  /**
+   * Sends a request to drop all RAN connections
+   * @returns Observable with body.
+   */
+  nodebPut(): Observable<any> {
+    return this.httpClient.put((this.basePath + 'shutdown'), { observe: 'body' });
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/policy/policy.service.spec.ts b/dashboard/webapp-frontend/src/app/services/policy/policy.service.spec.ts
new file mode 100644
index 0000000..de1f4e6
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/policy/policy.service.spec.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { TestBed } from '@angular/core/testing';
+
+import { PolicyService } from './policy.service';
+
+describe('PolicyService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: PolicyService = TestBed.get(PolicyService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/policy/policy.service.ts b/dashboard/webapp-frontend/src/app/services/policy/policy.service.ts
new file mode 100644
index 0000000..1c87081
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/policy/policy.service.ts
@@ -0,0 +1,104 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpClient } from '@angular/common/http';
+import { Observable } from 'rxjs';
+import { map } from 'rxjs/operators';
+import { PolicyType, PolicyInstance, PolicyInstanceAck } from '../../interfaces/policy.types';
+import { DashboardSuccessTransport } from '../../interfaces/dashboard.types';
+
+/**
+ * Services for calling the policy endpoints.
+ */
+@Injectable({
+    providedIn: 'root'
+})
+export class PolicyService {
+
+    private basePath = 'api/policy';
+    private policyTypePath = 'policytypes';
+    private policyPath = 'policies';
+
+    private buildPath(...args: any[]) {
+        let result = this.basePath;
+        args.forEach(part => {
+            result = result + '/' + part;
+        });
+        return result;
+    }
+
+    constructor(private httpClient: HttpClient) {
+        // injects to variable httpClient
+    }
+
+    /**
+     * Gets version details
+     * @returns Observable that should yield a String
+     */
+    getVersion(): Observable<string> {
+        const url = this.buildPath('version');
+        return this.httpClient.get<DashboardSuccessTransport>(url).pipe(
+            // Extract the string here
+            map(res => res['data'])
+        );
+    }
+
+    getPolicyTypes(): Observable<PolicyType[]> {
+        const url = this.buildPath(this.policyTypePath);
+        return this.httpClient.get<PolicyType[]>(url);
+    }
+
+    getPolicyInstances(policyTypeId: number): Observable<PolicyInstance[]> {
+        const url = this.buildPath(this.policyTypePath, policyTypeId, this.policyPath);
+        return this.httpClient.get<PolicyInstance[]>(url);
+    }
+
+    /**
+     * Gets policy parameters.
+     * @returns Observable that should yield a policy instance
+     */
+    getPolicy(policyTypeId: number, policyInstanceId: string): Observable<any> {
+        const url = this.buildPath(this.policyTypePath, policyTypeId, this.policyPath, policyInstanceId);
+        return this.httpClient.get<any>(url);
+    }
+
+    /**
+     * Creates or replaces policy instance.
+     * @param policyTypeId ID of the policy type that the instance will have
+     * @param policyInstanceId ID of the instance
+     * @param policyJson Json with the policy content
+     * @returns Observable that should yield a response code, no data
+     */
+    putPolicy(policyTypeId: number, policyInstanceId: string, policyJson: string): Observable<any> {
+        const url = this.buildPath(this.policyTypePath, policyTypeId, this.policyPath, policyInstanceId);
+        return this.httpClient.put<PolicyInstanceAck>(url, policyJson, { observe: 'response' });
+    }
+
+    /**
+     * Deletes a policy instance.
+     * @param policyTypeId
+     * @returns Observable that should yield a response code, no data
+     */
+    deletePolicy(policyTypeId: number, policyInstanceId: string): Observable<any> {
+        const url = this.buildPath(this.policyTypePath, policyTypeId, this.policyPath, policyInstanceId);
+        return this.httpClient.delete(url, { observe: 'response' });
+    }
+}
diff --git a/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.spec.ts b/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.spec.ts
new file mode 100644
index 0000000..e7a115e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.spec.ts
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { ConfirmDialogService } from './confirm-dialog.service';
+
+describe('ConfirmDialogService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: ConfirmDialogService = TestBed.get(ConfirmDialogService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts b/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts
new file mode 100644
index 0000000..297e673
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/confirm-dialog.service.ts
@@ -0,0 +1,55 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { ConfirmDialogComponent } from './../../ui/confirm-dialog/confirm-dialog.component';
+import { UiService } from './ui.service';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class ConfirmDialogService  {
+
+  darkMode: boolean;
+  panelClass: string = "";
+
+  constructor(private dialog: MatDialog,
+    public ui: UiService) { }
+
+  openConfirmDialog(msg: string) {
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+    if (this.darkMode) {
+      this.panelClass = "dark-theme";
+    } else {
+      this.panelClass = "";
+    }
+    return this.dialog.open(ConfirmDialogComponent, {
+      panelClass: this.panelClass,
+      width: '480px',
+      position: { top: '100px' },
+      data: {
+        message: msg
+      }
+    });
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/services/ui/error-dialog.service.ts b/dashboard/webapp-frontend/src/app/services/ui/error-dialog.service.ts
new file mode 100644
index 0000000..a5a12f4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/error-dialog.service.ts
@@ -0,0 +1,53 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { ErrorDialogComponent } from '../../ui/error-dialog/error-dialog.component';
+import { HttpErrorResponse } from '@angular/common/http';
+import { MatDialog } from '@angular/material/dialog';
+import { Injectable } from '@angular/core';
+import { UiService } from './ui.service';
+
+@Injectable()
+export class ErrorDialogService {
+
+  darkMode: boolean;
+  panelClass: string = "";
+  public errorMessage: string = '';
+
+  constructor(private dialog: MatDialog,
+    public ui: UiService) { }
+
+  public displayError(error: string) {
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+    if (this.darkMode) {
+      this.panelClass = "dark-theme";
+    } else {
+      this.panelClass = "";
+    }
+    return this.dialog.open(ErrorDialogComponent, {
+      panelClass: this.panelClass,
+      width: '400px',
+      position: { top: '100px' },
+      disableClose: true,
+      data: { 'errorMessage': error }
+    });
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.spec.ts b/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.spec.ts
new file mode 100644
index 0000000..a73be7c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.spec.ts
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { LoadingDialogService } from './loading-dialog.service';
+
+describe('LoadingDialogService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: LoadingDialogService = TestBed.get(LoadingDialogService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.ts b/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.ts
new file mode 100644
index 0000000..bf0830a
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/loading-dialog.service.ts
@@ -0,0 +1,65 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { MatDialog, MatDialogRef } from '@angular/material/dialog';
+import { LoadingDialogComponent } from './../../ui/loading-dialog/loading-dialog.component';
+import { UiService } from './ui.service';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class LoadingDialogService {
+
+  darkMode: boolean;
+  panelClass: string = "";
+
+  constructor(private dialog: MatDialog,
+    public ui: UiService) { }
+
+  private loadingDialogRef: MatDialogRef<LoadingDialogComponent>;
+
+  startLoading(msg: string) {
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+    if (this.darkMode) {
+      this.panelClass = "dark-theme";
+    } else {
+      this.panelClass = "";
+    }
+    this.loadingDialogRef = this.dialog.open(LoadingDialogComponent, {
+      panelClass: this.panelClass,
+      disableClose: true,
+      width: '480px',
+      position: { top: '100px' },
+      data: {
+        message: msg
+      }
+    });
+  }
+
+  stopLoading() {
+    this.loadingDialogRef.close()
+  }
+
+}
+
+
diff --git a/dashboard/webapp-frontend/src/app/services/ui/notification.service.spec.ts b/dashboard/webapp-frontend/src/app/services/ui/notification.service.spec.ts
new file mode 100644
index 0000000..9704720
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/notification.service.spec.ts
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { TestBed } from '@angular/core/testing';
+
+import { NotificationService } from './notification.service';
+
+describe('NotificationService', () => {
+  beforeEach(() => TestBed.configureTestingModule({}));
+
+  it('should be created', () => {
+    const service: NotificationService = TestBed.get(NotificationService);
+    expect(service).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/services/ui/notification.service.ts b/dashboard/webapp-frontend/src/app/services/ui/notification.service.ts
new file mode 100644
index 0000000..c7fe03f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/notification.service.ts
@@ -0,0 +1,58 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Injectable } from '@angular/core';
+import { ToastrService } from 'ngx-toastr';
+
+@Injectable({
+  providedIn: 'root'
+})
+export class NotificationService {
+
+  constructor(public toastr: ToastrService) { }
+
+  successConfig = {
+    timeOut: 10000,
+    closeButton: true
+  };
+
+  warningConfig = {
+    disableTimeOut: true,
+    closeButton: true
+  };
+
+  errorConfig = {
+    disableTimeOut: true,
+    closeButton: true
+  };
+
+  success(msg: string) {
+    this.toastr.success(msg, '', this.successConfig);
+  }
+
+  warn(msg: string) {
+    this.toastr.warning(msg, '', this.warningConfig);
+  }
+
+  error(msg: string) {
+    this.toastr.error(msg, '', this.errorConfig);
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/services/ui/ui.service.spec.ts b/dashboard/webapp-frontend/src/app/services/ui/ui.service.spec.ts
new file mode 100644
index 0000000..3df0e9c
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/ui.service.spec.ts
@@ -0,0 +1,34 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import {inject, TestBed} from '@angular/core/testing';
+
+import {UiService} from './ui.service';
+
+describe('UiService', () => {
+  beforeEach(() => {
+    TestBed.configureTestingModule({
+      providers: [UiService]
+    });
+  });
+
+  it('should be created', inject([UiService], (service: UiService) => {
+    expect(service).toBeTruthy();
+  }));
+});
diff --git a/dashboard/webapp-frontend/src/app/services/ui/ui.service.ts b/dashboard/webapp-frontend/src/app/services/ui/ui.service.ts
new file mode 100644
index 0000000..1e2376a
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/services/ui/ui.service.ts
@@ -0,0 +1,32 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import {Injectable} from '@angular/core';
+import {BehaviorSubject} from 'rxjs';
+
+@Injectable()
+export class UiService {
+
+  darkModeState: BehaviorSubject<boolean>;
+
+  constructor() {
+    // TODO: if the user is signed in get the default value from Firebase
+    this.darkModeState = new BehaviorSubject<boolean>(false);
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.html b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.html
new file mode 100644
index 0000000..7e86ba0
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.html
@@ -0,0 +1,29 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+  <div mat-dialog-title>
+  </div>
+  <div mat-dialog-content>
+    {{data.message}}
+  </div>
+  <div mat-dialog-actions class="modal-footer justify-content-center">
+    <button mat-button class="mat-raised-button" [mat-dialog-close]="false">Cancel</button>
+    <button mat-button class="mat-raised-button mat-primary" [mat-dialog-close]="true">OK</button>
+  </div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.spec.ts b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.spec.ts
new file mode 100644
index 0000000..1edce02
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.spec.ts
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ConfirmDialogComponent } from './confirm-dialog.component';
+
+describe('ConfirmDialogComponent', () => {
+  let component: ConfirmDialogComponent;
+  let fixture: ComponentFixture<ConfirmDialogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ConfirmDialogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ConfirmDialogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.ts b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.ts
new file mode 100644
index 0000000..3d99530
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/confirm-dialog/confirm-dialog.component.ts
@@ -0,0 +1,39 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Component, OnInit, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+
+@Component({
+  selector: 'rd-confirm-dialog',
+  templateUrl: './confirm-dialog.component.html',
+})
+export class ConfirmDialogComponent implements OnInit {
+
+  constructor(@Inject(MAT_DIALOG_DATA) public data,
+    public dialogRef: MatDialogRef<ConfirmDialogComponent>) { }
+
+  ngOnInit() {
+  }
+
+  closeDialog() {
+    this.dialogRef.close(false);
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.html b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.html
new file mode 100644
index 0000000..8516b94
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.html
@@ -0,0 +1,27 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+  
+  <div mat-dialog-content style="overflow-y: hidden;overflow:auto;">
+    <div class="error_message_text">{{data.errorMessage}}</div>    
+  </div>
+  <div mat-dialog-actions class="justify-content-center">
+    <button mat-button class="mat-raised-button mat-primary" (click)="closeDialog()">Close</button>
+  </div> 
+
diff --git a/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.scss b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.scss
new file mode 100644
index 0000000..23de19e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.scss
@@ -0,0 +1,25 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+ .error_message_text {
+    overflow-y: overlay; 
+    max-height: 150px;
+ }
+ 
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.ts b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.ts
new file mode 100644
index 0000000..1636c0d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/error-dialog/error-dialog.component.ts
@@ -0,0 +1,41 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog';
+
+export interface ErrorData {
+  errorMessage: string;
+}
+
+@Component({
+  selector: 'rd-error-dialog',
+  templateUrl: './error-dialog.component.html',
+  styleUrls: ['./error-dialog.component.scss']
+})
+
+export class ErrorDialogComponent {
+
+  constructor(private dialogRef: MatDialogRef<ErrorDialogComponent>,
+    @Inject(MAT_DIALOG_DATA) public data: ErrorData) { }
+
+  public closeDialog = () => {
+    this.dialogRef.close();
+  }
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.html b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.html
new file mode 100644
index 0000000..75d6e59
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.html
@@ -0,0 +1,27 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+
+
+  <div mat-dialog-content>
+    {{data.message}}
+  </div>
+  <mat-spinner diameter=70></mat-spinner>
+
+
diff --git a/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.scss b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.scss
new file mode 100644
index 0000000..fb66930
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.scss
@@ -0,0 +1,23 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+mat-spinner {
+  margin: 10px
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.spec.ts b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.spec.ts
new file mode 100644
index 0000000..40fa832
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.spec.ts
@@ -0,0 +1,45 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { LoadingDialogComponent } from './loading-dialog.component';
+
+describe('LoadingDialogComponent', () => {
+  let component: LoadingDialogComponent;
+  let fixture: ComponentFixture<LoadingDialogComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ LoadingDialogComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(LoadingDialogComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.ts b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.ts
new file mode 100644
index 0000000..c78ae4e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/loading-dialog/loading-dialog.component.ts
@@ -0,0 +1,36 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Component, OnInit, Inject } from '@angular/core';
+import { MAT_DIALOG_DATA } from '@angular/material/dialog';
+
+@Component({
+  selector: 'rd-loading-dialog',
+  templateUrl: './loading-dialog.component.html',
+  styleUrls: ['./loading-dialog.component.scss']
+})
+export class LoadingDialogComponent implements OnInit {
+
+  constructor(@Inject(MAT_DIALOG_DATA) public data) { }
+
+  ngOnInit() {
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.html b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.html
new file mode 100644
index 0000000..197561f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.html
@@ -0,0 +1,70 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<button type="button" mdbBtn color="default" rounded="true" data-toggle="modal" data-target="#basicExample"
+  (click)="frame.show()" mdbWavesEffect>Deploy</button>
+
+<div mdbModal #frame="mdbModal" class="modal fade left" id="frameModalTop" tabindex="-1" role="dialog"
+  aria-labelledby="myModalLabel" aria-hidden="true" (opened)="onOpened($event)">
+  <div class="modal-dialog modal-notify modal-info modal-side modal-top-left" role="document">
+    <!--Content-->
+    <div class="modal-content">
+      <!--Header-->
+      <div class="modal-header">
+        <p class="heading lead">xApp Info</p>
+
+        <button type="button" class="close" data-dismiss="modal" aria-label="Close" (click)="frame.hide()">
+          <span aria-hidden="true" class="white-text">&times;</span>
+        </button>
+      </div>
+
+      <!--Body-->
+      <div class="modal-body">
+
+        <img src="../../../assets/intelligence.png" alt=""
+          class="img-fluid">
+
+        <div class="text-center">
+          <p>xApp Manager Params</p>
+            <div class="md-form">
+                <textarea type="text" id="form8" class="md-textarea form-control" rows="1" mdbInput
+                    [formControl]="contactFormModalHelm"></textarea>
+                <label data-error="wrong" data-success="right" for="form8">Delay</label>
+            </div>
+            <div class="md-form">
+                <textarea type="text" id="form8" class="md-textarea form-control" rows="1" mdbInput
+                    [formControl]="contactFormModalHelm"></textarea>
+                <label data-error="wrong" data-success="right" for="form8">Load</label>
+            </div>
+        </div>
+      </div>
+
+      <!--Footer-->
+      <div class="modal-footer justify-content-center">
+        <a type="button" mdbBtn color="primary" class="waves-effect" mdbWavesEffect>
+            <mat-icon style="vertical-align: -21%;">launch</mat-icon> Deploy
+        </a>
+        <a type="button" mdbBtn color="primary" outline="true" class="waves-effect" mdbWavesEffect (click)="frame.hide()"
+          data-dismiss="modal">
+          <mat-icon style="vertical-align: -21%; size: 1em">close</mat-icon> Cancel</a>
+      </div>
+    </div>
+    <!--/.Content-->
+  </div>
+</div>
diff --git a/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.scss b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.scss
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.scss
diff --git a/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.spec.ts b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.spec.ts
new file mode 100644
index 0000000..0e4cf9d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ModalEventComponent } from './modal-event.component';
+
+describe('ModalEventComponent', () => {
+  let component: ModalEventComponent;
+  let fixture: ComponentFixture<ModalEventComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ ModalEventComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(ModalEventComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.ts b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.ts
new file mode 100644
index 0000000..18f5163
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/modal-event/modal-event.component.ts
@@ -0,0 +1,55 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, Input, OnInit , Output, EventEmitter  } from '@angular/core';
+import { FormControl, Validators } from '@angular/forms';
+
+@Component({
+  selector: 'rd-modal-event',
+  templateUrl: './modal-event.component.html',
+  styleUrls: ['./modal-event.component.scss']
+})
+export class ModalEventComponent implements OnInit {
+
+    public renderValue;
+
+    @Input() value;
+    @Input() rowData: any;
+    @Output() save: EventEmitter<any> = new EventEmitter();
+    contactFormModalHelm = new FormControl('', Validators.required);
+    onOpened(event: any) {
+    console.log(event);
+    }
+
+
+    constructor() {  }
+
+    ngOnInit() {
+        this.renderValue = this.value;
+    }
+
+    example() {
+        alert(this.renderValue);
+    }
+
+    onDeployxApp() {
+        this.save.emit(this.rowData);
+    }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.html b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.html
new file mode 100644
index 0000000..2c82628
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.html
@@ -0,0 +1,31 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 Nordix Foundation
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<div class="policy__card" routerLink="/policy" [ngClass]="{'add__card-dark': darkMode}">
+  <div class="header__container">
+    <span class="card__title">Policy Control</span><br><br><br>
+    <div style="color: black; size: 1em; text-align: center">
+        <mat-icon>build</mat-icon>Config</div>
+
+
+  </div>
+  <div class="body__container">
+    <img src="../../../assets/policy.png" width="250px"/>
+  </div>
+</div>
diff --git a/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.scss b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.scss
new file mode 100644
index 0000000..1b3c349
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.scss
@@ -0,0 +1,58 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.policy__card {
+  background-color: #ffffff;
+  box-shadow: 0 0 2rem rgba(0, 0, 255, 0.1);
+  display: grid;
+  grid-template-columns: 1fr;
+  grid-template-rows: 1fr 1fr;
+  padding: 2rem;
+  margin: 2rem;
+  width: 19rem;
+  height: 30rem;
+  justify-items: center;
+  cursor: pointer;
+  border-radius: 1.75rem;
+  animation: fadein 1.25s ease-in-out 0ms 1;
+  color: #443282;
+}
+
+.add__card-dark {
+  background: linear-gradient(to bottom, #711B86, #00057A);
+  color: white;
+}
+
+.card__title {
+  text-transform: uppercase;
+  letter-spacing: 0.1rem;
+}
+
+.body__container {
+  align-self: end;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  flex-flow: column;
+}
+
+.add__icon {
+  width: 10rem;
+  margin-bottom: 1.15rem;
+}
diff --git a/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.spec.ts b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.spec.ts
new file mode 100644
index 0000000..eb678a9
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import {async, ComponentFixture, TestBed} from '@angular/core/testing';
+
+import {PolicyCardComponent} from './policy-card.component';
+
+describe('PolicyCardComponent', () => {
+  let component: PolicyCardComponent;
+  let fixture: ComponentFixture<PolicyCardComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [PolicyCardComponent]
+    })
+      .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(PolicyCardComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.ts b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.ts
new file mode 100644
index 0000000..174af1d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/ui/policy-card/policy-card.component.ts
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 Nordix Foundation
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import {Component, OnDestroy, OnInit} from '@angular/core';
+import {Router} from '@angular/router';
+import {UiService} from '../../services/ui/ui.service';
+
+@Component({
+  selector: 'rd-policy-card',
+  templateUrl: './policy-card.component.html',
+  styleUrls: ['./policy-card.component.scss']
+})
+export class PolicyCardComponent implements OnInit, OnDestroy {
+  darkMode: boolean;
+
+  constructor(public router: Router, public ui: UiService) { }
+
+  ngOnInit() {
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+  ngOnDestroy() { }
+
+  openDetails() {
+    this.router.navigateByUrl('../../policy');
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.html b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.html
new file mode 100644
index 0000000..ef29a83
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.html
@@ -0,0 +1,44 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+-->
+<div mat-dialog-title>
+  Add Dashboard User
+</div>
+
+<form [formGroup]="addUserDialogForm" novalidate autocomplete="off">
+  <div mat-dialog-content>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="First Name" formControlName="firstName">
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Last Name" formControlName="lastName">
+    </mat-form-field>
+  </div>
+  <div name="status">
+    <label id="request-type-radio-group-label">Status:</label>
+    <mat-radio-group aria-label="status" formControlName="status">
+      <mat-radio-button value="Active">Active</mat-radio-button>
+      <mat-radio-button value="Inactive">Inactive</mat-radio-button>
+    </mat-radio-group>
+  </div>
+  <div mat-dialog-actions class="modal-footer justify-content-center">
+    <button class="mat-raised-button" (click)="onCancel()">Cancel</button>
+    <button class="mat-raised-button mat-primary" [disabled]="!addUserDialogForm.valid" (click)="addUser(addUserDialogForm.value)" >Add</button>
+  </div>
+</form>
diff --git a/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.scss b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.scss
new file mode 100644
index 0000000..9717962
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.scss
@@ -0,0 +1,23 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+.input-display-block {
+    display: block;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.ts b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.ts
new file mode 100644
index 0000000..faca105
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/add-dashboard-user-dialog/add-dashboard-user-dialog.component.ts
@@ -0,0 +1,61 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Component, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { MatDialogRef } from '@angular/material/dialog';
+import { DashboardService } from '../../services/dashboard/dashboard.service';
+import { ErrorDialogService } from '../../services/ui/error-dialog.service';
+
+@Component({
+  selector: 'add-dashboard-user-dialog',
+  templateUrl: './add-dashboard-user-dialog.component.html',
+  styleUrls: ['./add-dashboard-user-dialog.component.scss']
+})
+export class AddDashboardUserDialogComponent implements OnInit {
+
+  public addUserDialogForm: FormGroup;
+
+  constructor(
+    private dialogRef: MatDialogRef<AddDashboardUserDialogComponent>,
+    private dashSvc: DashboardService,
+    private errorService: ErrorDialogService) { }
+
+  ngOnInit() {
+    this.addUserDialogForm = new FormGroup({
+      firstName: new FormControl('', [Validators.required]),
+      lastName: new FormControl('', [Validators.required]),
+      status: new FormControl('', [Validators.required])
+    });
+  }
+
+  onCancel() {
+    this.dialogRef.close(false);
+  }
+
+  public addUser = (FormValue) => {
+    if (this.addUserDialogForm.valid) {
+      // send the request to backend when it's ready
+      const aboutError = 'Not implemented yet';
+      this.errorService.displayError(aboutError);
+    }
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.html b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.html
new file mode 100644
index 0000000..f64d9df
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.html
@@ -0,0 +1,44 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+-->
+<div mat-dialog-title>
+  Edit Dashboard User
+</div>
+  
+<form [formGroup]="editUserDialogForm" novalidate autocomplete="off">
+  <div mat-dialog-content>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="First Name" formControlName="firstName" >
+    </mat-form-field>
+    <mat-form-field class="input-display-block">
+      <input matInput type="text" placeholder="Last Name" formControlName="lastName" >
+    </mat-form-field>
+  </div>
+  <div name="status">
+    <label id="request-type-radio-group-label">Status:</label>
+    <mat-radio-group aria-label="status" formControlName="status">
+      <mat-radio-button value="Active">Active</mat-radio-button>
+      <mat-radio-button value="Inactive">Inactive</mat-radio-button>
+    </mat-radio-group>
+  </div>
+  <div mat-dialog-actions class="modal-footer justify-content-center">
+    <button class="mat-raised-button" (click)="onCancel()">Cancel</button>
+    <button class="mat-raised-button mat-primary" [disabled]="!editUserDialogForm.valid" (click)="editUser(editUserDialogForm.value)">Update</button>
+  </div>
+</form>
diff --git a/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.scss b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.scss
new file mode 100644
index 0000000..9717962
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.scss
@@ -0,0 +1,23 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+.input-display-block {
+    display: block;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.ts b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.ts
new file mode 100644
index 0000000..aef8860
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component.ts
@@ -0,0 +1,63 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { Component, Inject, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { DashboardService } from '../../services/dashboard/dashboard.service';
+import { ErrorDialogService } from '../../services/ui/error-dialog.service';
+
+
+@Component({
+  selector: 'rd-edit-app-dashboard-user-dialog',
+  templateUrl: './edit-dashboard-user-dialog.component.html',
+  styleUrls: ['./edit-dashboard-user-dialog.component.scss']
+})
+export class EditDashboardUserDialogComponent implements OnInit {
+
+  public editUserDialogForm: FormGroup;
+
+  constructor(
+    @Inject(MAT_DIALOG_DATA) public data,
+    private dialogRef: MatDialogRef<EditDashboardUserDialogComponent>,
+    private dashSvc: DashboardService,
+    private errorService: ErrorDialogService) { }
+
+  ngOnInit() {
+    this.editUserDialogForm = new FormGroup({
+      firstName: new FormControl(this.data.firstName , [Validators.required]),
+      lastName: new FormControl(this.data.lastName, [Validators.required]),
+      status: new FormControl(this.data.status, [Validators.required])
+    });
+  }
+
+  onCancel() {
+    this.dialogRef.close(false);
+  }
+
+  public editUser = (FormValue) => {
+    if (this.editUserDialogForm.valid) {
+      // send the request to backend when it's ready
+      const aboutError = 'Not implemented yet';
+      this.errorService.displayError(aboutError);
+    }
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/app/user/user.component.html b/dashboard/webapp-frontend/src/app/user/user.component.html
new file mode 100644
index 0000000..5bffc79
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/user.component.html
@@ -0,0 +1,76 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+-->
+<div class="user__section">
+  <h3 class="rd-global-page-title">Users</h3>
+  <button mat-raised-button (click)="addUser()">Add User</button>
+  <div class="spinner-container" *ngIf="dataSource.loading$ | async">
+    <mat-spinner></mat-spinner>
+  </div>
+  <table mat-table [dataSource]="dataSource" matSort class="user-table mat-elevation-z8">
+
+    <ng-container matColumnDef="loginId">
+      <mat-header-cell *matHeaderCellDef mat-sort-header> Login ID </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.loginId}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="firstName">
+      <mat-header-cell *matHeaderCellDef mat-sort-header> First Name </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.firstName}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="lastName">
+      <mat-header-cell *matHeaderCellDef mat-sort-header> Last Name </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.lastName}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="active">
+      <mat-header-cell *matHeaderCellDef mat-sort-header> Active? </mat-header-cell>
+      <mat-cell *matCellDef="let element"> {{element.active}} </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="action">
+      <mat-header-cell *matHeaderCellDef> Action </mat-header-cell>
+      <mat-cell *matCellDef="let element">
+        <div class="user-button-row">
+          <button mat-icon-button (click)="editUser(element)">
+            <mat-icon matTooltip="Edit properties">edit</mat-icon>
+          </button>
+          <button mat-icon-button color="warn" (click)="deleteUser(element)">
+            <mat-icon matTooltip="Delete user">delete</mat-icon>
+          </button>
+        </div>
+      </mat-cell>
+    </ng-container>
+
+    <ng-container matColumnDef="noRecordsFound">
+      <mat-footer-cell *matFooterCellDef>No records found.</mat-footer-cell>
+    </ng-container>
+
+    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
+    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
+    <mat-footer-row *matFooterRowDef="['noRecordsFound']" [ngClass]="{'display-none': dataSource.rowCount > 0}"></mat-footer-row>
+
+  </table>
+
+  <div class="spinner-container" *ngIf="dataSource.loading$ | async">
+    <mat-spinner diameter=50></mat-spinner>
+  </div>
+
+</div>
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/app/user/user.component.scss b/dashboard/webapp-frontend/src/app/user/user.component.scss
new file mode 100644
index 0000000..f3a5d89
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/user.component.scss
@@ -0,0 +1,46 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+.user__section {
+}
+
+.spinner-container {
+    height: 360px;
+    width: 390px;
+    position: fixed;
+}
+
+.spinner-container mat-spinner {
+    margin: 130px auto 0 auto;
+}
+
+.user-table {
+    width: 99%;
+    min-height: 150px;
+    margin-top: 10px;
+    background-color: transparent;
+}
+
+.user-button-row button {
+    margin-right: 5px;
+}
+
+.display-none {
+    display: none;
+}
diff --git a/dashboard/webapp-frontend/src/app/user/user.component.spec.ts b/dashboard/webapp-frontend/src/app/user/user.component.spec.ts
new file mode 100644
index 0000000..d4d822e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/user.component.spec.ts
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { UserComponent } from './user.component';
+
+describe('UserComponent', () => {
+  let component: AdminComponent;
+  let fixture: ComponentFixture<UserComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [UserComponent]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(UserComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/dashboard/webapp-frontend/src/app/user/user.component.ts b/dashboard/webapp-frontend/src/app/user/user.component.ts
new file mode 100644
index 0000000..a3573c0f
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/user.component.ts
@@ -0,0 +1,97 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { Component, OnInit, ViewChild } from '@angular/core';
+import { MatDialog } from '@angular/material/dialog';
+import { MatSort } from '@angular/material/sort';
+import { DashboardService } from '../services/dashboard/dashboard.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { EcompUser } from './../interfaces/dashboard.types';
+import { NotificationService } from './../services/ui/notification.service';
+import { UserDataSource } from './user.datasource';
+import { AddDashboardUserDialogComponent } from './add-dashboard-user-dialog/add-dashboard-user-dialog.component';
+import { EditDashboardUserDialogComponent } from './edit-dashboard-user-dialog/edit-dashboard-user-dialog.component';
+import { UiService } from '../services/ui/ui.service';
+
+@Component({
+  selector: 'rd-user',
+  templateUrl: './user.component.html',
+  styleUrls: ['./user.component.scss']
+})
+
+export class UserComponent implements OnInit {
+
+  darkMode: boolean;
+  panelClass: string = "";
+  displayedColumns: string[] = ['loginId', 'firstName', 'lastName', 'active', 'action'];
+  dataSource: UserDataSource;
+  @ViewChild(MatSort, {static: true}) sort: MatSort;
+
+  constructor(
+    private dashboardSvc: DashboardService,
+    private errorService: ErrorDialogService,
+    private notificationService: NotificationService,
+    public dialog: MatDialog,
+    public ui: UiService) { }
+
+  ngOnInit() {
+    this.dataSource = new UserDataSource(this.dashboardSvc, this.sort, this.notificationService);
+    this.dataSource.loadTable();
+    this.ui.darkModeState.subscribe((isDark) => {
+      this.darkMode = isDark;
+    });
+  }
+
+  editUser(user: EcompUser) {
+    if (this.darkMode) {
+      this.panelClass = "dark-theme"
+    } else {
+      this.panelClass = "";
+    }
+    const dialogRef = this.dialog.open(EditDashboardUserDialogComponent, {
+      panelClass: this.panelClass,
+      width: '450px',
+      data: user
+    });
+    dialogRef.afterClosed().subscribe(result => {
+      this.dataSource.loadTable();
+    });
+  }
+
+  deleteUser() {
+    const aboutError = 'Not implemented (yet).';
+    this.errorService.displayError(aboutError);
+  }
+
+  addUser() {
+    if (this.darkMode) {
+      this.panelClass = "dark-theme"
+    } else {
+      this.panelClass = "";
+    }
+    const dialogRef = this.dialog.open(AddDashboardUserDialogComponent, {
+      panelClass: this.panelClass,
+      width: '450px'
+    });
+    dialogRef.afterClosed().subscribe(result => {
+      this.dataSource.loadTable();
+    });
+  }
+}
+
diff --git a/dashboard/webapp-frontend/src/app/user/user.datasource.ts b/dashboard/webapp-frontend/src/app/user/user.datasource.ts
new file mode 100644
index 0000000..6b7805b
--- /dev/null
+++ b/dashboard/webapp-frontend/src/app/user/user.datasource.ts
@@ -0,0 +1,102 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+import { CollectionViewer, DataSource } from '@angular/cdk/collections';
+import { HttpErrorResponse } from '@angular/common/http';
+import { MatSort } from '@angular/material/sort';
+import { Observable } from 'rxjs/Observable';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { merge } from 'rxjs';
+import { of } from 'rxjs/observable/of';
+import { catchError, finalize, map } from 'rxjs/operators';
+import { EcompUser } from '../interfaces/dashboard.types';
+import { DashboardService } from '../services/dashboard/dashboard.service';
+import { NotificationService } from '../services/ui/notification.service';
+
+export class UserDataSource extends DataSource<EcompUser> {
+
+  private userSubject = new BehaviorSubject<EcompUser[]>([]);
+
+  private loadingSubject = new BehaviorSubject<boolean>(false);
+
+  public loading$ = this.loadingSubject.asObservable();
+
+  public rowCount = 1; // hide footer during intial load
+
+  constructor(private dashboardSvc: DashboardService,
+    private sort: MatSort,
+    private notificationService: NotificationService) {
+    super();
+  }
+
+  loadTable() {
+    this.loadingSubject.next(true);
+    this.dashboardSvc.getUsers()
+      .pipe(
+        catchError( (her: HttpErrorResponse) => {
+          console.log('UserDataSource failed: ' + her.message);
+          this.notificationService.error('Failed to get users: ' + her.message);
+          return of([]);
+        }),
+        finalize(() => this.loadingSubject.next(false))
+      )
+      .subscribe( (users: EcompUser[]) => {
+        this.rowCount = users.length;
+        this.userSubject.next(users);
+      });
+  }
+
+  connect(collectionViewer: CollectionViewer): Observable<EcompUser[]> {
+    const dataMutations = [
+      this.userSubject.asObservable(),
+      this.sort.sortChange
+    ];
+    return merge(...dataMutations).pipe(map(() => {
+      return this.getSortedData([...this.userSubject.getValue()]);
+    }));
+  }
+
+  disconnect(collectionViewer: CollectionViewer): void {
+    this.userSubject.complete();
+    this.loadingSubject.complete();
+  }
+
+  private getSortedData(data: EcompUser[]) {
+    if (!this.sort.active || this.sort.direction === '') {
+      return data;
+    }
+
+    return data.sort((a: EcompUser, b: EcompUser) => {
+      const isAsc = this.sort.direction === 'asc';
+      switch (this.sort.active) {
+        case 'loginId': return this.compare(a.loginId, b.loginId, isAsc);
+        case 'firstName': return this.compare(a.firstName, b.firstName, isAsc);
+        case 'lastName': return this.compare(a.lastName, b.lastName, isAsc);
+        case 'active': return this.compare(a.active, b.active, isAsc);
+        default: return 0;
+      }
+    });
+  }
+
+  private compare(a: any, b: any, isAsc: boolean) {
+    return (a < b ? -1 : 1) * (isAsc ? 1 : -1);
+  }
+
+}
diff --git a/dashboard/webapp-frontend/src/assets/ORANlogo.png b/dashboard/webapp-frontend/src/assets/ORANlogo.png
new file mode 100644
index 0000000..4c3dfb1
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/ORANlogo.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/at_t.png b/dashboard/webapp-frontend/src/assets/at_t.png
new file mode 100644
index 0000000..3cced1d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/at_t.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/intelligence.png b/dashboard/webapp-frontend/src/assets/intelligence.png
new file mode 100644
index 0000000..c40693e
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/intelligence.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/latency.png b/dashboard/webapp-frontend/src/assets/latency.png
new file mode 100644
index 0000000..874d11b
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/latency.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/mockdata/config.json b/dashboard/webapp-frontend/src/assets/mockdata/config.json
new file mode 100644
index 0000000..255b3fe
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/mockdata/config.json
@@ -0,0 +1,872 @@
+[
+  {
+    "metadata": {
+      "name": "Automatic Neighbor Relation",
+      "configName": "anr-appconfig",
+      "namespace": "ricxapp"
+    },
+    "descriptor": {
+      "$id": "http://example.com/root.json",
+      "$schema": "http://json-schema.org/draft-07/schema#",
+      "definitions": {},
+      "properties": {
+        "controls": {
+          "$id": "#/properties/controls",
+          "properties": {
+            "active": {
+              "$id": "#/properties/controls/properties/active",
+              "default": false,
+              "examples": [
+                true
+              ],
+              "title": "The Active Schema",
+              "type": "boolean"
+            },
+            "interfaceId": {
+              "$id": "#/properties/controls/properties/interfaceId",
+              "properties": {
+                "globalENBId": {
+                  "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId",
+                  "properties": {
+                    "bits": {
+                      "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId/properties/bits",
+                      "default": 0,
+                      "examples": [
+                        28
+                      ],
+                      "title": "The Bits Schema",
+                      "maximum": 1024,
+                      "type": "integer"
+                    },
+                    "id": {
+                      "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId/properties/id",
+                      "default": 0,
+                      "examples": [
+                        202251
+                      ],
+                      "title": "The Id Schema",
+                      "type": "integer"
+                    },
+                    "plmnid": {
+                      "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId/properties/plmnid",
+                      "default": "",
+                      "examples": [
+                        "310150"
+                      ],
+                      "pattern": "^(.*)$",
+                      "title": "The Plmnid Schema",
+                      "type": "string"
+                    }
+                  },
+                  "required": [
+                    "plmnid",
+                    "id",
+                    "bits"
+                  ],
+                  "title": "The Globalenbid Schema",
+                  "type": "object"
+                }
+              },
+              "required": [
+                "globalENBId"
+              ],
+              "title": "The Interfaceid Schema",
+              "type": "object"
+            },
+            "subscription": {
+              "$id": "#/properties/controls/properties/subscription",
+              "properties": {
+                "retries": {
+                  "$id": "#/properties/controls/properties/subscription/properties/retries",
+                  "default": 0,
+                  "examples": [
+                    1
+                  ],
+                  "title": "The Retries Schema",
+                  "type": "integer"
+                },
+                "retryto": {
+                  "$id": "#/properties/controls/properties/subscription/properties/retryto",
+                  "default": 0,
+                  "examples": [
+                    2
+                  ],
+                  "title": "The Retryto Schema",
+                  "type": "integer"
+                }
+              },
+              "required": [
+                "retries",
+                "retryto"
+              ],
+              "title": "The Subscription Schema",
+              "type": "object"
+            }
+          },
+          "required": [
+            "active",
+            "subscription",
+            "interfaceId"
+          ],
+          "title": "The Controls Schema",
+          "type": "object"
+        },
+        "db": {
+          "$id": "#/properties/db",
+          "properties": {
+            "host": {
+              "$id": "#/properties/db/properties/host",
+              "default": "",
+              "examples": [
+                "localhost"
+              ],
+              "pattern": "^(.*)$",
+              "title": "The Host Schema",
+              "type": "string"
+            },
+            "namespaces": {
+              "$id": "#/properties/db/properties/namespaces",
+              "items": {
+                "$id": "#/properties/db/properties/namespaces/items",
+                "default": "",
+                "examples": [
+                  "sdl",
+                  "rnib"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Items Schema",
+                "type": "string"
+              },
+              "title": "The Namespaces Schema",
+              "type": "array"
+            },
+            "port": {
+              "$id": "#/properties/db/properties/port",
+              "default": 0,
+              "examples": [
+                6379
+              ],
+              "title": "The Port Schema",
+              "type": "integer"
+            }
+          },
+          "required": [
+            "host",
+            "port",
+            "namespaces"
+          ],
+          "title": "The Db Schema",
+          "type": "object"
+        },
+        "local": {
+          "$id": "#/properties/local",
+          "properties": {
+            "host": {
+              "$id": "#/properties/local/properties/host",
+              "default": "",
+              "examples": [
+                ":8080"
+              ],
+              "pattern": "^(.*)$",
+              "title": "The Host Schema",
+              "type": "string"
+            }
+          },
+          "required": [
+            "host"
+          ],
+          "title": "The Local Schema",
+          "type": "object"
+        },
+        "logger": {
+          "$id": "#/properties/logger",
+          "properties": {
+            "level": {
+              "$id": "#/properties/logger/properties/level",
+              "default": 0,
+              "examples": [
+                3
+              ],
+              "title": "The Level Schema",
+              "type": "integer"
+            }
+          },
+          "required": [
+            "level"
+          ],
+          "title": "The Logger Schema",
+          "type": "object"
+        },
+        "metrics": {
+          "$id": "#/properties/metrics",
+          "items": {
+            "$id": "#/properties/metrics/items",
+            "properties": {
+              "description": {
+                "$id": "#/properties/metrics/items/properties/description",
+                "default": "",
+                "examples": [
+                  "The total number of UE context creation events"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Description Schema",
+                "type": "string"
+              },
+              "enabled": {
+                "$id": "#/properties/metrics/items/properties/enabled",
+                "default": false,
+                "examples": [
+                  true
+                ],
+                "title": "The Enabled Schema",
+                "type": "boolean"
+              },
+              "name": {
+                "$id": "#/properties/metrics/items/properties/name",
+                "default": "",
+                "examples": [
+                  "UEContextCreated"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Name Schema",
+                "type": "string"
+              },
+              "type": {
+                "$id": "#/properties/metrics/items/properties/type",
+                "default": "",
+                "examples": [
+                  "counter"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Type Schema",
+                "type": "string"
+              }
+            },
+            "required": [
+              "name",
+              "type",
+              "enabled",
+              "description"
+            ],
+            "title": "The Items Schema",
+            "type": "object"
+          },
+          "title": "The Metrics Schema",
+          "type": "array"
+        },
+        "rmr": {
+          "$id": "#/properties/rmr",
+          "properties": {
+            "maxSize": {
+              "$id": "#/properties/rmr/properties/maxSize",
+              "default": 0,
+              "examples": [
+                2072
+              ],
+              "title": "The Maxsize Schema",
+              "type": "integer"
+            },
+            "numWorkers": {
+              "$id": "#/properties/rmr/properties/numWorkers",
+              "default": 0,
+              "examples": [
+                1
+              ],
+              "title": "The Numworkers Schema",
+              "type": "integer"
+            },
+            "protPort": {
+              "$id": "#/properties/rmr/properties/protPort",
+              "default": "",
+              "examples": [
+                "tcp:4560"
+              ],
+              "pattern": "^(.*)$",
+              "title": "The Protport Schema",
+              "type": "string"
+            },
+            "rxMessages": {
+              "$id": "#/properties/rmr/properties/rxMessages",
+              "items": {
+                "$id": "#/properties/rmr/properties/rxMessages/items",
+                "default": "",
+                "examples": [
+                  "RIC_SUB_RESP",
+                  "RIC_SUB_FAILURE",
+                  "RIC_SUB_DEL_RESP",
+                  "RIC_SUB_DEL_FAILURE",
+                  "RIC_INDICATION"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Items Schema",
+                "type": "string"
+              },
+              "title": "The Rxmessages Schema",
+              "type": "array"
+            },
+            "txMessages": {
+              "$id": "#/properties/rmr/properties/txMessages",
+              "items": {
+                "$id": "#/properties/rmr/properties/txMessages/items",
+                "default": "",
+                "examples": [
+                  "RIC_SUB_REQ",
+                  "RIC_SUB_DEL_REQ"
+                ],
+                "pattern": "^(.*)$",
+                "title": "The Items Schema",
+                "type": "string"
+              },
+              "title": "The Txmessages Schema",
+              "type": "array"
+            }
+          },
+          "required": [
+            "protPort",
+            "maxSize",
+            "numWorkers",
+            "txMessages",
+            "rxMessages"
+          ],
+          "title": "The Rmr Schema",
+          "type": "object"
+        }
+      },
+      "required": [
+        "local",
+        "logger",
+        "rmr",
+        "db",
+        "controls",
+        "metrics"
+      ],
+      "title": "The Root Schema",
+      "type": "object"
+    },
+    "config": {
+      "controls": {
+        "active": true,
+        "interfaceId": {
+          "globalENBId": {
+            "bits": 28,
+            "id": 202251,
+            "plmnid": "310150"
+          }
+        },
+        "subscription": {
+          "retries": 1,
+          "retryto": 2
+        }
+      },
+      "db": {
+        "host": "localhost",
+        "namespaces": [
+          "sdl",
+          "rnib"
+        ],
+        "port": 6379
+      },
+      "local": {
+        "host": ":8080"
+      },
+      "logger": {
+        "level": 3
+      },
+      "metrics": [
+        {
+          "description": "The total number of UE context creation events",
+          "enabled": true,
+          "name": "UEContextCreated",
+          "type": "counter"
+        },
+        {
+          "description": "The total number of UE context release events",
+          "enabled": true,
+          "name": "UEContextReleased",
+          "type": "counter"
+        }
+      ],
+      "rmr": {
+        "maxSize": 2072,
+        "numWorkers": 1,
+        "protPort": "tcp:4560",
+        "rxMessages": [
+          "RIC_SUB_RESP",
+          "RIC_SUB_FAILURE",
+          "RIC_SUB_DEL_RESP",
+          "RIC_SUB_DEL_FAILURE",
+          "RIC_INDICATION"
+        ],
+        "txMessages": [
+          "RIC_SUB_REQ",
+          "RIC_SUB_DEL_REQ"
+        ]
+      }
+    },
+    "layout": [
+      {
+        "key": "controls.active",
+        "title": "Active"
+      },
+      {
+        "key": "controls.interfaceId.globalENBId",
+        "title": "Global ENB Id"
+      },
+      {
+        "type": "flex",
+        "flex-flow": "row wrap",
+        "items": [
+          {
+            "key": "controls.interfaceId.globalENBId.plmnid",
+            "title": "Plmn Id"
+          },
+          {
+            "key": "controls.interfaceId.globalENBId.id",
+            "title": "Id"
+
+          },
+          {
+            "key": "controls.interfaceId.globalENBId.bits",
+            "title": "Bits"
+          }
+        ]
+      },
+      {
+        "key": "controls.subscription",
+        "title": "Subscription"
+      },
+      {
+        "type": "flex",
+        "flex-flow": "row wrap",
+        "items": [
+          {
+            "key": "controls.subscription.retries",
+            "title": "Retries"
+          },
+          {
+            "key": "controls.subscription.retryto",
+            "title": "Retry to"
+          }
+        ]
+      }
+    ]
+  },
+  {
+    "metadata": {
+      "name": "UE Event Collector",
+      "configName": "UEEC-appconfig",
+      "namespace": "ricxapp"
+    },
+    "descriptor": {
+      "definitions": {},
+      "$schema": "http://json-schema.org/draft-07/schema#",
+      "$id": "http://example.com/root.json",
+      "type": "object",
+      "title": "The Root Schema",
+      "required": [
+        "local",
+        "logger",
+        "rmr",
+        "db",
+        "controls",
+        "metrics"
+      ],
+      "properties": {
+        "local": {
+          "$id": "#/properties/local",
+          "type": "object",
+          "title": "The Local Schema",
+          "required": [
+            "host"
+          ],
+          "properties": {
+            "host": {
+              "$id": "#/properties/local/properties/host",
+              "type": "string",
+              "title": "The Host Schema",
+              "default": "",
+              "examples": [
+                ":8080"
+              ],
+              "pattern": "^(.*)$"
+            }
+          }
+        },
+        "logger": {
+          "$id": "#/properties/logger",
+          "type": "object",
+          "title": "The Logger Schema",
+          "required": [
+            "level"
+          ],
+          "properties": {
+            "level": {
+              "$id": "#/properties/logger/properties/level",
+              "type": "integer",
+              "title": "The Level Schema",
+              "default": 0,
+              "examples": [
+                3
+              ]
+            }
+          }
+        },
+        "rmr": {
+          "$id": "#/properties/rmr",
+          "type": "object",
+          "title": "The Rmr Schema",
+          "required": [
+            "protPort",
+            "maxSize",
+            "numWorkers",
+            "txMessages",
+            "rxMessages"
+          ],
+          "properties": {
+            "protPort": {
+              "$id": "#/properties/rmr/properties/protPort",
+              "type": "string",
+              "title": "The Protport Schema",
+              "default": "",
+              "examples": [
+                "tcp:4560"
+              ],
+              "pattern": "^(.*)$"
+            },
+            "maxSize": {
+              "$id": "#/properties/rmr/properties/maxSize",
+              "type": "integer",
+              "title": "The Maxsize Schema",
+              "default": 0,
+              "examples": [
+                2072
+              ]
+            },
+            "numWorkers": {
+              "$id": "#/properties/rmr/properties/numWorkers",
+              "type": "integer",
+              "title": "The Numworkers Schema",
+              "default": 0,
+              "examples": [
+                1
+              ]
+            },
+            "txMessages": {
+              "$id": "#/properties/rmr/properties/txMessages",
+              "type": "array",
+              "title": "The Txmessages Schema",
+              "items": {
+                "$id": "#/properties/rmr/properties/txMessages/items",
+                "type": "string",
+                "title": "The Items Schema",
+                "default": "",
+                "examples": [
+                  "RIC_SUB_REQ",
+                  "RIC_SUB_DEL_REQ"
+                ],
+                "pattern": "^(.*)$"
+              }
+            },
+            "rxMessages": {
+              "$id": "#/properties/rmr/properties/rxMessages",
+              "type": "array",
+              "title": "The Rxmessages Schema",
+              "items": {
+                "$id": "#/properties/rmr/properties/rxMessages/items",
+                "type": "string",
+                "title": "The Items Schema",
+                "default": "",
+                "examples": [
+                  "RIC_SUB_RESP",
+                  "RIC_SUB_FAILURE",
+                  "RIC_SUB_DEL_RESP",
+                  "RIC_SUB_DEL_FAILURE",
+                  "RIC_INDICATION"
+                ],
+                "pattern": "^(.*)$"
+              }
+            }
+          }
+        },
+        "db": {
+          "$id": "#/properties/db",
+          "type": "object",
+          "title": "The Db Schema",
+          "required": [
+            "host",
+            "port",
+            "namespaces"
+          ],
+          "properties": {
+            "host": {
+              "$id": "#/properties/db/properties/host",
+              "type": "string",
+              "title": "The Host Schema",
+              "default": "",
+              "examples": [
+                "localhost"
+              ],
+              "pattern": "^(.*)$"
+            },
+            "port": {
+              "$id": "#/properties/db/properties/port",
+              "type": "integer",
+              "title": "The Port Schema",
+              "default": 0,
+              "examples": [
+                6379
+              ]
+            },
+            "namespaces": {
+              "$id": "#/properties/db/properties/namespaces",
+              "type": "array",
+              "title": "The Namespaces Schema",
+              "items": {
+                "$id": "#/properties/db/properties/namespaces/items",
+                "type": "string",
+                "title": "The Items Schema",
+                "default": "",
+                "examples": [
+                  "sdl",
+                  "rnib"
+                ],
+                "pattern": "^(.*)$"
+              }
+            }
+          }
+        },
+        "controls": {
+          "$id": "#/properties/controls",
+          "type": "object",
+          "title": "The Controls Schema",
+          "required": [
+            "active",
+            "requestorId",
+            "ranFunctionId",
+            "ricActionId",
+            "interfaceId"
+          ],
+          "properties": {
+            "active": {
+              "$id": "#/properties/controls/properties/active",
+              "type": "boolean",
+              "title": "The Active Schema",
+              "default": false,
+              "examples": [
+                true
+              ]
+            },
+            "requestorId": {
+              "$id": "#/properties/controls/properties/requestorId",
+              "type": "integer",
+              "title": "The Requestorid Schema",
+              "default": 0,
+              "examples": [
+                66
+              ]
+            },
+            "ranFunctionId": {
+              "$id": "#/properties/controls/properties/ranFunctionId",
+              "type": "integer",
+              "title": "The Ranfunctionid Schema",
+              "default": 0,
+              "examples": [
+                1
+              ]
+            },
+            "ricActionId": {
+              "$id": "#/properties/controls/properties/ricActionId",
+              "type": "integer",
+              "title": "The Ricactionid Schema",
+              "default": 0,
+              "examples": [
+                0
+              ]
+            },
+            "interfaceId": {
+              "$id": "#/properties/controls/properties/interfaceId",
+              "type": "object",
+              "title": "The Interfaceid Schema",
+              "required": [
+                "globalENBId"
+              ],
+              "properties": {
+                "globalENBId": {
+                  "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId",
+                  "type": "object",
+                  "title": "The Globalenbid Schema",
+                  "required": [
+                    "plmnId",
+                    "eNBId"
+                  ],
+                  "properties": {
+                    "plmnId": {
+                      "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId/properties/plmnId",
+                      "type": "string",
+                      "title": "The Plmnid Schema",
+                      "default": "",
+                      "examples": [
+                        "43962"
+                      ],
+                      "pattern": "^(.*)$"
+                    },
+                    "eNBId": {
+                      "$id": "#/properties/controls/properties/interfaceId/properties/globalENBId/properties/eNBId",
+                      "type": "string",
+                      "title": "The Enbid Schema",
+                      "default": "",
+                      "examples": [
+                        "43962"
+                      ],
+                      "pattern": "^(.*)$"
+                    }
+                  }
+                }
+              }
+            }
+          }
+        },
+        "metrics": {
+          "$id": "#/properties/metrics",
+          "type": "array",
+          "title": "The Metrics Schema",
+          "items": {
+            "$id": "#/properties/metrics/items",
+            "type": "object",
+            "title": "The Items Schema",
+            "required": [
+              "name",
+              "type",
+              "enabled",
+              "description"
+            ],
+            "properties": {
+              "name": {
+                "$id": "#/properties/metrics/items/properties/name",
+                "type": "string",
+                "title": "The Name Schema",
+                "default": "",
+                "examples": [
+                  "UEContextCreated"
+                ],
+                "pattern": "^(.*)$"
+              },
+              "type": {
+                "$id": "#/properties/metrics/items/properties/type",
+                "type": "string",
+                "title": "The Type Schema",
+                "default": "",
+                "examples": [
+                  "counter"
+                ],
+                "pattern": "^(.*)$"
+              },
+              "enabled": {
+                "$id": "#/properties/metrics/items/properties/enabled",
+                "type": "boolean",
+                "title": "The Enabled Schema",
+                "default": false,
+                "examples": [
+                  true
+                ]
+              },
+              "description": {
+                "$id": "#/properties/metrics/items/properties/description",
+                "type": "string",
+                "title": "The Description Schema",
+                "default": "",
+                "examples": [
+                  "The total number of UE context creation events"
+                ],
+                "pattern": "^(.*)$"
+              }
+            }
+          }
+        }
+      }
+    },
+    "config": {
+      "local": {
+        "host": ":8080"
+      },
+      "logger": {
+        "level": 3
+      },
+      "rmr": {
+        "protPort": "tcp:4560",
+        "maxSize": 2072,
+        "numWorkers": 1,
+        "txMessages": [ "RIC_SUB_REQ", "RIC_SUB_DEL_REQ" ],
+        "rxMessages": [ "RIC_SUB_RESP", "RIC_SUB_FAILURE", "RIC_SUB_DEL_RESP", "RIC_SUB_DEL_FAILURE", "RIC_INDICATION" ]
+      },
+      "db": {
+        "host": "localhost",
+        "port": 6379,
+        "namespaces": [ "sdl", "rnib" ]
+      },
+      "controls": {
+        "active": true,
+        "requestorId": 66,
+        "ranFunctionId": 1,
+        "ricActionId": 0,
+        "interfaceId": {
+          "globalENBId": {
+            "plmnId": "43962",
+            "eNBId": "43962"
+          }
+        }
+      },
+      "metrics": [
+        {
+          "name": "UEContextCreated",
+          "type": "counter",
+          "enabled": true,
+          "description": "The total number of UE context creation events"
+        },
+        {
+          "name": "UEContextReleased",
+          "type": "counter",
+          "enabled": true,
+          "description": "The total number of UE context release events"
+        }
+      ]
+    },
+    "layout": [
+      {
+        "key": "controls.active",
+        "title": "Active"
+      },
+      {
+        "key": "controls.requestorId",
+        "title": "Requestor Id"
+      },
+      {
+        "key": "controls.ranFunctionId",
+        "title": "RAN Function Id"
+      },
+      {
+        "key": "controls.ricActionId",
+        "title": "RIC Action Id"
+      },
+      {
+        "key": "controls.interfaceId.globalENBId",
+        "title": "Global ENB Id"
+      },
+      {
+        "type": "flex",
+        "flex-flow": "row wrap",
+        "items": [
+          {
+            "key": "controls.interfaceId.globalENBId.plmnId",
+            "title": "Plmn Id"
+          },
+          {
+            "key": "controls.interfaceId.globalENBId.eNBId",
+            "title": "ENB Id"
+
+          }
+        ]
+      }
+    ]
+  }
+]
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/assets/mockdata/db.json b/dashboard/webapp-frontend/src/assets/mockdata/db.json
new file mode 100644
index 0000000..31bd473
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/mockdata/db.json
@@ -0,0 +1,36 @@
+{
+  "config": [
+    {
+      "id": "jsonURL",
+      "value": "http://localhost:3000"
+    },
+    {
+      "id": "host",
+      "value": "http://localhost:3000"
+    },
+    {
+      "id": "metricspath",
+      "value": "/a1ric/metrics"
+    },
+    {
+      "id": "delaypath",
+      "value": "/a1ric/delay"
+    },
+    {
+      "id": "loadpath",
+      "value": "/a1ric/load"
+    }
+  ],
+  "metrics": {
+    "latency": 11,
+    "load": 100,
+    "ricload": 100,
+    "time": 123
+  },
+  "delay": {
+    "delay": 64877
+  },
+  "load": {
+    "load": 1
+  }
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/assets/mockdata/routes.json b/dashboard/webapp-frontend/src/assets/mockdata/routes.json
new file mode 100644
index 0000000..0745958
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/mockdata/routes.json
@@ -0,0 +1,4 @@
+{
+  "/a1ric/*": "/$1",
+  "/:resource/:id/show": "/:resource/:id"
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/assets/oran-logo.png b/dashboard/webapp-frontend/src/assets/oran-logo.png
new file mode 100644
index 0000000..c3b6ce5
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/oran-logo.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/policy.png b/dashboard/webapp-frontend/src/assets/policy.png
new file mode 100644
index 0000000..11df15d
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/policy.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/profile_default.png b/dashboard/webapp-frontend/src/assets/profile_default.png
new file mode 100644
index 0000000..2b90bf0
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/profile_default.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/assets/xAppControl.png b/dashboard/webapp-frontend/src/assets/xAppControl.png
new file mode 100644
index 0000000..9458a85
--- /dev/null
+++ b/dashboard/webapp-frontend/src/assets/xAppControl.png
Binary files differ
diff --git a/dashboard/webapp-frontend/src/environments/environment.prod.ts b/dashboard/webapp-frontend/src/environments/environment.prod.ts
new file mode 100644
index 0000000..58489a2
--- /dev/null
+++ b/dashboard/webapp-frontend/src/environments/environment.prod.ts
@@ -0,0 +1,22 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+export const environment = {
+  production: true
+};
diff --git a/dashboard/webapp-frontend/src/environments/environment.ts b/dashboard/webapp-frontend/src/environments/environment.ts
new file mode 100644
index 0000000..c7873a3
--- /dev/null
+++ b/dashboard/webapp-frontend/src/environments/environment.ts
@@ -0,0 +1,35 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+// This file can be replaced during build by using the `fileReplacements` array.
+// `ng build --prod` replaces `environment.ts` with `environment.prod.ts`.
+// The list of file replacements can be found in `angular.json`.
+
+export const environment = {
+  production: false
+};
+
+/*
+ * For easier debugging in development mode, you can import the following file
+ * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`.
+ *
+ * This import should be commented out in production mode because it will have a negative impact
+ * on performance if an error is thrown.
+ */
+// import 'zone.js/dist/zone-error';  // Included with Angular CLI.
diff --git a/dashboard/webapp-frontend/src/favicon.ico b/dashboard/webapp-frontend/src/favicon.ico
new file mode 100644
index 0000000..00b0fd0
--- /dev/null
+++ b/dashboard/webapp-frontend/src/favicon.ico
Binary files differ
diff --git a/dashboard/webapp-frontend/src/index.html b/dashboard/webapp-frontend/src/index.html
new file mode 100644
index 0000000..f423e92
--- /dev/null
+++ b/dashboard/webapp-frontend/src/index.html
@@ -0,0 +1,32 @@
+<!--
+  ========================LICENSE_START=================================
+  O-RAN-SC
+  %%
+  Copyright (C) 2019 AT&T Intellectual Property
+  %%
+  Licensed under the Apache License, Version 2.0 (the "License");
+  you may not use this file except in compliance with the License.
+  You may obtain a copy of the License at
+  
+       http://www.apache.org/licenses/LICENSE-2.0
+  
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+  ========================LICENSE_END===================================
+  -->
+<!doctype html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Non RT RIC Dashboard</title>
+    <base href="/">
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <link rel="icon" type="image/x-icon" href="assets/oran-logo.png">
+  </head>
+  <body>
+    <rd-root></rd-root>
+  </body>
+</html>
diff --git a/dashboard/webapp-frontend/src/karma.conf.js b/dashboard/webapp-frontend/src/karma.conf.js
new file mode 100644
index 0000000..a125d9b
--- /dev/null
+++ b/dashboard/webapp-frontend/src/karma.conf.js
@@ -0,0 +1,50 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+// Karma configuration file, see link for more information
+// https://karma-runner.github.io/1.0/config/configuration-file.html
+
+module.exports = function (config) {
+  config.set({
+    basePath: '',
+    frameworks: ['jasmine', '@angular-devkit/build-angular'],
+    plugins: [
+      require('karma-jasmine'),
+      require('karma-chrome-launcher'),
+      require('karma-jasmine-html-reporter'),
+      require('karma-coverage-istanbul-reporter'),
+      require('@angular-devkit/build-angular/plugins/karma')
+    ],
+    client: {
+      clearContext: false // leave Jasmine Spec Runner output visible in browser
+    },
+    coverageIstanbulReporter: {
+      dir: require('path').join(__dirname, '../coverage'),
+      reports: ['html', 'lcovonly', 'text-summary'],
+      fixWebpackSourcePaths: true
+    },
+    reporters: ['progress', 'kjhtml'],
+    port: 9876,
+    colors: true,
+    logLevel: config.LOG_INFO,
+    autoWatch: true,
+    browsers: ['Chrome'],
+    singleRun: false
+  });
+};
diff --git a/dashboard/webapp-frontend/src/main.ts b/dashboard/webapp-frontend/src/main.ts
new file mode 100644
index 0000000..60c66e4
--- /dev/null
+++ b/dashboard/webapp-frontend/src/main.ts
@@ -0,0 +1,31 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+import { enableProdMode } from '@angular/core';
+import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
+
+import { RdModule } from './app/rd.module';
+import { environment } from './environments/environment';
+
+if (environment.production) {
+  enableProdMode();
+}
+
+platformBrowserDynamic().bootstrapModule(RdModule)
+  .catch(err => console.error(err));
diff --git a/dashboard/webapp-frontend/src/polyfills.ts b/dashboard/webapp-frontend/src/polyfills.ts
new file mode 100644
index 0000000..09fd208
--- /dev/null
+++ b/dashboard/webapp-frontend/src/polyfills.ts
@@ -0,0 +1,104 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+/**
+ * This file includes polyfills needed by Angular and is loaded before the app.
+ * You can add your own extra polyfills to this file.
+ *
+ * This file is divided into 2 sections:
+ *   1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
+ *   2. Application imports. Files imported after ZoneJS that should be loaded before your main
+ *      file.
+ *
+ * The current setup is for so-called "evergreen" browsers; the last versions of browsers that
+ * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
+ * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
+ *
+ * Learn more in https://angular.io/guide/browser-support
+ */
+
+/***************************************************************************************************
+ * BROWSER POLYFILLS
+ */
+
+/** IE9, IE10, IE11, and Chrome <55 requires all of the following polyfills.
+ *  This also includes Android Emulators with older versions of Chrome and Google Search/Googlebot
+ */
+
+// import 'core-js/es6/symbol';
+// import 'core-js/es6/object';
+// import 'core-js/es6/function';
+// import 'core-js/es6/parse-int';
+// import 'core-js/es6/parse-float';
+// import 'core-js/es6/number';
+// import 'core-js/es6/math';
+// import 'core-js/es6/string';
+// import 'core-js/es6/date';
+// import 'core-js/es6/array';
+// import 'core-js/es6/regexp';
+// import 'core-js/es6/map';
+// import 'core-js/es6/weak-map';
+// import 'core-js/es6/set';
+
+/** IE10 and IE11 requires the following for NgClass support on SVG elements */
+// import 'classlist.js';  // Run `npm install --save classlist.js`.
+
+/** IE10 and IE11 requires the following for the Reflect API. */
+// import 'core-js/es6/reflect';
+
+/**
+ * Web Animations `@angular/platform-browser/animations`
+ * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari.
+ * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0).
+ */
+// import 'web-animations-js';  // Run `npm install --save web-animations-js`.
+
+/**
+ * By default, zone.js will patch all possible macroTask and DomEvents
+ * user can disable parts of macroTask/DomEvents patch by setting following flags
+ * because those flags need to be set before `zone.js` being loaded, and webpack
+ * will put import in the top of bundle, so user need to create a separate file
+ * in this directory (for example: zone-flags.ts), and put the following flags
+ * into that file, and then add the following code before importing zone.js.
+ * import './zone-flags.ts';
+ *
+ * The flags allowed in zone-flags.ts are listed here.
+ *
+ * The following flags will work for all browsers.
+ *
+ * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame
+ * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick
+ * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames
+ *
+ *  in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js
+ *  with the following flag, it will bypass `zone.js` patch for IE/Edge
+ *
+ *  (window as any).__Zone_enable_cross_context_check = true;
+ *
+ */
+
+/***************************************************************************************************
+ * Zone JS is required by default for Angular itself.
+ */
+import 'zone.js/dist/zone';  // Included with Angular CLI.
+
+
+/***************************************************************************************************
+ * APPLICATION IMPORTS
+ */
diff --git a/dashboard/webapp-frontend/src/styles.scss b/dashboard/webapp-frontend/src/styles.scss
new file mode 100644
index 0000000..c74cf88
--- /dev/null
+++ b/dashboard/webapp-frontend/src/styles.scss
@@ -0,0 +1,44 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+@import '~bootstrap/dist/css/bootstrap.min.css';
+@import '~@angular/material/prebuilt-themes/deeppurple-amber.css';
+@import './styles/dark-theme';
+
+/* for sidenav to take a whole page */
+html, body { 
+    margin: 0;
+    height: 100%;
+    font-family: Helvetica, Arial, sans-serif;
+}
+
+/* notification */
+.confirm-dialog-container span.content-span {
+  padding: 35px 16px 20px 16px;
+  text-align: center;
+  font-size: 20px;
+}
+
+.rd-global-page-title {
+  margin-left: 0.5%;
+  color: #432c85;
+  font-size: 25px;
+  font-weight: 100;
+}
diff --git a/dashboard/webapp-frontend/src/styles/dark-theme.scss b/dashboard/webapp-frontend/src/styles/dark-theme.scss
new file mode 100644
index 0000000..8cc0ece
--- /dev/null
+++ b/dashboard/webapp-frontend/src/styles/dark-theme.scss
@@ -0,0 +1,36 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+
+@import '~@angular/material/theming';
+@include mat-core();
+
+.dark-theme {
+  color: white;
+  $dark-primary: mat-palette($mat-yellow);
+  $dark-accent: mat-palette($mat-amber, A400, A100, A700);
+  $dark-warn: mat-palette($mat-red);
+  $dark-theme: mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
+
+  @include angular-material-theme($dark-theme);
+}
+
+.dark-theme .rd-global-page-title {
+  color:white;
+}
\ No newline at end of file
diff --git a/dashboard/webapp-frontend/src/test.ts b/dashboard/webapp-frontend/src/test.ts
new file mode 100644
index 0000000..e9d6a82
--- /dev/null
+++ b/dashboard/webapp-frontend/src/test.ts
@@ -0,0 +1,39 @@
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property
+ * %%
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * 
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ * 
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * ========================LICENSE_END===================================
+ */
+// This file is required by karma.conf.js and loads recursively all the .spec and framework files
+
+import 'zone.js/dist/zone-testing';
+import { getTestBed } from '@angular/core/testing';
+import {
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting
+} from '@angular/platform-browser-dynamic/testing';
+
+declare const require: any;
+
+// First, initialize the Angular testing environment.
+getTestBed().initTestEnvironment(
+  BrowserDynamicTestingModule,
+  platformBrowserDynamicTesting()
+);
+// Then we find all the tests.
+const context = require.context('./', true, /\.spec\.ts$/);
+// And load the modules.
+context.keys().map(context);
diff --git a/dashboard/webapp-frontend/src/tsconfig.app.json b/dashboard/webapp-frontend/src/tsconfig.app.json
new file mode 100644
index 0000000..190fd30
--- /dev/null
+++ b/dashboard/webapp-frontend/src/tsconfig.app.json
@@ -0,0 +1,11 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/app",
+    "types": []
+  },
+  "exclude": [
+    "test.ts",
+    "**/*.spec.ts"
+  ]
+}
diff --git a/dashboard/webapp-frontend/src/tsconfig.spec.json b/dashboard/webapp-frontend/src/tsconfig.spec.json
new file mode 100644
index 0000000..de77336
--- /dev/null
+++ b/dashboard/webapp-frontend/src/tsconfig.spec.json
@@ -0,0 +1,18 @@
+{
+  "extends": "../tsconfig.json",
+  "compilerOptions": {
+    "outDir": "../out-tsc/spec",
+    "types": [
+      "jasmine",
+      "node"
+    ]
+  },
+  "files": [
+    "test.ts",
+    "polyfills.ts"
+  ],
+  "include": [
+    "**/*.spec.ts",
+    "**/*.d.ts"
+  ]
+}
diff --git a/dashboard/webapp-frontend/src/tslint.json b/dashboard/webapp-frontend/src/tslint.json
new file mode 100644
index 0000000..30581c6
--- /dev/null
+++ b/dashboard/webapp-frontend/src/tslint.json
@@ -0,0 +1,17 @@
+{
+    "extends": "../tslint.json",
+    "rules": {
+        "directive-selector": [
+            true,
+            "attribute",
+            "rd",
+            "camelCase"
+        ],
+        "component-selector": [
+            true,
+            "element",
+            "rd",
+            "kebab-case"
+        ]
+    }
+}