70c1057bf2b6a6b41ccab912cbbb8b1a078a82cc
[portal/nonrtric-controlpanel.git] / webapp-frontend / src / app / policy-control / policy-instance-dialog.component.ts
1 /*-
2  * ========================LICENSE_START=================================
3  * O-RAN-SC
4  * %%
5  * Copyright (C) 2019 Nordix Foundation
6  * %%
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ========================LICENSE_END===================================
19  */
20 import { animate, state, style, transition, trigger } from '@angular/animations';
21 import { AfterViewInit, Component, Inject, OnInit, ViewChild } from '@angular/core';
22 import { MatDialogConfig, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';
23 import { MatMenuTrigger } from '@angular/material/menu';
24 import { JsonPointer } from 'angular6-json-schema-form';
25 import * as uuid from 'uuid';
26 import { CreatePolicyInstance, PolicyInstance, PolicyTypeSchema } from '../interfaces/policy.types';
27 import { PolicyService } from '../services/policy/policy.service';
28 import { ErrorDialogService } from '../services/ui/error-dialog.service';
29 import { NotificationService } from './../services/ui/notification.service';
30 import { UiService } from '../services/ui/ui.service';
31 import { HttpErrorResponse } from '@angular/common/http';
32 import { FormGroup, FormControl, Validators } from '@angular/forms';
33 import { ChangeDetectorRef } from '@angular/core';
34 import { Ric } from '../interfaces/ric';
35
36
37 @Component({
38     selector: 'nrcp-policy-instance-dialog',
39     templateUrl: './policy-instance-dialog.component.html',
40     styleUrls: ['./policy-instance-dialog.component.scss'],
41     animations: [
42         trigger('expandSection', [
43             state('in', style({ height: '*' })),
44             transition(':enter', [
45                 style({ height: 0 }), animate(100),
46             ]),
47             transition(':leave', [
48                 style({ height: '*' }),
49                 animate(100, style({ height: 0 })),
50             ]),
51         ]),
52     ],
53 })
54 export class PolicyInstanceDialogComponent implements OnInit, AfterViewInit {
55     instanceForm: FormGroup;
56
57
58     formActive = false;
59     isVisible = {
60         form: true,
61         json: false,
62         schema: false
63     };
64
65     jsonFormStatusMessage = 'Loading form...';
66     jsonSchemaObject: any = {};
67     jsonObject: any = {};
68
69
70     jsonFormOptions: any = {
71         addSubmit: false, // Add a submit button if layout does not have one
72         debug: false, // Don't show inline debugging information
73         loadExternalAssets: true, // Load external css and JavaScript for frameworks
74         returnEmptyFields: false, // Don't return values for empty input fields
75         setSchemaDefaults: true, // Always use schema defaults for empty fields
76         defautWidgetOptions: { feedback: true }, // Show inline feedback icons
77     };
78
79     liveFormData: any = {};
80     formValidationErrors: any;
81     formIsValid = false;
82
83     @ViewChild(MatMenuTrigger, { static: true }) menuTrigger: MatMenuTrigger;
84
85     policyInstanceId: string; // null if not yet created
86     policyTypeName: string;
87     darkMode: boolean;
88     ric: string;
89     allRics: Ric[];
90
91     private fetchRics() {
92         console.log('fetchRics ' + this.policyTypeName);
93         const self: PolicyInstanceDialogComponent = this;
94         this.dataService.getRics(this.policyTypeName).subscribe(
95             {
96                 next(value: Ric[]) {
97                     self.allRics = value;
98                     console.log(value);
99                 },
100                 error(error: HttpErrorResponse) {
101                     self.errorService.displayError('Fetching of rics failed: ' + error.message);
102                 },
103                 complete() { }
104             });
105     }
106
107     constructor(
108         private cdr: ChangeDetectorRef,
109         private dataService: PolicyService,
110         private errorService: ErrorDialogService,
111         private notificationService: NotificationService,
112         @Inject(MAT_DIALOG_DATA) private data,
113         private dialogRef: MatDialogRef<PolicyInstanceDialogComponent>,
114         private ui: UiService) {
115         this.formActive = false;
116         this.policyInstanceId = data.instanceId;
117         this.policyTypeName = data.name;
118         this.jsonSchemaObject = data.createSchema;
119         this.jsonObject = data.instanceJson;
120         this.ric = data.ric;
121     }
122
123     ngOnInit() {
124         this.jsonFormStatusMessage = 'Init';
125         this.formActive = true;
126         this.ui.darkModeState.subscribe((isDark) => {
127             this.darkMode = isDark;
128         });
129         this.instanceForm = new FormGroup({
130             'ricSelector': new FormControl(this.ric, [
131                 Validators.required
132             ])
133         });
134         if (!this.policyInstanceId) {
135             this.fetchRics();
136         }
137     }
138
139     ngAfterViewInit() {
140         this.cdr.detectChanges();
141     }
142
143     get ricSelector() { return this.instanceForm.get('ricSelector'); }
144
145     onSubmit() {
146         if (this.policyInstanceId == null) {
147             this.policyInstanceId = uuid.v4();
148         }
149         const policyJson: string = this.prettyLiveFormData;
150         const self: PolicyInstanceDialogComponent = this;
151         let createPolicyInstance = this.createPolicyInstance(policyJson);
152         this.dataService.putPolicy(createPolicyInstance).subscribe(
153             {
154                 next(_) {
155                     self.notificationService.success('Policy ' + self.policyTypeName + ':' + self.policyInstanceId +
156                         ' submitted');
157                 },
158                 error(error: HttpErrorResponse) {
159                     self.errorService.displayError('Submit failed: ' + error.error);
160                 },
161                 complete() { }
162             });
163     }
164
165     private createPolicyInstance(policyJson: string) {
166         let createPolicyInstance = {} as CreatePolicyInstance;
167         createPolicyInstance.policy_data = JSON.parse(policyJson);
168         createPolicyInstance.policy_id = this.policyInstanceId;
169         createPolicyInstance.policytype_id = this.policyTypeName;
170         createPolicyInstance.ric_id = (!this.ricSelector.value.ric_id) ? this.ric : this.ricSelector.value.ric_id;
171         createPolicyInstance.service_id = 'controlpanel';
172         return createPolicyInstance;
173     }
174
175     onClose() {
176         this.dialogRef.close();
177     }
178
179     public onChanges(formData: any) {
180         this.liveFormData = formData;
181     }
182
183     get prettyLiveFormData(): string {
184         return JSON.stringify(this.liveFormData, null, 2);
185     }
186
187     get schemaAsString(): string {
188         return JSON.stringify(this.jsonSchemaObject, null, 2);
189     }
190
191     get jsonAsString(): string {
192         return JSON.stringify(this.jsonObject, null, 2);
193     }
194
195     isValid(isValid: boolean): void {
196         this.formIsValid = isValid;
197     }
198
199     validationErrors(validationErrors: any): void {
200         this.formValidationErrors = validationErrors;
201     }
202
203     get prettyValidationErrors() {
204         if (!this.formValidationErrors) { return null; }
205         const errorArray = [];
206         for (const error of this.formValidationErrors) {
207             const message = error.message;
208             const dataPathArray = JsonPointer.parse(error.dataPath);
209             if (dataPathArray.length) {
210                 let field = dataPathArray[0];
211                 for (let i = 1; i < dataPathArray.length; i++) {
212                     const key = dataPathArray[i];
213                     field += /^\d+$/.test(key) ? `[${key}]` : `.${key}`;
214                 }
215                 errorArray.push(`${field}: ${message}`);
216             } else {
217                 errorArray.push(message);
218             }
219         }
220         return errorArray.join('<br>');
221     }
222
223     private parseJson(str: string): string {
224         try {
225             if (str != null) {
226                 return JSON.parse(str);
227             }
228         } catch (jsonError) {
229             this.jsonFormStatusMessage =
230                 'Invalid JSON\n' +
231                 'parser returned:\n\n' + jsonError;
232         }
233         return null;
234     }
235
236     public toggleVisible(item: string) {
237         this.isVisible[item] = !this.isVisible[item];
238     }
239 }
240
241 export function getPolicyDialogProperties(policyTypeSchema: PolicyTypeSchema, instance: PolicyInstance, darkMode: boolean): MatDialogConfig {
242     const createSchema = policyTypeSchema.schemaObject;
243     const instanceId = instance ? instance.policy_id : null;
244     const instanceJson = instance ? instance.policy_data : null;
245     const name = policyTypeSchema.name;
246     const ric = instance ? instance.ric_id : null;
247     return {
248         maxWidth: '1200px',
249         maxHeight: '900px',
250         width: '900px',
251         role: 'dialog',
252         disableClose: false,
253         panelClass: darkMode ? 'dark-theme' : '',
254         data: {
255             createSchema,
256             instanceId,
257             instanceJson,
258             name,
259             ric
260         }
261     };
262 }
263