* Upgrade A1 Mediator API and submodule to tag 2.1.0
* Upgrade App Manager API and submodule to tag 0.3.3
* Upgrade E2 Manager API and submodule to tag 3.0.3
+* Add instance selector dialog component and service
+* Repair onSidenavClose method
Version 1.3.0, 26 Nov 2019
--------------------------
*/
import { HttpErrorResponse } from '@angular/common/http';
-import { Component, OnInit, OnDestroy } from '@angular/core';
+import { Component, OnDestroy, OnInit } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { Subscription } from 'rxjs';
import { ACAdmissionIntervalControl } from '../interfaces/ac-xapp.types';
+import { RicInstance } from '../interfaces/dashboard.types';
import { ACXappService } from '../services/ac-xapp/ac-xapp.service';
-import { ErrorDialogService } from '../services/ui/error-dialog.service';
-import { NotificationService } from './../services/ui/notification.service';
-import { Subscription } from 'rxjs';
import { InstanceSelectorService } from '../services/instance-selector/instance-selector.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
@Component({
selector: 'rd-ac-xapp',
trigger_threshold: new FormControl('', [Validators.required, Validators.min(1)])
});
- this.instanceChange = this.instanceSelectorService.getSelectedInstancekey().subscribe((instanceKey: string) => {
- if (instanceKey) {
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.key) {
// TODO: show pending action indicator
- this.instanceKey = instanceKey;
- this.acXappService.getPolicy(instanceKey).subscribe((res: ACAdmissionIntervalControl) => {
+ this.instanceKey = instance.key;
+ this.acXappService.getPolicy(instance.key).subscribe((res: ACAdmissionIntervalControl) => {
this.acForm.controls['class'].setValue(res.class);
this.acForm.controls['enforce'].setValue(res.enforce);
this.acForm.controls['window_length'].setValue(res.window_length);
import { ErrorDialogService } from '../services/ui/error-dialog.service';
import { LoadingDialogService } from '../services/ui/loading-dialog.service';
import { HttpErrorResponse, HttpResponse } from '@angular/common/http';
-import { NotificationService } from './../services/ui/notification.service';
+import { NotificationService } from '../services/ui/notification.service';
@Component({
selector: 'rd-app-configuration',
import { Subscription } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { XappControlRow } from '../interfaces/app-mgr.types';
+import { RicInstance } from '../interfaces/dashboard.types';
import { AppMgrService } from '../services/app-mgr/app-mgr.service';
import { InstanceSelectorService } from '../services/instance-selector/instance-selector.service';
import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
ngOnInit() {
this.dataSource = new AppControlDataSource(this.appMgrSvc, this.sort, this.notificationService);
- this.instanceChange = this.instanceSelectorService.getSelectedInstancekey().subscribe((instanceKey: string) => {
- if (instanceKey) {
- this.instanceKey = instanceKey;
- this.dataSource.loadTable(instanceKey);
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.key) {
+ this.instanceKey = instance.key;
+ this.dataSource.loadTable(instance.key);
}
});
}
import { Component, Input, OnDestroy, OnInit, ViewChild } from '@angular/core';
import { MatSort } from '@angular/material/sort';
import { Subscription } from 'rxjs';
+import { RicInstance } from '../interfaces/dashboard.types';
import { CaasIngressService } from '../services/caas-ingress/caas-ingress.service';
import { InstanceSelectorService } from '../services/instance-selector/instance-selector.service';
import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
ngOnInit() {
this.dataSource = new CaasIngressDataSource(this.caasIngressSvc, this.sort, this.notificationService);
- this.instanceChange = this.instanceSelectorService.getSelectedInstancekey().subscribe((instanceKey: string) => {
- if (instanceKey) {
- this.dataSource.loadTable(instanceKey, this.cluster, this.namespace);
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.key) {
+ this.dataSource.loadTable(instance.key, this.cluster, this.namespace);
}
});
}
import { MatSort } from '@angular/material/sort';
import { Subscription } from 'rxjs';
import { finalize } from 'rxjs/operators';
+import { RicInstance } from '../interfaces/dashboard.types';
import { XMDeployableApp } from '../interfaces/app-mgr.types';
import { AppMgrService } from '../services/app-mgr/app-mgr.service';
import { InstanceSelectorService } from '../services/instance-selector/instance-selector.service';
import { LoadingDialogService } from '../services/ui/loading-dialog.service';
import { UiService } from '../services/ui/ui.service';
import { AppConfigurationComponent } from './../app-configuration/app-configuration.component';
-import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
-import { NotificationService } from './../services/ui/notification.service';
+import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
+import { NotificationService } from '../services/ui/notification.service';
import { CatalogDataSource } from './catalog.datasource';
@Component({
this.darkMode = isDark;
});
- this.instanceChange = this.instanceSelectorService.getSelectedInstancekey().subscribe((instanceKey: string) => {
- if (instanceKey) {
- this.instanceKey = instanceKey;
- this.dataSource.loadTable(instanceKey);
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.key) {
+ this.instanceKey = instance.key;
+ this.dataSource.loadTable(instance.key);
}
});
}
========================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.
+ Copyright (C) 2020 AT&T Intellectual Property. Licensed under the Apache License, Version 2.0.
<br/>
Version {{dashboardVersion}}
</div>
})
export class SidenavListComponent implements OnInit {
darkMode: boolean;
- @Output() sidenavClose = new EventEmitter();
+ @Output() sidenavClose: EventEmitter<any> = new EventEmitter();
constructor(public ui: UiService) { }
import { MatDialog } from '@angular/material/dialog';
import { Subscription } from 'rxjs';
import { finalize } from 'rxjs/operators';
+import { RicInstance } from '../interfaces/dashboard.types';
import { E2ManagerService } from '../services/e2-mgr/e2-mgr.service';
import { InstanceSelectorService } from '../services/instance-selector/instance-selector.service';
import { ConfirmDialogService } from '../services/ui/confirm-dialog.service';
this.darkMode = isDark;
});
- this.instanceChange = this.instanceSelectorService.getSelectedInstancekey().subscribe((instanceKey: string) => {
- if (instanceKey) {
- this.instanceKey = instanceKey;
- this.dataSource.loadTable(instanceKey);
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.key) {
+ this.instanceKey = instance.key;
+ this.dataSource.loadTable(instance.key);
}
});
}
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.
========================LICENSE_END===================================
-->
<!-- Slide Menu-->
-<mat-drawer-container autosize >
+<mat-drawer-container autosize [hasBackdrop]=true>
<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 313.7 42.8">
- <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">RIC Dashboard</tspan>
- </text>
- </svg>
+ <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 313.7 42.8">
+ <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">RIC Dashboard</tspan>
+ </text>
+ </svg>
- </div>
+ </div>
<div class="profile-image__container">
<img src="assets/profile_default.png" alt="profile-image"
<span class="email__text">demo@o-ran-sc.org</span>
</div>
</section>
- <section #sidenav class="menu-body" >
- <rd-sidenav-list ></rd-sidenav-list>
+ <section #sidenav class="menu-body">
+ <rd-sidenav-list (sidenavClose)="drawer.toggle()"></rd-sidenav-list>
</section>
<section class="menu-footer">
-
+ <mat-nav-list [ngClass]="{'dark': darkModeActive}">
+ <a mat-list-item (click)="openInstanceSelectorDialog(); drawer.toggle()">
+ <mat-icon>link</mat-icon> <span class="nav-caption">{{selectedInstanceName}}</span>
+ </a>
+ </mat-nav-list>
</section>
-</mat-drawer>
+ </mat-drawer>
-<mat-drawer-content>
-<div class="root__container">
+ <mat-drawer-content>
+ <div class="root__container">
- <header [ngClass]="{'main__header-dark': darkModeActive}" class="main__header">
+ <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 313.7 42.8">
- <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">RIC Dashboard</tspan>
- </text>
- </svg>
+ <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 313.7 42.8">
+ <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">RIC Dashboard</tspan>
+ </text>
+ </svg>
- </div>
+ </div>
- <div>
- <mat-label class="selector-label">Select RIC Instance</mat-label>
- <mat-form-field>
- <mat-select (selectionChange)="changeInstance($event.value)" [(value)]="selectedInstanceKey">
- <mat-option *ngFor="let instance of instanceArray" [value]="instance.key">
- {{instance.name}}
- </mat-option>
- </mat-select>
- </mat-form-field>
- </div>
+ <div> </div>
- <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>
+ <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>
+ </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>
+ <!-- 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>
+ <!-- Footer -->
+ <footer class="main__footer" [ngClass]="{'main-footer__bg-dark': darkModeActive}">
+ <div class="main-footer-licence">
+ <rd-footer></rd-footer>
+ </div>
+ <button mat-flat-button color="primary" class="main-footer-instance" (click)="openInstanceSelectorDialog()" >
+ <span> {{selectedInstanceName}} </span>
+ </button>
+ </footer>
-</div>
-</mat-drawer-content>
+ </div>
+ </mat-drawer-content>
</mat-drawer-container>
/* Header */
mat-sidenav-container, mat-sidenav-content, mat-sidenav {
- height: 100%;
+ height: 100%;
}
mat-sidenav {
- width: 250px;
+ width: 250px;
}
main {
- padding: 10px;
+ padding: 10px;
}
/* Slide Menu */
.slide-menu-active {
transform: none;
}
+
.menu-header.menu-header__dark {
background: #2B244D;
}
}
.menumargin-top {
- margin-top: 10px;
+ margin-top: 10px;
}
.greeting__text {
max-width: 4rem;
}
-.home_bg_image{
- height:40em;
- background-size:cover;
- width:auto;
- background-image:url('../assets/intelligence.png');
- background-position:50% 50%;
+.home_bg_image {
+ height: 40em;
+ background-size: cover;
+ width: auto;
+ background-image: url('../assets/intelligence.png');
+ background-position: 50% 50%;
}
/*Header*/
color: white;
}
+.main-footer-licence {
+ float: left;
+}
+
.main-footer__bg-dark {
opacity: 1;
background: linear-gradient(to bottom, #B290FF, #2E1D65);
transition: opacity 300ms linear;
}
+.main-footer-instance {
+ margin-right: 10px;
+ float: right;
+ color: white;
+ letter-spacing: 0.1rem;
+ font-size: 15px;
+}
+
+.main-footer-instance:hover {
+ color: lightgray;
+}
+
@media only screen and (max-width: 300px) {
.slide-menu {
width: 100%;
}
.selector-label {
- margin-right: 20px;
-}
\ No newline at end of file
+ margin-right: 20px;
+}
+
+.menu-footer {
+ display: grid;
+ width: 100%;
+ position: absolute;
+ bottom: 10px;
+}
+
+a {
+ text-decoration: none;
+ color: black;
+}
+
+.dark a {
+ color: white;
+}
+
+a:hover, a:active {
+ color: lightgray;
+}
+
+.nav-caption {
+ display: inline-block;
+ padding-left: 6px;
+}
* ========================LICENSE_END===================================
*/
import { Component, OnInit } from '@angular/core';
-import { finalize } from 'rxjs/operators';
+import { Subscription } from 'rxjs';
import { RicInstance } from './interfaces/dashboard.types';
import { InstanceSelectorService } from './services/instance-selector/instance-selector.service';
-import { LoadingDialogService } from './services/ui/loading-dialog.service';
+import { InstanceSelectorDialogService } from './services/ui/instance-selector-dialog.service';
import { UiService } from './services/ui/ui.service';
@Component({
export class RdComponent implements OnInit {
showMenu = false;
darkModeActive: boolean;
- private instanceArray: RicInstance[];
- private selectedInstanceKey: string;
+
+ private selectedInstanceName: string = 'Select RIC instance';
+ private instanceChange: Subscription;
constructor(
public ui: UiService,
- private instanceSelectorService: InstanceSelectorService,
- private loadingDialogService: LoadingDialogService) {
+ private instanceSelectorDialogService: InstanceSelectorDialogService,
+ private instanceSelectorService: InstanceSelectorService) {
}
ngOnInit() {
this.ui.darkModeState.subscribe((value) => {
this.darkModeActive = value;
});
- this.loadingDialogService.startLoading('Loading RIC instances');
- this.instanceSelectorService.getInstanceArray()
- .pipe(
- finalize(() => this.loadingDialogService.stopLoading())
- )
- .subscribe((instanceArray: RicInstance[]) => {
- this.instanceArray = instanceArray;
- this.selectedInstanceKey = instanceArray[0].key;
- })
+
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((instance: RicInstance) => {
+ if (instance.name) {
+ this.selectedInstanceName = instance.name;
+ } else {
+ this.openInstanceSelectorDialog()
+ }
+ });
}
- toggleMenu() {
- this.showMenu = !this.showMenu;
+ ngOnDestroy() {
+ this.instanceChange.unsubscribe();
}
modeToggleSwitch() {
this.ui.darkModeState.next(!this.darkModeActive);
}
- changeInstance(selectedInstancekey: string) {
- this.instanceSelectorService.updateSelectedInstance(selectedInstancekey);
+ openInstanceSelectorDialog() {
+ this.instanceSelectorDialogService.openInstanceSelectorDialog();
}
}
import { EditDashboardUserDialogComponent } from './user/edit-dashboard-user-dialog/edit-dashboard-user-dialog.component';
import { ErrorDialogComponent } from './ui/error-dialog/error-dialog.component';
import { FooterComponent } from './footer/footer.component';
+import { InstanceSelectorDialogComponent } from './ui/instance-selector-dialog/instance-selector-dialog.component';
import { LoadingDialogComponent } from './ui/loading-dialog/loading-dialog.component';
import { MainComponent } from './main/main.component';
import { PlatformComponent } from './platform/platform.component';
import { E2ManagerService } from './services/e2-mgr/e2-mgr.service';
import { ErrorDialogService } from './services/ui/error-dialog.service';
import { InstanceSelectorService } from './services/instance-selector/instance-selector.service';
+import { InstanceSelectorDialogService } from './services/ui/instance-selector-dialog.service';
import { UiService } from './services/ui/ui.service';
+
@NgModule({
declarations: [
AcXappComponent,
SidenavListComponent,
StatCardComponent,
StatsComponent,
- UserComponent
+ UserComponent,
+ InstanceSelectorDialogComponent
],
imports: [
BrowserModule,
ConfirmDialogComponent,
EditDashboardUserDialogComponent,
ErrorDialogComponent,
+ InstanceSelectorDialogComponent,
LoadingDialogComponent,
RanControlConnectDialogComponent
],
E2ManagerService,
ErrorDialogService,
InstanceSelectorService,
+ InstanceSelectorDialogService,
UiService
],
bootstrap: [RdComponent]
providedIn: 'root'
})
export class InstanceSelectorService {
- private selectedInstanceKey: BehaviorSubject<string> = new BehaviorSubject<string>('');
+
private instanceArray: Observable<RicInstance[]>;
+ private selectedInstance: BehaviorSubject<RicInstance> = new BehaviorSubject<RicInstance>({ key: '', name:''});
constructor(
private dashboardSvc: DashboardService,
const path = this.dashboardSvc.buildPath('admin', null, 'instance');
return this.instanceArray = this.httpClient.get<RicInstance[]>(path)
.pipe(
- tap(ricInstanceArray => {
- this.initselectedInstanceKey(ricInstanceArray[0].key);
- }),
shareReplay(1)
);
}
- private initselectedInstanceKey(instanceKey: string) {
- if (!this.selectedInstanceKey.value) {
- this.selectedInstanceKey.next(instanceKey)
- }
- }
-
- // This method may return the BehaviorSubject with empty string
+ // This method may return the BehaviorSubject with empty value
// Afther subscribe that BehaviorSubject
// Please make sure this BehaviorSubject has non empty value
- getSelectedInstancekey(): BehaviorSubject<string> {
- return this.selectedInstanceKey;
+ getSelectedInstance(): BehaviorSubject<RicInstance> {
+ return this.selectedInstance;
}
- updateSelectedInstance(instanceKey: string) {
- this.selectedInstanceKey.next(instanceKey)
+ updateSelectedInstance(instance: RicInstance) {
+ this.selectedInstance.next(instance)
}
}
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 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 { InstanceSelectorDialogService } from './instance-selector-dialog.service';
+
+describe('InstanceSelectorDialogService', () => {
+ beforeEach(() => TestBed.configureTestingModule({}));
+
+ it('should be created', () => {
+ const service: InstanceSelectorDialogService = TestBed.get(InstanceSelectorDialogService);
+ expect(service).toBeTruthy();
+ });
+});
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 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 { InstanceSelectorDialogComponent } from '../../ui/instance-selector-dialog/instance-selector-dialog.component';
+import { UiService } from './ui.service';
+
+
+@Injectable({
+ providedIn: 'root'
+})
+export class InstanceSelectorDialogService {
+
+ darkMode: boolean;
+ panelClass: string;
+
+ constructor(private dialog: MatDialog,
+ public ui: UiService) { }
+
+ openInstanceSelectorDialog() {
+ this.ui.darkModeState.subscribe((isDark) => {
+ this.darkMode = isDark;
+ });
+ if (this.darkMode) {
+ this.panelClass = 'dark-theme';
+ } else {
+ this.panelClass = '';
+ }
+ return this.dialog.open(InstanceSelectorDialogComponent, {
+ panelClass: this.panelClass,
+ width: '480px',
+ position: { top: '100px' },
+ });
+ }
+}
--- /dev/null
+<!--
+ ========================LICENSE_START=================================
+ O-RAN-SC
+ %%
+ Copyright (C) 2020 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>
+ Select RIC Instance
+</div>
+<form [formGroup]="instanceForm" novalidate autocomplete="off" (ngSubmit)="changeInstance(instanceForm.value.instance)">
+ <div mat-dialog-content>
+ <mat-form-field>
+ <mat-label>Select an instance</mat-label>
+ <mat-select formControlName="instance">
+ <mat-option *ngFor="let instance of instanceArray" [value]="instance">
+ {{instance.name}}
+ </mat-option>
+ </mat-select>
+ </mat-form-field>
+ </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" [disabled]="!instanceForm.valid">OK</button>
+ </div>
+</form>
\ No newline at end of file
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 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 { InstanceSelectorDialogComponent } from './instance-selector-dialog.component';
+
+describe('InstanceSelectorDialogComponent', () => {
+ let component: InstanceSelectorDialogComponent;
+ let fixture: ComponentFixture<InstanceSelectorDialogComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ InstanceSelectorDialogComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(InstanceSelectorDialogComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+/*-
+ * ========================LICENSE_START=================================
+ * O-RAN-SC
+ * %%
+ * Copyright (C) 2020 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, OnDestroy, OnInit } from '@angular/core';
+import { FormControl, FormGroup, Validators } from '@angular/forms';
+import { MatDialogRef } from '@angular/material/dialog';
+import { Subscription } from 'rxjs';
+import { finalize } from 'rxjs/operators';
+import { RicInstance } from '../../interfaces/dashboard.types';
+import { InstanceSelectorService } from '../../services/instance-selector/instance-selector.service';
+import { LoadingDialogService } from '../../services/ui/loading-dialog.service';
+
+@Component({
+ selector: 'rd-instance-selector-dialog',
+ templateUrl: './instance-selector-dialog.component.html',
+})
+export class InstanceSelectorDialogComponent implements OnInit, OnDestroy {
+
+ private instanceArray: RicInstance[];
+ private instanceForm: FormGroup;
+ private instanceChange: Subscription;
+
+ constructor(
+ private dialogRef: MatDialogRef<InstanceSelectorDialogComponent>,
+ private instanceSelectorService: InstanceSelectorService,
+ private loadingDialogService: LoadingDialogService) { }
+
+ ngOnInit() {
+ this.instanceForm = new FormGroup({
+ instance: new FormControl('', [Validators.required]),
+ })
+
+ this.loadingDialogService.startLoading('Loading RIC instances');
+ this.instanceSelectorService.getInstanceArray()
+ .pipe(
+ finalize(() => this.loadingDialogService.stopLoading())
+ )
+ .subscribe((instanceArray: RicInstance[]) => {
+ this.instanceArray = instanceArray;
+ })
+
+ this.instanceChange = this.instanceSelectorService.getSelectedInstance().subscribe((selectedInstance: RicInstance) => {
+ if (selectedInstance.key) {
+ this.instanceForm.setValue({ instance: selectedInstance })
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ this.instanceChange.unsubscribe();
+ }
+
+ changeInstance(selectedInstance) {
+ this.instanceSelectorService.updateSelectedInstance(selectedInstance);
+ this.dialogRef.close(true);
+ }
+
+}