319efaa30b18885c96a46648c97e6371dbea2bc6
[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 { 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
34
35 @Component({
36     selector: 'rd-policy-instance-dialog',
37     templateUrl: './policy-instance-dialog.component.html',
38     styleUrls: ['./policy-instance-dialog.component.scss'],
39     animations: [
40         trigger('expandSection', [
41             state('in', style({ height: '*' })),
42             transition(':enter', [
43                 style({ height: 0 }), animate(100),
44             ]),
45             transition(':leave', [
46                 style({ height: '*' }),
47                 animate(100, style({ height: 0 })),
48             ]),
49         ]),
50     ],
51 })
52 export class PolicyInstanceDialogComponent implements OnInit, AfterViewInit {
53     instanceForm: FormGroup;
54
55
56     formActive = false;
57     isVisible = {
58         form: true,
59         json: false,
60         schema: false
61     };
62
63     jsonFormStatusMessage = 'Loading form...';
64     jsonSchemaObject: any = {};
65     jsonObject: any = {};
66
67
68     jsonFormOptions: any = {
69         addSubmit: false, // Add a submit button if layout does not have one
70         debug: false, // Don't show inline debugging information
71         loadExternalAssets: true, // Load external css and JavaScript for frameworks
72         returnEmptyFields: false, // Don't return values for empty input fields
73         setSchemaDefaults: true, // Always use schema defaults for empty fields
74         defautWidgetOptions: { feedback: true }, // Show inline feedback icons
75     };
76
77     liveFormData: any = {};
78     formValidationErrors: any;
79     formIsValid = false;
80
81     @ViewChild(MatMenuTrigger, { static: true }) menuTrigger: MatMenuTrigger;
82
83     policyInstanceId: string; // null if not yet created
84     policyTypeName: string;
85     darkMode: boolean;
86     ric: string;
87     allRics: string[];
88
89     private fetchRics() {
90         console.log('fetchRics ' + this.policyTypeName);
91         const self: PolicyInstanceDialogComponent = this;
92         this.dataService.getRics(this.policyTypeName).subscribe(
93             {
94                 next(value) {
95                     self.allRics = value;
96                     console.log(value);
97                 },
98                 error(error: HttpErrorResponse) {
99                     self.errorService.displayError('Fetching of rics failed: ' + error.message);
100                 },
101                 complete() { }
102             });
103     }
104
105     constructor(
106         private dataService: PolicyService,
107         private errorService: ErrorDialogService,
108         private notificationService: NotificationService,
109         @Inject(MAT_DIALOG_DATA) private data,
110         private dialogRef: MatDialogRef<PolicyInstanceDialogComponent>,
111         private ui: UiService) {
112         this.formActive = false;
113         this.policyInstanceId = data.instanceId;
114         this.policyTypeName = data.name;
115         this.jsonSchemaObject = data.createSchema;
116         this.jsonObject = this.parseJson(data.instanceJson);
117         this.ric = data.ric;
118     }
119
120     ngOnInit() {
121         this.jsonFormStatusMessage = 'Init';
122         this.formActive = true;
123         this.ui.darkModeState.subscribe((isDark) => {
124             this.darkMode = isDark;
125         });
126         this.instanceForm = new FormGroup({
127             'ricSelector': new FormControl(this.ric, [
128                 Validators.required
129             ])
130         });
131         if (!this.policyInstanceId) {
132             this.fetchRics();
133         }
134     }
135
136     ngAfterViewInit() {
137     }
138
139     get ricSelector() { return this.instanceForm.get('ricSelector'); }
140
141     onSubmit() {
142         if (this.policyInstanceId == null) {
143             this.policyInstanceId = uuid.v4();
144         }
145         const policyJson: string = this.prettyLiveFormData;
146         const self: PolicyInstanceDialogComponent = this;
147         this.dataService.putPolicy(this.policyTypeName, this.policyInstanceId, policyJson, this.ric).subscribe(
148             {
149                 next(_) {
150                     self.notificationService.success('Policy ' + self.policyTypeName + ':' + self.policyInstanceId +
151                     ' submitted');
152                 },
153                 error(error: HttpErrorResponse) {
154                     self.errorService.displayError('Submit failed: ' + error.error);
155                 },
156                 complete() { }
157             });
158     }
159
160     onClose() {
161         this.dialogRef.close();
162     }
163
164     public onChanges(formData: any) {
165         this.liveFormData = formData;
166     }
167
168     get prettyLiveFormData(): string {
169         return JSON.stringify(this.liveFormData, null, 2);
170     }
171
172     get schemaAsString(): string {
173         return JSON.stringify(this.jsonSchemaObject, null, 2);
174     }
175
176     get jsonAsString(): string {
177         return JSON.stringify(this.jsonObject, null, 2);
178     }
179
180     isValid(isValid: boolean): void {
181         this.formIsValid = isValid;
182     }
183
184     validationErrors(validationErrors: any): void {
185         this.formValidationErrors = validationErrors;
186     }
187
188     get prettyValidationErrors() {
189         if (!this.formValidationErrors) { return null; }
190         const errorArray = [];
191         for (const error of this.formValidationErrors) {
192             const message = error.message;
193             const dataPathArray = JsonPointer.parse(error.dataPath);
194             if (dataPathArray.length) {
195                 let field = dataPathArray[0];
196                 for (let i = 1; i < dataPathArray.length; i++) {
197                     const key = dataPathArray[i];
198                     field += /^\d+$/.test(key) ? `[${key}]` : `.${key}`;
199                 }
200                 errorArray.push(`${field}: ${message}`);
201             } else {
202                 errorArray.push(message);
203             }
204         }
205         return errorArray.join('<br>');
206     }
207
208     private parseJson(str: string): string {
209         try {
210             if (str != null) {
211                 return JSON.parse(str);
212             }
213         } catch (jsonError) {
214             this.jsonFormStatusMessage =
215                 'Invalid JSON\n' +
216                 'parser returned:\n\n' + jsonError;
217         }
218         return null;
219     }
220
221     public toggleVisible(item: string) {
222         this.isVisible[item] = !this.isVisible[item];
223     }
224 }
225
226 export function getPolicyDialogProperties(policyTypeSchema: PolicyTypeSchema, instance: PolicyInstance, darkMode: boolean): MatDialogConfig {
227     const createSchema = policyTypeSchema.schemaObject;
228     const instanceId = instance ? instance.policy_id : null;
229     const instanceJson = instance ? instance.policy_data : null;
230     const name = policyTypeSchema.name;
231     const ric = instance ? instance.ric_id : null;
232     return {
233         maxWidth: '1200px',
234         maxHeight: '900px',
235         width: '900px',
236         role: 'dialog',
237         disableClose: false,
238         panelClass: darkMode ? 'dark-theme' : '',
239         data: {
240             createSchema,
241             instanceId,
242             instanceJson,
243             name,
244             ric
245         }
246     };
247 }
248