Support complex types in interface operation inputs
[sdc.git] / catalog-ui / src / app / ng2 / pages / composition / interface-operatons / operation-creator / add-input / add-input.component.ts
1 /*
2  * -
3  *  ============LICENSE_START=======================================================
4  *  Copyright (C) 2022 Nordix Foundation.
5  *  ================================================================================
6  *  Licensed under the Apache License, Version 2.0 (the "License");
7  *  you may not use this file except in compliance with the License.
8  *  You may obtain a copy of the License at
9  *
10  *       http://www.apache.org/licenses/LICENSE-2.0
11  *
12  *  Unless required by applicable law or agreed to in writing, software
13  *  distributed under the License is distributed on an "AS IS" BASIS,
14  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  *  See the License for the specific language governing permissions and
16  *  limitations under the License.
17  *
18  *  SPDX-License-Identifier: Apache-2.0
19  *  ============LICENSE_END=========================================================
20  */
21
22 import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
23 import {InputOperationParameter} from '../../../../../../models/interfaceOperation';
24 import {IDropDownOption} from 'onap-ui-angular/dist/form-elements/dropdown/dropdown-models';
25 import {Observable} from 'rxjs/Observable';
26 import {AbstractControl, FormControl, FormGroup, ValidationErrors, ValidatorFn, Validators} from '@angular/forms';
27 import {PROPERTY_TYPES} from '../../../../../../utils/constants';
28 import {SchemaProperty, SchemaPropertyGroupModel} from '../../../../../../models/schema-property';
29 import {DataTypeModel} from "../../../../../../models/data-types";
30
31 @Component({
32   selector: 'app-add-input',
33   templateUrl: './add-input.component.html',
34   styleUrls: ['./add-input.component.less']
35 })
36 export class AddInputComponent implements OnInit {
37
38   @Input('dataTypeMap') dataTypeMap$: Observable<Map<string, DataTypeModel>>;
39   @Input('isView') isView: boolean;
40   @Input() existingInputNames: Array<string> = [];
41   @Output('onAddInput') onAddInputEvent: EventEmitter<InputOperationParameter>;
42
43   dataTypeMap: Map<string, DataTypeModel>;
44   inputToAdd: InputOperationParameter;
45   inputTypeOptions: Array<IDropDownOption>;
46   inputSchemaOptions: Array<IDropDownOption>;
47   showForm: boolean = false;
48   showAddLink: boolean = true;
49   showInputSchema: boolean = false;
50
51   inputForm: FormGroup;
52
53   constructor() {
54     this.onAddInputEvent = new EventEmitter<InputOperationParameter>();
55     this.inputTypeOptions = [];
56     this.inputSchemaOptions = [];
57     this.inputToAdd = new InputOperationParameter();
58   }
59
60   schemaValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
61     const type = control.get('type');
62     const schema = control.get('schema');
63     return (type.value === 'list' || type.value === 'map') && !schema.value ? { schemaRequired: true } : null;
64   };
65
66   uniqueNameValidator: ValidatorFn = (control: AbstractControl): ValidationErrors | null => {
67     const name = control.get('name');
68     return this.existingInputNames.indexOf(name.value) === -1 ? null : { nameIsNotUnique: true };
69   };
70
71   ngOnInit() {
72     this.initForm();
73     this.initInputType();
74   }
75
76   private initForm() {
77     this.inputForm = new FormGroup({
78       name: new FormControl({value: '', disabled: this.isView}, [Validators.required, Validators.minLength(1)]),
79       type: new FormControl({value: '', disabled: this.isView}, [Validators.required, Validators.minLength(1)]),
80       schema: new FormControl({value: '', disabled: this.isView})
81     }, { validators: [this.schemaValidator, this.uniqueNameValidator] });
82   }
83
84   private initInputType() {
85     this.dataTypeMap$.subscribe((dataTypesMap: Map<string, DataTypeModel>) => {
86       this.dataTypeMap = dataTypesMap;
87       this.inputTypeOptions = [];
88       this.inputSchemaOptions = [];
89       dataTypesMap.forEach((value, key) => {
90         const entry = {label: key, value: key};
91         this.inputTypeOptions.push(entry);
92         if (key != PROPERTY_TYPES.LIST && key != PROPERTY_TYPES.MAP) {
93           this.inputSchemaOptions.push(entry);
94         }
95       });
96     });
97   }
98
99   onChangeInputType(inputType) {
100     const typeForm = this.inputForm.get('type');
101     if (!inputType) {
102       this.inputToAdd.type = undefined;
103       typeForm.setValue(undefined);
104       this.toggleInputSchema();
105       return;
106     }
107     typeForm.setValue(inputType);
108     this.inputToAdd.type = inputType;
109     this.toggleInputSchema();
110   }
111
112   onChangeInputSchema(inputSchema: string) {
113     const schemaForm = this.inputForm.get('schema');
114     if (!inputSchema) {
115       this.inputToAdd.schema = undefined;
116       schemaForm.setValue(undefined);
117       return;
118     }
119     schemaForm.setValue(inputSchema);
120     this.inputToAdd.schema = new SchemaPropertyGroupModel();
121     this.inputToAdd.schema.property = new SchemaProperty();
122     this.inputToAdd.schema.property.type = inputSchema;
123   }
124
125   onSubmit() {
126     this.trimForm();
127     if (this.inputForm.valid) {
128       const nameForm = this.inputForm.get('name');
129       const typeForm = this.inputForm.get('type');
130       const schemaForm = this.inputForm.get('schema');
131       const input = new InputOperationParameter();
132       input.name = nameForm.value;
133       input.type = typeForm.value;
134       if (this.typeHasSchema()) {
135         input.schema = new SchemaPropertyGroupModel();
136         input.schema.property = new SchemaProperty();
137         input.schema.property.type = schemaForm.value;
138       }
139       input.inputId = this.generateUniqueId();
140       this.onAddInputEvent.emit(input);
141       this.hideAddInput();
142       this.resetForm();
143     }
144   }
145
146   showAddInput() {
147     this.showForm = true;
148     this.showAddLink = false;
149   }
150
151   hideAddInput() {
152     this.showForm = false;
153     this.showAddLink = true;
154   }
155
156   onCancel() {
157     this.hideAddInput();
158     this.resetForm();
159   }
160
161   private generateUniqueId(): string {
162     let result = '';
163     const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
164     const charactersLength = characters.length;
165     for (let i = 0; i < 36; i++ ) {
166       result += characters.charAt(Math.floor(Math.random() * charactersLength));
167     }
168     return result;
169   }
170
171   private resetForm() {
172     this.inputForm.reset();
173     this.showInputSchema = false;
174     this.inputToAdd = new InputOperationParameter();
175   }
176
177   getSchemaType() {
178     return this.inputToAdd.schema == undefined ? undefined : this.inputToAdd.schema.property.type;
179   }
180
181   getSchemaPlaceholder() {
182     const schemaType = this.getSchemaType();
183     return schemaType === undefined ? 'Select...' : schemaType;
184   }
185
186   private toggleInputSchema() {
187     this.showInputSchema = this.typeHasSchema();
188   }
189
190   private typeHasSchema() {
191     const typeForm = this.inputForm.get('type');
192     return typeForm.value == PROPERTY_TYPES.LIST || typeForm.value == PROPERTY_TYPES.MAP;
193   }
194
195   private trimForm() {
196     const nameForm = this.inputForm.get('name');
197     if (nameForm.value) {
198       nameForm.setValue(nameForm.value.trim());
199     }
200     const typeForm = this.inputForm.get('type');
201     if (typeForm.value) {
202       typeForm.setValue(typeForm.value.trim());
203     }
204     const schemaForm = this.inputForm.get('schema');
205     if (schemaForm.value) {
206       schemaForm.setValue(schemaForm.value.trim());
207     }
208   }
209
210 }