RIC dynamic config screen for each xApp 47/647/12
authorjh245g <jh245g@att.com>
Tue, 6 Aug 2019 13:50:48 +0000 (09:50 -0400)
committerjh245g <jh245g@att.com>
Mon, 19 Aug 2019 19:10:16 +0000 (15:10 -0400)
create an app-configuration component

Change-Id: I62dbeaf20508296b99248d3f0d8c2af11111f7ac
Signed-off-by: Jun (Nicolas) Hu <jh245g@att.com>
13 files changed:
docs/release-notes.rst
webapp-backend/src/test/java/org/oransc/ric/portal/dashboard/config/AppManagerMockConfiguration.java
webapp-frontend/package-lock.json
webapp-frontend/package.json
webapp-frontend/src/app/app-configuration/app-configuration.component.html [new file with mode: 0644]
webapp-frontend/src/app/app-configuration/app-configuration.component.scss [new file with mode: 0644]
webapp-frontend/src/app/app-configuration/app-configuration.component.spec.ts [new file with mode: 0644]
webapp-frontend/src/app/app-configuration/app-configuration.component.ts [new file with mode: 0644]
webapp-frontend/src/app/catalog/catalog.component.ts
webapp-frontend/src/app/rd.module.ts
webapp-frontend/src/app/services/app-mgr/app-mgr.service.ts
webapp-frontend/src/app/ui/catalog-card/catalog-card.component.html
webapp-frontend/src/assets/mockdata/config.json [new file with mode: 0644]

index 90e1b73..6c89ab9 100644 (file)
@@ -23,7 +23,7 @@ Version 1.2.1, ? Aug 2019
 -------------------------
 * Add EPSDK-FW user management and Portal security
 
-Version 1.2.0, 16 Aug 2019
+Version 1.2.0, 19 Aug 2019
 --------------------------
 * Split URL properties into prefix/suffix parts
 * Add jacoco plugin to back-end for code coverage
@@ -40,6 +40,7 @@ Version 1.2.0, 16 Aug 2019
 * Add pattern for matching AC/admin application name
 * Add custom (plain but not white-label) error page
 * Synch A1 method paths in front-end and back-end
+* Add xapp dynamic configuration feature
 
 Version 1.0.5, 5 July 2019
 --------------------------
index 32de4df..0633b04 100644 (file)
@@ -69,7 +69,7 @@ public class AppManagerMockConfiguration {
 
        public AppManagerMockConfiguration() {
                logger.info("Configuring mock xApp Manager");
-               final String[] appNames = { "AdmissionControl", "Automatic Neighbor Relation", "Dual Connectivity" };
+               final String[] appNames = { "AdmissionControl", "Automatic Neighbor Relation", "UE Event Collector" };
                final String configJson = " { \"config\" : \"example\" }";
                final String descriptorJson = " { \"descriptor\" : \"example\" }";
                allXappConfigs = new AllXappConfig();
index 6165c8c..c03ccd4 100644 (file)
         "tslib": "^1.9.0"
       }
     },
+    "@angular/flex-layout": {
+      "version": "7.0.0-beta.19",
+      "resolved": "https://registry.npmjs.org/@angular/flex-layout/-/flex-layout-7.0.0-beta.19.tgz",
+      "integrity": "sha512-MXq+zZ6/s5/+GsL9fZ42mKL0LjZ/+L0sVU5FaQuSAJ57soLl5QAGWvdxVmROtqcHd3Htp35R49nKSZBJ0nfAjg==",
+      "requires": {
+        "tslib": "^1.7.1"
+      }
+    },
     "@angular/forms": {
       "version": "8.0.3",
       "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-8.0.3.tgz",
         "tslib": "^1.9.0"
       }
     },
