-->
<div class="text-muted logo" fxLayout="row" fxLayoutGap="50px" fxLayoutAlign="space-around center">
- <div *ngIf="policyInstanceId">[{{this.ric}}] Instance ID: {{policyInstanceId}}</div>
+ <div *ngIf="policyInstanceId">[{{ric}}] Instance ID: {{policyInstanceId}}</div>
</div>
<div class="mat-elevation-z8 header row" [ngClass]="{'header-dark': darkMode}">
<div class="logo">
<svg class="logo__icon" viewBox="150.3 22.2 1000 50">
<text class="logo__text" [ngClass]="{'logo__text-dark': darkMode}" font-size="30" font-weight="600"
letter-spacing=".1em" transform="translate(149 56)">
- <tspan *ngIf="!this.policyInstanceId">Create new policy instance of type </tspan>
- <tspan *ngIf="jsonSchemaObject.title"> {{this.jsonSchemaObject.title}}</tspan>
- <tspan *ngIf="!jsonSchemaObject.title"> {{this.policyTypeName}}</tspan>
+ <tspan *ngIf="!policyInstanceId">Create new policy instance of type </tspan>
+ <tspan *ngIf="jsonSchemaObject.title"> {{jsonSchemaObject.title}}</tspan>
+ <tspan *ngIf="!jsonSchemaObject.title"> {{policyTypeName}}</tspan>
</text>
</svg>
</div>
fxLayoutAlign.lt-sm="flex-start center">
<mat-card class="card" [ngClass]="{'card-dark': darkMode}">
- <mat-form-field *ngIf="!this.policyInstanceId" appearance="fill">
- <mat-select id="ricSelector" formControlName="ricSelector" matInput required [(value)]="this.ric"
+ <mat-form-field *ngIf="!policyInstanceId" appearance="fill">
+ <mat-select id="ricSelector" formControlName="ricSelector" matInput required [(value)]="ric"
placeholder="Target"
matTooltip="Element where the policy instance resides, e.g. a gNodeB or Near-RT RIC">
- <mat-option *ngFor="let ric of this.allRics" [value]="ric">
+ <mat-option *ngFor="let ric of allRics" [value]="ric">
{{ric.ric_id}}
</mat-option>
</mat-select>
</div>
</mat-form-field>
- <h4 class="default-cursor" (click)="toggleVisible('form')">
- <mat-icon matTooltip="Properties">{{isVisible.form ? 'expand_less' : 'expand_more'}}</mat-icon>
- Properties
- </h4>
- <div *ngIf="isVisible.form" class="json-schema-form" [@expandSection]="true">
- <div *ngIf="!formActive">{{jsonFormStatusMessage}}</div>
-
- <json-schema-form *ngIf="formActive" [form]="jsonSchemaObject"
- [(data)]="jsonObject" [options]="jsonFormOptions" [framework]="'material-design'" [language]="'en'"
- (onChanges)="onChanges($event)" (onSubmit)="onSubmit()" (isValid)="isValid($event)"
- (validationErrors)="validationErrors($event)">
- </json-schema-form>
- </div>
+ <nrcp-typed-policy-editor [jsonSchemaObject]="jsonSchemaObject" [jsonObject]="data.instanceJson" [darkMode]="darkMode"></nrcp-typed-policy-editor>
<hr />
- <button mat-raised-button (click)="this.onClose()">Close</button>
- <button mat-raised-button (click)="this.onSubmit()" [disabled]="!this.formIsValid || !this.ric"
+ <button mat-raised-button (click)="onClose()">Close</button>
+ <button mat-raised-button (click)="onSubmit()" [disabled]="!isJsonFormValid || !ric"
class="submitBtn">Submit</button>
<hr />
- <h4 [class.text-danger]="!formIsValid && !isVisible.json" [class.default-cursor]="formIsValid || isVisible.json"
- (click)="toggleVisible('json')">
- <mat-icon matTooltip="Json">{{isVisible.json ? 'expand_less' : 'expand_more'}}</mat-icon>
- Json
- </h4>
- <div *ngIf="isVisible.json" fxLayout="column" [@expandSection]="true">
- <div>
- <strong *ngIf="formIsValid || prettyValidationErrors" [class.text-muted]="formIsValid"
- [class.text-danger]="!formIsValid">
- {{formIsValid ? 'Json' : 'Not valid'}}
- </strong>
- <span *ngIf="!formIsValid && !prettyValidationErrors">Invalid form</span>
- <span *ngIf="prettyValidationErrors">— errors:</span>
- <div *ngIf="prettyValidationErrors" class="text-danger" [innerHTML]="prettyValidationErrors"></div>
- </div>
- <div>
- <pre [class.text__dark]="this.darkMode">{{prettyLiveFormData}}</pre>
- </div>
- </div>
-
- <h4 class="default-cursor" (click)="toggleVisible('schema')">
- <mat-icon matTooltip="Json Schema">{{isVisible.schema ? 'expand_less' : 'expand_more'}}</mat-icon>
- Json Schema
- </h4>
- <div *ngIf="isVisible.schema" fxLayout="column" [@expandSection]="true">
- <strong class="text-muted">Schema</strong>
- <pre [class.text__dark]="this.darkMode">{{schemaAsString}}</pre>
- </div>
</mat-card>
</div>
\ No newline at end of file
* limitations under the License.
* ========================LICENSE_END===================================
*/
-import { animate, state, style, transition, trigger } from '@angular/animations';
import { AfterViewInit, Component, Inject, OnInit, ViewChild } from '@angular/core';
import { MatDialogConfig, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
-import { JsonPointer } from 'angular6-json-schema-form';
import * as uuid from 'uuid';
import { CreatePolicyInstance, PolicyInstance, PolicyTypeSchema } from '../../interfaces/policy.types';
import { PolicyService } from '../../services/policy/policy.service';
import { FormGroup, FormControl, Validators } from '@angular/forms';
import { ChangeDetectorRef } from '@angular/core';
import { Ric, Rics } from '../../interfaces/ric';
+import { TypedPolicyEditorComponent } from '../typed-policy-editor/typed-policy-editor.component';
@Component({
selector: 'nrcp-policy-instance-dialog',
templateUrl: './policy-instance-dialog.component.html',
- styleUrls: ['./policy-instance-dialog.component.scss'],
- animations: [
- trigger('expandSection', [
- state('in', style({ height: '*' })),
- transition(':enter', [
- style({ height: 0 }), animate(100),
- ]),
- transition(':leave', [
- style({ height: '*' }),
- animate(100, style({ height: 0 })),
- ]),
- ]),
- ],
+ styleUrls: ['./policy-instance-dialog.component.scss']
})
export class PolicyInstanceDialogComponent implements OnInit, AfterViewInit {
+ @ViewChild(TypedPolicyEditorComponent)
+ policyEditor: TypedPolicyEditorComponent;
instanceForm: FormGroup;
- formActive = false;
- isVisible = {
- form: true,
- json: false,
- schema: false
- };
-
- jsonFormStatusMessage = 'Loading form...';
- jsonSchemaObject: any = {};
- jsonObject: any = {};
-
-
- jsonFormOptions: any = {
- addSubmit: false, // Add a submit button if layout does not have one
- debug: false, // Don't show inline debugging information
- loadExternalAssets: true, // Load external css and JavaScript for frameworks
- returnEmptyFields: false, // Don't return values for empty input fields
- setSchemaDefaults: true, // Always use schema defaults for empty fields
- defautWidgetOptions: { feedback: true }, // Show inline feedback icons
- };
-
- liveFormData: any = {};
- formValidationErrors: any;
- formIsValid = false;
-
+ ric: string;
+ allRics: Ric[];
policyInstanceId: string; // null if not yet created
policyTypeName: string;
+ jsonSchemaObject: any = {};
darkMode: boolean;
- ric: string;
- allRics: Ric[];
private fetchRics() {
console.log('fetchRics ' + this.policyTypeName);
private dataService: PolicyService,
private errorService: ErrorDialogService,
private notificationService: NotificationService,
- @Inject(MAT_DIALOG_DATA) private data,
+ @Inject(MAT_DIALOG_DATA) public data,
private dialogRef: MatDialogRef<PolicyInstanceDialogComponent>,
private ui: UiService) {
- this.formActive = false;
this.policyInstanceId = data.instanceId;
this.policyTypeName = data.name;
this.jsonSchemaObject = data.createSchema;
- this.jsonObject = data.instanceJson;
this.ric = data.ric;
}
ngOnInit() {
- this.jsonFormStatusMessage = 'Init';
- this.formActive = true;
this.ui.darkModeState.subscribe((isDark) => {
this.darkMode = isDark;
});
if (this.policyInstanceId == null) {
this.policyInstanceId = uuid.v4();
}
- const policyJson: string = this.prettyLiveFormData;
+ const policyJson: string = this.policyEditor.prettyLiveFormData;
const self: PolicyInstanceDialogComponent = this;
let createPolicyInstance: CreatePolicyInstance = this.createPolicyInstance(policyJson);
this.dataService.putPolicy(createPolicyInstance).subscribe(
this.dialogRef.close();
}
- public onChanges(formData: any) {
- this.liveFormData = formData;
- }
-
- get prettyLiveFormData(): string {
- return JSON.stringify(this.liveFormData, null, 2);
- }
-
- get schemaAsString(): string {
- return JSON.stringify(this.jsonSchemaObject, null, 2);
- }
-
- get jsonAsString(): string {
- return JSON.stringify(this.jsonObject, null, 2);
- }
-
- isValid(isValid: boolean): void {
- this.formIsValid = isValid;
- }
-
- validationErrors(validationErrors: any): void {
- this.formValidationErrors = validationErrors;
- }
-
- get prettyValidationErrors() {
- if (!this.formValidationErrors) { return null; }
- const errorArray = [];
- for (const error of this.formValidationErrors) {
- const message = error.message;
- const dataPathArray = JsonPointer.parse(error.dataPath);
- if (dataPathArray.length) {
- let field = dataPathArray[0];
- for (let i = 1; i < dataPathArray.length; i++) {
- const key = dataPathArray[i];
- field += /^\d+$/.test(key) ? `[${key}]` : `.${key}`;
- }
- errorArray.push(`${field}: ${message}`);
- } else {
- errorArray.push(message);
- }
- }
- return errorArray.join('<br>');
- }
-
- private parseJson(str: string): string {
- try {
- if (str != null) {
- return JSON.parse(str);
- }
- } catch (jsonError) {
- this.jsonFormStatusMessage =
- 'Invalid JSON\n' +
- 'parser returned:\n\n' + jsonError;
- }
- return null;
- }
-
- public toggleVisible(item: string) {
- this.isVisible[item] = !this.isVisible[item];
+ get isJsonFormValid(): boolean {
+ return this.policyEditor ? this.policyEditor.formIsValid : false;
}
}
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2021: Nordix Foundation
+// %%
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================LICENSE_END===================================
+//
+
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatTableModule } from '@angular/material/table';
import { Routes, RouterModule } from '@angular/router';
import { RicSelectorComponent } from './ric-selector/ric-selector.component';
import { NoTypePolicyEditorComponent } from './no-type-policy-editor/no-type-policy-editor.component';
+import { TypedPolicyEditorComponent } from './typed-policy-editor/typed-policy-editor.component';
const routes:Routes = [
{path: 'policy', component: PolicyControlComponent}
PolicyInstanceDialogComponent,
RicSelectorComponent,
NoTypePolicyEditorComponent,
+ TypedPolicyEditorComponent,
],
imports: [
CommonModule,
--- /dev/null
+<!--
+ -
+ ========================LICENSE_START=================================
+ O-RAN-SC
+ %%
+ Copyright (C) 2021: Nordix Foundation
+ %%
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ ========================LICENSE_END===================================
+
+-->
+
+<h4 class="default-cursor" (click)="toggleVisible('form')">
+ <mat-icon matTooltip="Properties">{{isVisible.form ? 'expand_less' : 'expand_more'}}</mat-icon>
+ Properties
+</h4>
+<div *ngIf="isVisible.form" class="json-schema-form" [@expandSection]="true">
+ <div *ngIf="!formActive">{{jsonFormStatusMessage}}</div>
+
+ <json-schema-form id="json-schema-form" *ngIf="formActive" [form]="jsonSchemaObject"
+ [(data)]="jsonObject" [options]="jsonFormOptions" [framework]="'material-design'" [language]="'en'"
+ (onChanges)="onChanges($event)" (isValid)="isValid($event)"
+ (validationErrors)="validationErrors($event)">
+ </json-schema-form>
+</div>
+<h4 [class.text-danger]="!formIsValid && !isVisible.json" [class.default-cursor]="formIsValid || isVisible.json"
+(click)="toggleVisible('json')">
+<mat-icon matTooltip="Json">{{isVisible.json ? 'expand_less' : 'expand_more'}}</mat-icon>
+Json
+</h4>
+<div *ngIf="isVisible.json" fxLayout="column" [@expandSection]="true">
+<div>
+ <strong *ngIf="formIsValid || prettyValidationErrors" [class.text-muted]="formIsValid"
+ [class.text-danger]="!formIsValid">
+ {{formIsValid ? 'Json' : 'Not valid'}}
+ </strong>
+ <span *ngIf="!formIsValid && !prettyValidationErrors">Invalid form</span>
+ <span *ngIf="prettyValidationErrors">— errors:</span>
+ <div *ngIf="prettyValidationErrors" class="text-danger" [innerHTML]="prettyValidationErrors"></div>
+</div>
+<div>
+ <pre [class.text__dark]="darkMode">{{prettyLiveFormData}}</pre>
+</div>
+</div>
+
+<h4 class="default-cursor" (click)="toggleVisible('schema')">
+<mat-icon matTooltip="Json Schema">{{isVisible.schema ? 'expand_less' : 'expand_more'}}</mat-icon>
+Json Schema
+</h4>
+<div *ngIf="isVisible.schema" fxLayout="column" [@expandSection]="true">
+<strong class="text-muted">Schema</strong>
+<pre [class.text__dark]="darkMode">{{schemaAsString}}</pre>
+</div>
--- /dev/null
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2021: Nordix Foundation
+// %%
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================LICENSE_END===================================
+//
+
+.text__dark {
+ color: white;
+}
--- /dev/null
+import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/compiler';
+import { ChangeDetectorRef } from '@angular/core';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MatIconModule } from '@angular/material/icon';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+
+import { TypedPolicyEditorComponent } from './typed-policy-editor.component';
+
+describe('TypedPolicyEditorComponent', () => {
+ let component: TypedPolicyEditorComponent;
+ let fixture: ComponentFixture<TypedPolicyEditorComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ BrowserAnimationsModule,
+ MatIconModule
+ ],
+ declarations: [
+ TypedPolicyEditorComponent
+ ],
+ schemas: [
+ CUSTOM_ELEMENTS_SCHEMA
+ ],
+ providers: [
+ ChangeDetectorRef
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(TypedPolicyEditorComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2021: Nordix Foundation
+// %%
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+// ========================LICENSE_END===================================
+//
+
+import { animate, state, style, transition, trigger } from '@angular/animations';
+import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core';
+import { JsonPointer } from 'angular6-json-schema-form';
+
+@Component({
+ selector: 'nrcp-typed-policy-editor',
+ templateUrl: './typed-policy-editor.component.html',
+ styleUrls: ['./typed-policy-editor.component.scss'],
+ animations: [
+ trigger('expandSection', [
+ state('in', style({ height: '*' })),
+ transition(':enter', [
+ style({ height: 0 }), animate(100),
+ ]),
+ transition(':leave', [
+ style({ height: '*' }),
+ animate(100, style({ height: 0 })),
+ ]),
+ ]),
+ ],
+
+})
+export class TypedPolicyEditorComponent implements OnInit {
+ jsonFormOptions: any = {
+ addSubmit: false, // Add a submit button if layout does not have one
+ debug: false, // Don't show inline debugging information
+ loadExternalAssets: false, // Load external css and JavaScript for frameworks
+ returnEmptyFields: false, // Don't return values for empty input fields
+ setSchemaDefaults: true, // Always use schema defaults for empty fields
+ defautWidgetOptions: { feedback: true }, // Show inline feedback icons
+ };
+
+ @Input() jsonSchemaObject: any = {};
+ @Input() jsonObject: any = {};
+ @Input() darkMode: boolean;
+
+ isVisible = {
+ form: true,
+ json: false,
+ schema: false
+ };
+ formActive: boolean = false;
+ jsonFormStatusMessage: string = 'Loading form...';
+ liveFormData: any = {};
+ formIsValid: boolean = false;
+ formValidationErrors: any;
+
+ constructor(
+ private cdr: ChangeDetectorRef) {
+ this.formActive = false;
+ }
+
+ ngOnInit(): void {
+ this.formActive = true;
+ }
+
+ ngAfterViewInit() {
+ this.cdr.detectChanges();
+ }
+
+ public onChanges(formData: any) {
+ this.liveFormData = formData;
+ }
+
+ get prettyLiveFormData(): string {
+ return JSON.stringify(this.liveFormData, null, 2);
+ }
+
+ get schemaAsString(): string {
+ return JSON.stringify(this.jsonSchemaObject, null, 2);
+ }
+
+ get jsonAsString(): string {
+ return JSON.stringify(this.jsonObject, null, 2);
+ }
+
+ isValid(isValid: boolean): void {
+ this.formIsValid = isValid;
+ }
+
+ validationErrors(validationErrors: any): void {
+ this.formValidationErrors = validationErrors;
+ }
+
+ get prettyValidationErrors() {
+ if (!this.formValidationErrors) { return null; }
+ const errorArray = [];
+ for (const error of this.formValidationErrors) {
+ const message = error.message;
+ const dataPathArray = JsonPointer.parse(error.dataPath);
+ if (dataPathArray.length) {
+ let field = dataPathArray[0];
+ for (let i = 1; i < dataPathArray.length; i++) {
+ const key = dataPathArray[i];
+ field += /^\d+$/.test(key) ? `[${key}]` : `.${key}`;
+ }
+ errorArray.push(`${field}: ${message}`);
+ } else {
+ errorArray.push(message);
+ }
+ }
+ return errorArray.join('<br>');
+ }
+
+ public toggleVisible(item: string) {
+ this.isVisible[item] = !this.isVisible[item];
+ }
+}