Fix validation bug in operation modal
[sdc.git] / catalog-ui / src / app / ng2 / pages / interface-operation / operation-creator / operation-creator.component.ts
1 import * as _ from "lodash";
2 import {Component, ViewChild} from '@angular/core';
3
4 import {Subscription} from "rxjs/Subscription";
5
6 import {TranslateService} from "app/ng2/shared/translator/translate.service";
7 import {WorkflowServiceNg2} from 'app/ng2/services/workflow.service';
8 import {OperationModel, OperationParameter, InputBEModel, RadioButtonModel, WORKFLOW_ASSOCIATION_OPTIONS} from 'app/models';
9
10 import {Tabs, Tab} from "app/ng2/components/ui/tabs/tabs.component";
11 import {DropdownValue} from "app/ng2/components/ui/form-components/dropdown/ui-element-dropdown.component";
12
13 export interface OperationCreatorInput {
14     operation: OperationModel,
15     inputProperties: Array<InputBEModel>,
16     enableWorkflowAssociation: boolean,
17     readonly: boolean,
18     isService: boolean
19 }
20
21
22 @Component({
23     selector: 'operation-creator',
24     templateUrl: './operation-creator.component.html',
25     styleUrls: ['./operation-creator.component.less'],
26     providers: [TranslateService]
27 })
28
29 export class OperationCreatorComponent {
30
31     input: OperationCreatorInput;
32     operation: OperationModel;
33
34     workflows: Array<DropdownValue> = [];
35     workflowVersions: Array<DropdownValue> = [];
36     inputProperties: Array<DropdownValue> = [];
37     inputPropertyTypes: { [key: string]: string };
38
39     inputParameters: Array<OperationParameter> = [];
40     noAssignInputParameters: Array<OperationParameter> = [];
41     assignInputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
42
43     outputParameters: Array<OperationParameter> = [];
44     noAssignOutputParameters: Array<OperationParameter> = [];
45     assignOutputParameters: { [key: string]: { [key: string]: Array<OperationParameter>; }; } = {};
46
47     tableParameters: Array<OperationParameter> = [];
48
49     associationOptions: Array<DropdownValue>;
50
51     enableWorkflowAssociation: boolean;
52     isEditMode: boolean = false;
53     isLoading: boolean = false;
54     readonly: boolean;
55     isService: boolean;
56
57     propertyTooltipText: String;
58
59     TYPE_INPUT = 'Inputs';
60     TYPE_OUTPUT = 'Outputs';
61
62     @ViewChild('propertyInputTabs') propertyInputTabs: Tabs;
63     currentTab: String;
64
65     constructor(private workflowServiceNg2: WorkflowServiceNg2, private translateService: TranslateService) {
66         this.translateService.languageChangedObservable.subscribe(lang => {
67             this.propertyTooltipText = this.translateService.translate("OPERATION_PROPERTY_TOOLTIP_TEXT");
68
69             this.associationOptions = [
70                 new DropdownValue(WORKFLOW_ASSOCIATION_OPTIONS.NONE, this.translateService.translate("NO_WORKFLOW_ASSOCIATION")),
71                 new DropdownValue(WORKFLOW_ASSOCIATION_OPTIONS.EXISTING, this.translateService.translate("EXISTING_WORKFLOW_ASSOCIATION"))
72             ];
73         });
74
75         this.currentTab = this.TYPE_INPUT;
76     }
77
78     ngOnInit() {
79
80         this.readonly = this.input.readonly;
81         this.isService = this.input.isService;
82         this.enableWorkflowAssociation = this.input.enableWorkflowAssociation && !this.isService;
83
84         this.inputProperties = _.map(this.input.inputProperties,
85             (input: InputBEModel) => new DropdownValue(input.uniqueId, input.name)
86         );
87
88         this.inputPropertyTypes = {};
89         _.forEach(this.input.inputProperties, (input: InputBEModel) => {
90             this.inputPropertyTypes[input.uniqueId] = input.type;
91         });
92
93         const inputOperation = this.input.operation;
94         this.operation = new OperationModel(inputOperation || {});
95         if (!inputOperation) {
96             this.operation.workflowAssociationType = WORKFLOW_ASSOCIATION_OPTIONS.NONE;
97         }
98
99         if (this.enableWorkflowAssociation) {
100             this.isLoading = true;
101             this.workflowServiceNg2.getWorkflows().subscribe(workflows => {
102                 this.isLoading = false;
103                 this.workflows = _.map(workflows, (workflow: any) => {
104                     return new DropdownValue(workflow.id, workflow.name);
105                 });
106                 this.reconstructOperation();
107             });
108         } else {
109             this.reconstructOperation();
110         }
111
112     }
113
114     reconstructOperation = () => {
115         const inputOperation = this.input.operation;
116         if (inputOperation) {
117             if (!this.enableWorkflowAssociation || !inputOperation.workflowVersionId || this.isService) {
118                 this.inputParameters = this.noAssignInputParameters;
119                 this.outputParameters = this.noAssignOutputParameters;
120                 this.buildParams();
121                 this.updateTable();
122             } else {
123                 this.onSelectWorkflow(inputOperation.workflowVersionId).add(() => {
124                     this.buildParams();
125                     this.updateTable();
126                 });
127             }
128
129             if (inputOperation.uniqueId) {
130                 this.isEditMode = true;
131             }
132         }
133         this.updateTable();
134     }
135
136     buildParams = () => {
137         if (this.input.operation.outputParams) {
138             this.currentTab = this.TYPE_OUTPUT;
139             this.updateTable();
140             _.forEach(
141                 [...this.input.operation.outputParams.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
142                 (output: OperationParameter) => {
143                     this.addParam(output);
144                 }
145             );
146         }
147         this.currentTab = this.TYPE_INPUT;
148         this.updateTable();
149         if (this.input.operation.inputParams) {
150             _.forEach(
151                 [...this.input.operation.inputParams.listToscaDataDefinition].sort((a, b) => a.name.localeCompare(b.name)),
152                 (input: OperationParameter) => {
153                     this.addParam(input);
154                 }
155             );
156         }
157     }
158
159     onSelectWorkflow(selectedVersionId?: string): Subscription {
160
161         this.operation.workflowVersionId = selectedVersionId || null;
162         if (!this.assignInputParameters[this.operation.workflowId]) {
163             this.assignInputParameters[this.operation.workflowId] = {};
164             this.assignOutputParameters[this.operation.workflowId] = {};
165         }
166
167         this.isLoading = true;
168         return this.workflowServiceNg2.getWorkflowVersions(this.operation.workflowId).subscribe((versions: Array<any>) => {
169             this.isLoading = false;
170
171             this.workflowVersions = _.map(
172                 _.filter(
173                     versions, version => version.state === this.workflowServiceNg2.VERSION_STATE_CERTIFIED
174                 ).sort((a, b) => a.name.localeCompare(b.name)),
175                 (version: any) => {
176                     if (!this.assignInputParameters[this.operation.workflowId][version.id] && version.id !== selectedVersionId) {
177                         this.assignInputParameters[this.operation.workflowId][version.id] = _.map(version.inputs, (input: OperationParameter) => {
178                             return new OperationParameter({...input, type: input.type.toLowerCase()});
179                         })
180                         .sort((a, b) => a.name.localeCompare(b.name));
181
182                         this.assignOutputParameters[this.operation.workflowId][version.id] = _.map(version.outputs, (output: OperationParameter) => {
183                             return new OperationParameter({...output, type: output.type.toLowerCase()});
184                         })
185                         .sort((a, b) => a.name.localeCompare(b.name));
186                     }
187                     return new DropdownValue(version.id, `V ${version.name}`);
188                 }
189             );
190
191             if (selectedVersionId) {
192                 this.assignInputParameters[this.operation.workflowId][selectedVersionId] = [];
193                 this.assignOutputParameters[this.operation.workflowId][selectedVersionId] = [];
194             }
195             if (!selectedVersionId && this.workflowVersions.length) {
196                 this.operation.workflowVersionId = _.last(this.workflowVersions).value;
197             }
198
199             this.changeWorkflowVersion();
200         });
201
202     }
203
204     changeWorkflowVersion() {
205         this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
206         this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
207         this.updateTable();
208     }
209
210     toggleAssociateWorkflow() {
211
212         if (!this.isUsingExistingWF()) {
213             this.inputParameters = this.noAssignInputParameters;
214             this.outputParameters = this.noAssignOutputParameters;
215         } else {
216             if (!this.operation.workflowId || !this.operation.workflowVersionId) {
217                 this.inputParameters = [];
218                 this.outputParameters = [];
219             } else {
220                 this.inputParameters = this.assignInputParameters[this.operation.workflowId][this.operation.workflowVersionId];
221                 this.outputParameters = this.assignOutputParameters[this.operation.workflowId][this.operation.workflowVersionId];
222             }
223         }
224
225         this.updateTable();
226
227     }
228
229     tabChanged = (event) => {
230         this.currentTab = event.title;
231         this.updateTable();
232     }
233
234     updateTable() {
235         switch (this.currentTab) {
236             case this.TYPE_INPUT:
237                 this.tableParameters = this.inputParameters;
238                 break;
239             case this.TYPE_OUTPUT:
240                 this.tableParameters = this.outputParameters;
241                 break;
242         }
243     }
244
245     addParam(param?: OperationParameter): void {
246         this.tableParameters.push(new OperationParameter(param));
247     }
248
249     canAdd(): boolean {
250         let valid = true;
251         if (this.currentTab === this.TYPE_INPUT) {
252             _.forEach(this.inputParameters, param => {
253                 if (!param.name || !param.property) {
254                     valid = false;
255                 }
256             });
257         } else {
258             _.forEach(this.outputParameters, param => {
259                 if (!param.name || !param.type) {
260                     valid = false;
261                 }
262             });
263         }
264         return valid;
265     }
266
267     isParamsValid(): boolean {
268         let valid = true;
269         _.forEach(this.inputParameters, param => {
270             if (!param.name || !param.property) {
271                 valid = false;
272             }
273         });
274         _.forEach(this.outputParameters, param => {
275             if (!param.name || !param.type) {
276                 valid = false;
277             }
278         });
279         return valid;
280     }
281
282     onRemoveParam = (param: OperationParameter): void => {
283         let index = _.indexOf(this.tableParameters, param);
284         this.tableParameters.splice(index, 1);
285     }
286
287     createParamLists(): void {
288         this.operation.createInputParamsList(this.inputParameters);
289         this.operation.createOutputParamsList(this.outputParameters);
290     }
291
292     isUsingExistingWF = (): boolean => {
293         return this.operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.EXISTING;
294     }
295
296     shouldCreateWF(): boolean {
297         return this.operation.workflowAssociationType === WORKFLOW_ASSOCIATION_OPTIONS.NEW;
298     }
299
300     checkFormValidForSubmit(): boolean {
301         return this.operation.operationType &&
302             (!this.isUsingExistingWF() || this.operation.workflowVersionId) &&
303             this.isParamsValid();
304     }
305
306 }