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