/nbdist/
/.nb-gradle/
/build/
+
+### visual studio ###
+.vs
\ No newline at end of file
[gerrit]
-host=gerrit.oran-osc.org
+host=gerrit.o-ran-sc.org
port=29418
project=portal/ric-dashboard.git
* Allow the user to initiate an E2 (X2) connection between RIC and gNB/eNB
* User input validations on connections between RIC and eNB/gNB in the dashboard
* Add ANR xApp backend with mock implementation
+* Add undeploy xApp function
+* Add shared confirm dialog
+* Add shared notification
Version 1.0.1, 6 May 2019
-------------------------
// tslint:disable-next-line:max-line-length
import { MatIconModule, MatCardModule, MatListModule, MatSidenavModule,
MatButtonToggleModule, MatSliderModule, MatGridListModule, MatSlideToggleModule,
- MatExpansionModule, MatTabsModule, MatDialogModule, MatFormFieldModule, MatButtonModule, MatInputModule} from '@angular/material';
+ MatExpansionModule, MatTabsModule, MatDialogModule, MatFormFieldModule, MatButtonModule, MatInputModule, MatSnackBarModule} from '@angular/material';
import { BrowserAnimationsModule} from '@angular/platform-browser/animations';
import { NgModule } from '@angular/core';
import { Ng2SmartTableModule } from 'ng2-smart-table';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { LoginComponent } from './login/login.component';
-import { CatalogComponent, AppCatalogDeployDialog } from './catalog/catalog.component';
+import { CatalogComponent } from './catalog/catalog.component';
import { UiService } from './services/ui/ui.service';
import { AdminService } from './services/admin/admin.service';
import { CatalogService } from './services/catalog/catalog.service';
import { ModalEventComponent } from './ui/modal-event/modal-event.component';
import { XappComponent } from './xapp/xapp.component';
import { ConfigEventComponent } from './ui/config-event/config-event.component';
+import { ConfirmDialogComponent } from './ui/confirm-dialog/confirm-dialog.component';
@NgModule({
ModalEventComponent,
XappComponent,
ConfigEventComponent,
- AppCatalogDeployDialog,
- AppRANConnectDialog
+ AppRANConnectDialog,
+ ConfirmDialogComponent,
],
imports: [
BrowserModule,
MatButtonModule,
MatInputModule,
Ng2SmartTableModule,
+ MatSnackBarModule,
MDBBootstrapModule.forRoot(),
],
exports: [
MatInputModule
],
entryComponents: [
- AppCatalogDeployDialog,
- AppRANConnectDialog
+ AppRANConnectDialog,
+ ConfirmDialogComponent,
],
providers: [
UiService,
import { Component, Inject } from '@angular/core';
import { LocalDataSource } from 'ng2-smart-table';
import { CatalogService } from '../services/catalog/catalog.service';
-import { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-
-export interface DialogData {
- name: string;
-}
-
+import { ConfirmDialogService } from './../services/ui/confirm-dialog.service'
+import { NotificationService } from './../services/ui/notification.service'
@Component({
selector: 'app-catalog',
edit: false,
delete: false,
custom: [
- { name: 'deployxApp', title: 'Deploy'},
- ],
+ { name: 'deployxApp', title: 'Deploy' },
+ ],
position: 'right'
},
source: LocalDataSource = new LocalDataSource();
- constructor(private service: CatalogService, public dialog: MatDialog) {
- this.service.getAll().subscribe((val:any[]) => this.source.load(val));
+ constructor(
+ private service: CatalogService,
+ private confirmDialogService: ConfirmDialogService,
+ private notification: NotificationService) {
+ this.service.getAll().subscribe((val: any[]) => this.source.load(val));
}
+ onDeployxApp(event): void {
+ this.confirmDialogService.openConfirmDialog('Are you sure you want to deploy this xApp?')
+ .afterClosed().subscribe(res => {
+ if (res) {
+ this.service.deployXapp(event.data.name).subscribe(
+ response => {
+ switch (response.status) {
+ case 200:
+ this.notification.success('xApp deploy succeeded!');
+ break;
+ default:
+ this.notification.warn('xApp deploy failed.');
+ }
+ }
+ );
+ }
+ });
- onDeployxApp(event): void {
- const dialogRef = this.dialog.open(AppCatalogDeployDialog, {
- width: '400px',
- data: { name: event.data.name }
- });
-
- dialogRef.afterClosed().subscribe(result => {
- console.log('The dialog was closed');
- });
- }
-
-}
-
-@Component({
- selector: 'app-catalog-deploy-dialog',
- templateUrl: 'catalog.component.deploy-dialog.html',
- styleUrls: ['./catalog.component.css']
-})
-
-export class AppCatalogDeployDialog{
-
- constructor(
- public dialogRef: MatDialogRef<AppCatalogDeployDialog>,
- private service: CatalogService,
- @Inject(MAT_DIALOG_DATA) public data: DialogData) { }
-
- onNoClick(): void {
- this.dialogRef.close();
- }
-
- deployXapp(): void {
- this.service.deployXapp(this.data.name).subscribe((val: any[]) => { });
- this.dialogRef.close();
- }
-
-}
+ }
+}
\ No newline at end of file
* limitations under the License.
* ========================LICENSE_END===================================
*/
+
.control__section {
position: relative;
top: -150px;
:host /deep/ ng2-smart-table thead th{
text-align: left;
}
+
+:host /deep/ ng2-st-tbody-custom a.ng2-smart-action.ng2-smart-action-custom-custom {
+ display: inline-block;
+ width: 50px;
+ text-align: center;
+ font-size: 1.1em;
+}
+
+:host /deep/ i.material-icons.red-close {
+ color: red !important;
+}
\ No newline at end of file
-->
<div class="control__section">
<h3 class="control__header">xApp Control</h3>
- <ng2-smart-table [settings]="settings" [source]="source" (custom)="view($event)">
+ <ng2-smart-table [settings]="settings" [source]="source" (custom)="onxAppControlAction($event)">
</ng2-smart-table>
<app-modal-event hidden></app-modal-event>
</div>
* limitations under the License.
* ========================LICENSE_END===================================
*/
-import { Component, OnInit } from '@angular/core';
+import { Component, OnInit, ViewEncapsulation } from '@angular/core';
import { LocalDataSource } from 'ng2-smart-table';
import { ControlService } from '../services/control/control.service';
import { Router } from '@angular/router';
+import { ConfirmDialogService } from './../services/ui/confirm-dialog.service'
+import { NotificationService } from './../services/ui/notification.service'
@Component({
selector: 'app-control',
templateUrl: './control.component.html',
- styleUrls: ['./control.component.css']
+ styleUrls: ['./control.component.css'],
+ encapsulation: ViewEncapsulation.Emulated,
})
export class ControlComponent {
- settings = {
+ settings = {
hideSubHeader: true,
actions: {
columnTitle: 'Actions',
edit: false,
delete: false,
custom: [
- { name: 'view', title: 'view', },
- ],
+ { name: 'view', title: '<i class="material-icons">visibility</i>', },
+ { name: 'undeploy', title: '<i class="material-icons red-close">close</i>', },
+ ],
position: 'right'
},
columns: {
xapp: {
- title:'xApp Name',
+ title: 'xApp Name',
type: 'string',
},
name: {
- title:'Instance Name',
+ title: 'Instance Name',
type: 'string',
},
- status: {
+ status: {
title: 'Status',
type: 'string',
},
txMessages: {
title: 'txMessages',
type: 'array',
- },
+ },
rxMessages: {
- title: 'rxMessages',
- type: 'array',
+ title: 'rxMessages',
+ type: 'array',
},
},
};
source: LocalDataSource = new LocalDataSource();
- constructor(private service: ControlService, private router: Router) {
- this.service.getxAppInstances((instances) => { this.source.load(instances); } );
+ constructor(
+ private service: ControlService,
+ private router: Router,
+ private confirmDialogService: ConfirmDialogService,
+ private notification: NotificationService) {
+ this.service.getxAppInstances((instances) => { this.source.load(instances); });
+ }
+
+ onxAppControlAction(event) {
+ switch (event.action) {
+ case 'view':
+ this.view(event);
+ break;
+ case 'undeploy':
+ this.undeploy(event);
+ break;
+ }
}
view(event): void {
- const url = '/xapp';
- this.router.navigate([url, event]);
+ const url = '/xapp';
+ this.router.navigate([url, event]);
+ }
+
+ undeploy(event): void {
+ this.confirmDialogService.openConfirmDialog('Are you sure you want to undeploy this xApp ?')
+ .afterClosed().subscribe(res => {
+ if (res) {
+ this.service.undeployxApp(event.data.xapp).subscribe(
+ response => {
+ this.service.getxAppInstances((instances) => { this.source.load(instances); });
+ switch (response.status) {
+ case 200:
+ this.notification.success('xApp undeployed successfully!');
+ break;
+ default:
+ this.notification.warn('xApp undeploy failed.');
+ }
+ }
+ );
+ }
+ });
}
@Injectable()
export class CatalogService {
-
+
constructor(private http: HttpClient) {
}
return this.http.get('api/xappmgr/xapps');
}
- deployXapp(name) {
- return this.http.post('api/xappmgr/xapps',
- {
- "xAppName": name
- });
- }
-
+ deployXapp(name) {
+ return this.http.post('api/xappmgr/xapps',
+ {
+ "xAppName": name
+ }
+ , { observe: 'response' });
+ }
+
}
}
+ undeployxApp(xapp) {
+ return this.http.delete(('api/xappmgr/xapps/' + xapp),{ observe: 'response' })
+ }
+
fetchInstance(allxappdata) {
var xAppInstances = []
for (const xappindex in allxappdata) {
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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();
+ });
+});
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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';
+import { ConfirmDialogComponent } from './../../ui/confirm-dialog/confirm-dialog.component'
+
+@Injectable({
+ providedIn: 'root'
+})
+export class ConfirmDialogService {
+
+ constructor(private dialog: MatDialog) { }
+
+ openConfirmDialog(msg) {
+ return this.dialog.open(ConfirmDialogComponent, {
+ width: '480px',
+ position: { top: "100px" },
+ data: {
+ message: msg
+ }
+ });
+ }
+}
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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();
+ });
+});
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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 { MatSnackBar, MatSnackBarConfig } from '@angular/material';
+
+@Injectable({
+ providedIn: 'root'
+})
+export class NotificationService {
+
+ constructor(public snackBar: MatSnackBar) { }
+
+ config: MatSnackBarConfig = {
+ duration: 3000,
+ horizontalPosition: 'right',
+ verticalPosition: 'top'
+ }
+
+
+ success(msg) {
+ this.config['panelClass'] = ['notification', 'success', 'default'];
+ this.snackBar.open(msg, '', this.config);
+ }
+
+ warn(msg) {
+ this.config['panelClass'] = ['notification', 'warn', 'default'];
+ this.snackBar.open(msg, '', this.config);
+ }
+
+ error(msg) {
+ this.config['panelClass'] = ['notification', 'error', 'default'];
+ this.snackBar.open(msg, '', this.config);
+ }
+}
-->
-
-<div mat-dialog-content class="modal-header">
- <p>Do you want to deploy {{data.name}}?</p>
-</div>
-
-<div mat-dialog-actions class="modal-footer justify-content-center">
- <a type="button" mdbBtn color="primary" class="waves-effect" mdbWavesEffect mat-button (click)="deployXapp()">
- <mat-icon style="vertical-align: -21%;">launch</mat-icon> Deploy
- </a>
- <a type="button" mdbBtn color="primary" outline="true" class="waves-effect" mdbWavesEffect
- data-dismiss="modal" mat-button (click)="onNoClick()">
- <mat-icon style="vertical-align: -21%; size: 1em">close</mat-icon> Cancel
- </a>
-</div>
\ No newline at end of file
+ <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>
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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();
+ });
+});
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2019 AT&T Intellectual Property and Nokia
+ * %%
+ * 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';
+
+@Component({
+ selector: 'app-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);
+ }
+}
font-family: Helvetica, Arial, sans-serif;
}
+/* notification */
+.confirm-dialog-container span.content-span {
+ padding: 35px 16px 20px 16px;
+ text-align: center;
+ font-size: 20px;
+}
+
+snack-bar-container.success.default {
+ background-color: #5cb85c;
+ color: #fff;
+}
+
+snack-bar-container.warn.default {
+ background-color: #f99157;
+ color: #fff;
+}
+
+snack-bar-container.error.default {
+ background-color: #fc7169;
+ color: #fff;
+}
+
+
+snack-bar-container.notification simple-snack-bar {
+ font-size: 18px !important;
+ font-weight: bold;
+}
\ No newline at end of file