+    "angular6-json-schema-form": {
+      "version": "7.3.0",
+      "resolved": "https://registry.npmjs.org/angular6-json-schema-form/-/angular6-json-schema-form-7.3.0.tgz",
+      "integrity": "sha512-ZoCCsE4KDjHF9sLcA3NnglVpA+N578R+DYMaSfc4F0UviUoil61oeGTMhVYOuFjJ6Yui0mxKY9B0sgJzvaCjxw==",
+      "requires": {
+        "tslib": "^1.9.0"
+      }
+    },
     "ansi-colors": {
       "version": "3.2.4",
       "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz",
index ede4c64..648f8f4 100644 (file)
@@ -16,6 +16,7 @@
     "@angular/common": "^8.0.3",
     "@angular/compiler": "^8.0.3",
     "@angular/core": "^8.0.3",
+    "@angular/flex-layout": "^7.0.0-beta.19",
     "@angular/forms": "^8.0.3",
     "@angular/material": "~7.2.0",
     "@angular/platform-browser": "^8.0.3",
     "@material/radio": "^2.3.0",
     "@types/chart.js": "^2.7.54",
     "angular-bootstrap-md": "^7.5.4",
+    "angular6-json-schema-form": "^7.3.0",
     "bootstrap": "^4.3.1",
     "chart.js": "^2.8.0",
     "core-js": "^2.6.9",
     "hammerjs": "^2.0.8",
+    "lodash-es": "^4.17.15",
     "material-design-icons": "^3.0.1",
     "ng2-charts": "^1.6.0",
     "ng2-completer": "^2.0.8",
diff --git a/webapp-frontend/src/app/app-configuration/app-configuration.component.html b/webapp-frontend/src/app/app-configuration/app-configuration.component.html
new file mode 100644 (file)
index 0000000..a90af7a
--- /dev/null
@@ -0,0 +1,41 @@
+<!--
+  ========================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===================================
+  -->
+
+<div mat-dialog-title *ngIf="loading$ | async">
+  Loading {{data.name}} Configuration
+  <mat-spinner diameter=70></mat-spinner>
+</div>
+
+<div *ngIf="((loading$ | async)==false) " class="config-div">
+
+  <div mat-dialog-title class="config-title">
+    {{data.name}} Configuration
+  </div>
+
+  <div  class="config-form">
+    <json-schema-form loadExternalAssets="true"
+                      framework="material-design"
+                      [data]="xappConfigData"
+                      [schema]="xappConfigSchema"
+                      [layout]="xappLayout"
+                      (onSubmit)="updateconfig($event)">
+    </json-schema-form>
+  </div>
+</div>
\ No newline at end of file
diff --git a/webapp-frontend/src/app/app-configuration/app-configuration.component.scss b/webapp-frontend/src/app/app-configuration/app-configuration.component.scss
new file mode 100644 (file)
index 0000000..e7f0166
--- /dev/null
@@ -0,0 +1,50 @@
+/*-
+ * ========================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===================================
+ */
+
+mat-spinner {
+  margin:10px
+}
+
+.config-div{
+  max-height:450px;
+}
+
+.config-title {
+  height:50px;
+  text-align: center;
+  color: #432c85;
+  font-size: 30px;
+  font-weight: 300;
+  transform: translate(149 56);
+  margin-bottom:0px
+}
+
+.config-form {
+  max-height: 400px;
+  overflow-y:scroll;
+}
+
+.config-form::-webkit-scrollbar {
+  display: none;
+}
+
+/deep/ .mat-form-field-wrapper{
+  margin-right:10px
+}
\ No newline at end of file
diff --git a/webapp-frontend/src/app/app-configuration/app-configuration.component.spec.ts b/webapp-frontend/src/app/app-configuration/app-configuration.component.spec.ts
new file mode 100644 (file)
index 0000000..078532c
--- /dev/null
@@ -0,0 +1,45 @@
+/*-
+ * ========================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 { AppConfigurationComponent } from './app-configuration.component';
+
+describe('AppConfigurationComponent', () => {
+  let component: AppConfigurationComponent;
+  let fixture: ComponentFixture<AppConfigurationComponent>;
+
+  beforeEach(async(() => {
+    TestBed.configureTestingModule({
+      declarations: [ AppConfigurationComponent ]
+    })
+    .compileComponents();
+  }));
+
+  beforeEach(() => {
+    fixture = TestBed.createComponent(AppConfigurationComponent);
+    component = fixture.componentInstance;
+    fixture.detectChanges();
+  });
+
+  it('should create', () => {
+    expect(component).toBeTruthy();
+  });
+});
diff --git a/webapp-frontend/src/app/app-configuration/app-configuration.component.ts b/webapp-frontend/src/app/app-configuration/app-configuration.component.ts
new file mode 100644 (file)
index 0000000..8b429c6
--- /dev/null
@@ -0,0 +1,86 @@
+/*-
+ * ========================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 { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
+import { AppMgrService } from '../services/app-mgr/app-mgr.service';
+import { ErrorDialogService } from '../services/ui/error-dialog.service';
+import { BehaviorSubject } from 'rxjs/BehaviorSubject';
+import { finalize } from 'rxjs/operators';
+
+
+@Component({
+  selector: 'rd-app-configuration',
+  templateUrl: './app-configuration.component.html',
+  styleUrls: ['./app-configuration.component.scss']
+})
+export class AppConfigurationComponent implements OnInit {
+
+  private loadingSubject = new BehaviorSubject<boolean>(false);
+  public loading$ = this.loadingSubject.asObservable();
+
+  constructor(
+    private dialogRef: MatDialogRef<AppConfigurationComponent>,
+    private appMgrService: AppMgrService,
+    private errorDiaglogService: ErrorDialogService,
+    @Inject(MAT_DIALOG_DATA) private data
+  ) { }
+
+  xappMetadata: any;
+  xappConfigSchema: any;
+  xappConfigData: any; 
+  xappLayout:any;
+  ngOnInit() {
+    this.loadingSubject.next(true);
+    this.appMgrService.getConfig()
+      .pipe(
+        finalize(() => this.loadingSubject.next(false))
+      )
+      .subscribe(
+      (allConfig: any) => {
+        this.loadConfigForm(this.data.name, allConfig)
+      }
+    )
+  }
+
+  updateconfig(event) {
+    var config = {
+      metadata: this.xappMetadata,
+      descriptor: this.xappConfigSchema,
+      config: event,
+      layout: this.xappLayout
+    }
+    this.appMgrService.putConfig(config)
+    this.dialogRef.close();
+  }
+
+  loadConfigForm(name: string, allConfig: any) {
+    var xappConfig = allConfig.find(xapp => xapp.metadata.name == name)
+    if (xappConfig != null) {
+      this.xappMetadata = xappConfig.metadata
+      this.xappConfigSchema = xappConfig.descriptor;
+      this.xappConfigData = xappConfig.config;
+      this.xappLayout= xappConfig.layout;
+    } else {
+      this.errorDiaglogService.displayError("Cannot find configration data for " + name);
+      this.dialogRef.close();
+    }
+  }
+}
index 21860ac..9100de4 100644 (file)
@@ -26,6 +26,8 @@ import { ConfirmDialogService } from './../services/ui/confirm-dialog.service';
 import { NotificationService } from './../services/ui/notification.service';
 import { CatalogDataSource } from './catalog.datasource';
 import { XMDeployableApp } from '../interfaces/app-mgr.types';
+import { MatDialog } from '@angular/material/dialog';
+import { AppConfigurationComponent } from './../app-configuration/app-configuration.component';
 
 @Component({
   selector: 'rd-app-catalog',
@@ -41,6 +43,7 @@ export class CatalogComponent implements OnInit {
   constructor(
     private appMgrService: AppMgrService,
     private confirmDialogService: ConfirmDialogService,
+    private dialog: MatDialog,
     private errorDiaglogService: ErrorDialogService,
     private notificationService: NotificationService) { }
 
@@ -49,9 +52,16 @@ export class CatalogComponent implements OnInit {
     this.dataSource.loadTable();
   }
 
-  onConfigureApp(name: string): void {
-    const aboutError = 'Configure not implemented (yet)';
-    this.errorDiaglogService.displayError(aboutError);
+  onConfigureApp(xapp: XMDeployableApp): void {
+    const dialogRef = this.dialog.open(AppConfigurationComponent, {
+      width: '40%',
+      maxHeight:'500px',
+      position: {
+        top:'10%'
+      },
+      data: xapp
+    });
+
   }
 
   onDeployApp(app: XMDeployableApp): void {
index 4ffaa52..8b59594 100644 (file)
@@ -39,6 +39,7 @@ import { AcXappComponent } from './ac-xapp/ac-xapp.component';
 import { AddDashboardUserDialogComponent } from './user/add-dashboard-user-dialog/add-dashboard-user-dialog.component';
 import { AnrEditNcrDialogComponent } from './anr-xapp/anr-edit-ncr-dialog.component';
 import { AnrXappComponent } from './anr-xapp/anr-xapp.component';
+import { AppConfigurationComponent } from './app-configuration/app-configuration.component';
 import { AppControlComponent } from './app-control/app-control.component';
 import { AppMgrService } from './services/app-mgr/app-mgr.service';
 import { CatalogCardComponent } from './ui/catalog-card/catalog-card.component';
@@ -52,8 +53,10 @@ 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 { MainComponent } from './main/main.component';
+import { MaterialDesignFrameworkModule } from 'angular6-json-schema-form';
 import { ModalEventComponent } from './ui/modal-event/modal-event.component';
 import { RanControlComponent } from './ran-control/ran-control.component';
 import { RanControlConnectDialogComponent } from './ran-control/ran-connection-dialog.component';
@@ -71,6 +74,7 @@ import { UserComponent } from './user/user.component';
     AddDashboardUserDialogComponent,
     AnrEditNcrDialogComponent,
     AnrXappComponent,
+    AppConfigurationComponent,
     AppControlComponent,
     CatalogCardComponent,
     CatalogComponent,
@@ -95,6 +99,7 @@ import { UserComponent } from './user/user.component';
     BrowserModule,
     BrowserAnimationsModule,
     ChartsModule,
+    FlexLayoutModule,
     FormsModule,
     HttpClientModule,
     MatButtonModule,
@@ -102,6 +107,7 @@ import { UserComponent } from './user/user.component';
     MatCardModule,
     MatCheckboxModule,
     MatDialogModule,
+    MaterialDesignFrameworkModule,
     MatExpansionModule,
     MatFormFieldModule,
     MatGridListModule,
@@ -142,15 +148,16 @@ import { UserComponent } from './user/user.component';
     MatButtonModule,
     MatInputModule,
     RanControlConnectDialogComponent,
-    ErrorDialogComponent,
+    ErrorDialogComponent
   ],
   entryComponents: [
     AddDashboardUserDialogComponent,
     AnrEditNcrDialogComponent,
+    AppConfigurationComponent,
     ConfirmDialogComponent,
     EditDashboardUserDialogComponent,
     ErrorDialogComponent,
-    RanControlConnectDialogComponent,
+    RanControlConnectDialogComponent
   ],
   providers: [
     AppMgrService,
index 13df94c..33dd1cb 100644 (file)
@@ -48,4 +48,14 @@ export class AppMgrService {
     return this.httpClient.delete((this.basePath + '/' + 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.post((this.basePath + '/config' ), config, { observe: 'response' });
+  }
+
+
 }
index 3c8f59c..f870b20 100644 (file)
@@ -21,7 +21,7 @@
   <div class="header__container">
     <span class="card__title">xApp Catalog</span><br><br><br>
     <div style="color: black; size: 1em; text-align: center">
-        <mat-icon>wifi</mat-icon> Dual Connectivity</div>
+        <mat-icon>wifi</mat-icon> UE Event Collector</div>
     <div style="color: black; size: 1em; text-align: center">
         <mat-icon>check_box</mat-icon> Admission Control</div>
     <div style="color: black; size: 1em; text-align: center">
diff --git a/webapp-frontend/src/assets/mockdata/config.json b/webapp-frontend/src/assets/mockdata/config.json
new file mode 100644 (file)
index 0000000..255b3fe
--- /dev/null
@@ -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