d36b16f1623c926abae834911b96bed72c0e41e6
[ccsdk/cds.git] /
1 import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
2 import { DesignerStore } from '../designer.store';
3 import { PackageCreationStore } from '../../package-creation/package-creation.store';
4 import { Subject } from 'rxjs';
5 import { distinctUntilChanged, takeUntil } from 'rxjs/operators';
6 import { CBAPackage } from '../../package-creation/mapping-models/CBAPacakge.model';
7 import { TemplateAndMapping } from '../../package-creation/template-mapping/TemplateAndMapping';
8 import { FunctionsStore } from '../functions.store';
9 import { NodeProcess, NodeTemplate } from '../model/desinger.nodeTemplate.model';
10 import { DesignerDashboardState } from '../model/designer.dashboard.state';
11 import { Action } from '../action-attributes/models/Action';
12
13 @Component({
14     selector: 'app-functions-attribute',
15     templateUrl: './functions-attribute.component.html',
16     styleUrls: ['./functions-attribute.component.css']
17 })
18 export class FunctionsAttributeComponent implements OnInit, OnDestroy {
19
20     ngUnsubscribe = new Subject();
21     designerDashboardState: DecodeSuccessCallback;
22     cbaPackage: CBAPackage;
23     templateAndMappingMap = new Map<string, TemplateAndMapping>();
24     selectedTemplates = new Map<string, TemplateAndMapping>();
25     finalTemplates = new Map<string, TemplateAndMapping>();
26     fileToDelete: string;
27     requiredInputs = new Map<string, {}>();
28     requiredOutputs = new Map<string, {}>();
29     OptionalInputs = new Map<string, {}>();
30     optionalOutputs = new Map<string, {}>();
31     artifactPrefix = false;
32     currentFuncion = new NodeProcess();
33     nodeTemplates = new NodeTemplate('');
34     designerState: DesignerDashboardState;
35     actionName = '';
36     functionName = '';
37     interfaceChildName = '';
38     @Output() saveEvent = new EventEmitter<string>();
39
40
41     constructor(
42         private designerStore: DesignerStore,
43         private packageCreationStore: PackageCreationStore,
44         private functionStore: FunctionsStore
45     ) {
46     }
47
48     ngOnInit() {
49         this.designerStore.state$.subscribe(designerDashboardState => {
50             this.designerState = designerDashboardState;
51             this.actionName = this.designerState.actionName;
52             const action = this.designerState.template.workflows[this.actionName] as Action;
53             this.currentFuncion = new NodeProcess();
54             try {
55                 console.log(action);
56                 if (action) {
57                     // this.designerState.functionName
58                     const child = Object.keys(action.steps)[0];
59                     this.functionName = this.designerState.functionName;
60                     console.log(this.designerState.template.node_templates);
61                     console.log(this.designerState);
62                     console.log(this.designerState.template.node_templates[this.functionName]);
63                     //  this.currentFuncion = this.designerState.template.node_templates[this.functionName];
64                     // reset inouts&outputs
65                     this.requiredInputs = new Map<string, {}>();
66                     this.requiredOutputs = new Map<string, {}>();
67                     this.OptionalInputs = new Map<string, {}>();
68                     this.optionalOutputs = new Map<string, {}>();
69                     this.toNodeProcess(this.designerState.template.node_templates[this.functionName], this.functionName);
70                     const type = this.designerState.template.node_templates[this.functionName].type;
71                     this.getNodeType(type);
72                     this.onInitMapping();
73                 }
74             } catch (e) { }
75         });
76
77         this.packageCreationStore.state$
78             .subscribe(cbaPackage => {
79                 this.cbaPackage = cbaPackage;
80                 console.log('File name =>================== ');
81                 console.log(this.cbaPackage.templates.files);
82                 this.cbaPackage.templates.files.forEach((value, key) => {
83                     console.log('File name => ' + key);
84                     const templateAndMapping = new TemplateAndMapping();
85                     templateAndMapping.isTemplate = true;
86                     const isFromTemplate = true;
87                     this.setIsMappingOrTemplate(key, templateAndMapping, isFromTemplate);
88                 });
89
90                 this.cbaPackage.mapping.files.forEach((value, key) => {
91                     const templateAndMapping = new TemplateAndMapping();
92                     templateAndMapping.isMapping = true;
93                     const isFromTemplate = false;
94                     this.setIsMappingOrTemplate(key, templateAndMapping, isFromTemplate);
95                 });
96             });
97
98     }
99
100     onInitMapping() {
101         // selectedTemplates , templateAndMappingMap
102         this.selectedTemplates = new Map<string, TemplateAndMapping>();
103         try {
104             const functionMap = this.designerState.template.node_templates[this.functionName].artifacts;
105             console.log(this.templateAndMappingMap);
106
107             Object.keys(functionMap).forEach((file) => {
108                 const filename = file.substring(0, file.lastIndexOf('-'));
109                 console.log(filename);
110                 if (this.templateAndMappingMap.has(filename)) {
111                     this.selectedTemplates.set(filename, this.templateAndMappingMap.get(filename));
112                     this.finalTemplates.set(filename, this.templateAndMappingMap.get(filename));
113                 }
114             });
115
116
117         } catch (e) { }
118     }
119
120     toNodeProcess(nodeTemplate, functionName) {
121         console.log(nodeTemplate);
122         this.currentFuncion['instance-name'] = functionName;
123         // tslint:disable-next-line: no-string-literal
124         this.currentFuncion['type'] = nodeTemplate['type'];
125         if (nodeTemplate.interfaces && Object.keys(nodeTemplate.interfaces).length > 0) {
126             const nodeName = Object.keys(nodeTemplate.interfaces)[0];
127             // console.log(Object.keys(nodeTemplate.interfaces));
128             // tslint:disable-next-line: no-string-literal
129             const inputs = nodeTemplate.interfaces[nodeName]['operations']['process']['inputs'];
130             // tslint:disable-next-line: no-string-literal
131             const outputs = nodeTemplate.interfaces[nodeName]['operations']['process']['outputs'];
132
133             // console.log(inputs);
134
135             if (inputs) {
136                 for (const [key, value] of Object.entries(inputs)) {
137                     console.log(key + ' - ' + value);
138                     if (typeof value === 'object') {
139                         this.currentFuncion.inputs[key] = JSON.stringify(value);
140                     } else {
141                         this.currentFuncion.inputs[key] = value;
142                     }
143                 }
144             }
145             if (outputs) {
146                 for (const [key, value] of Object.entries(outputs)) {
147                     console.log(key + '-' + value);
148                     this.currentFuncion.outputs[key] = value;
149                 }
150             }
151         }
152     }
153     ngOnDestroy() {
154         this.ngUnsubscribe.next();
155         this.ngUnsubscribe.complete();
156     }
157
158     addTemplates() {
159         this.finalTemplates = this.selectedTemplates;
160     }
161     cancel() {
162         this.selectedTemplates = new Map<string, TemplateAndMapping>();
163     }
164
165     saveFunctionData() {
166         this.nodeTemplates = new NodeTemplate('');
167         // tslint:disable-next-line: variable-name
168         const node_templates = {};
169         const finalFunctionData = this.currentFuncion;
170         // tslint:disable-next-line: no-string-literal
171         const type = finalFunctionData['type'];
172         const instanceName = finalFunctionData['instance-name'];
173         // insert selected templates in nodeTemplates.artifacts
174         this.selectedTemplates.forEach((value, key) => {
175             console.log(key);
176             console.log(value);
177             console.log(finalFunctionData.inputs['artifact-prefix-names']);
178
179             if (finalFunctionData.inputs['artifact-prefix-names'] === undefined) {
180                 finalFunctionData.inputs['artifact-prefix-names'] = [key];
181             } else if (
182                 Array.isArray(finalFunctionData.inputs['artifact-prefix-names']) &&
183                 !finalFunctionData.inputs['artifact-prefix-names'].includes(key)
184             ) {
185                 finalFunctionData.inputs['artifact-prefix-names'].push(key);
186             }
187
188             if (value.isMapping) {
189                 this.nodeTemplates.artifacts[key + '-mapping'] = {
190                     type: 'artifact-mapping-resource',
191                     file: 'Templates/' + key + '-mapping.json'
192                 };
193             }
194
195             if (value.isTemplate) {
196                 this.nodeTemplates.artifacts[key + '-template'] = {
197                     type: 'artifact-template-velocity',
198                     file: 'Templates/' + key + '-template.vtl'
199                 };
200             }
201         });
202         // instantiate the final node_template object to save
203
204         this.nodeTemplates.type = type;
205         delete this.nodeTemplates.properties;
206         node_templates[finalFunctionData['instance-name']] = this.nodeTemplates;
207
208         delete finalFunctionData['instance-name'];
209         // tslint:disable-next-line: no-string-literal
210         delete finalFunctionData['type'];
211
212         if (finalFunctionData.outputs === {} || Object.keys(finalFunctionData.outputs).length <= 0) {
213             delete finalFunctionData.outputs;
214         }
215
216         this.nodeTemplates.interfaces = {
217             [this.interfaceChildName]: {
218                 operations: {
219                     process: {
220                         ...finalFunctionData,
221                     }
222                 }
223             }
224         };
225         console.log(finalFunctionData);
226         console.log(node_templates);
227         // save function to store
228         // tslint:disable-next-line: no-unused-expression
229         this.designerStore.addNodeTemplate(instanceName, type, node_templates[instanceName]);
230         // create a new package
231         this.saveEvent.emit('save');
232     }
233     // Template logic
234     private setIsMappingOrTemplate(key: string, templateAndMapping: TemplateAndMapping, isFromTemplate: boolean) {
235         const nameOfFile = isFromTemplate ?
236             key.split('/')[1].split('.')[0].split('-template')[0]
237             : key.split('/')[1].split('.')[0].split('-mapping')[0];
238         // const fullName = nameOfFile + ',' + key.split('.');
239         if (this.templateAndMappingMap.has(nameOfFile)) {
240             const templateAndMappingExisted = this.templateAndMappingMap.get(nameOfFile);
241             !isFromTemplate ? templateAndMappingExisted.isMapping = true : templateAndMappingExisted.isTemplate = true;
242             this.templateAndMappingMap.set(nameOfFile, templateAndMappingExisted);
243         } else {
244             this.templateAndMappingMap.set(nameOfFile, templateAndMapping);
245         }
246
247     }
248
249     setArtifact(predefined: boolean) {
250         if (predefined) {
251             this.currentFuncion.inputs['artifact-prefix-names'] = [];
252         } else {
253             this.currentFuncion.inputs['artifact-prefix-names'] = { get_input: 'template-prefix' };
254         }
255     }
256     addToInputs(optionalInput) {
257         this.requiredInputs.set(optionalInput, this.OptionalInputs.get(optionalInput));
258         this.OptionalInputs.delete(optionalInput);
259     }
260
261     setTemplate(file: string) {
262         if (this.selectedTemplates.has(file)) {
263             this.selectedTemplates.delete(file);
264         } else {
265             this.selectedTemplates.set(file, this.templateAndMappingMap.get(file));
266         }
267         console.log(this.selectedTemplates);
268     }
269
270     getKeys(map: Map<string, any>) {
271         return Array.from(map.keys());
272     }
273     getValue(file: string, map: Map<string, any>) {
274         return map.get(file);
275     }
276
277     getObjectKey(object) {
278         // console.log(object);
279         return Object.keys(object);
280     }
281     getObjectValue(object) {
282         return Object.values(object);
283     }
284
285     getNodeType(nodeName: string) {
286         this.functionStore.state$
287             .subscribe(state => {
288                 console.log(state);
289                 console.log(nodeName);
290                 const functions = state.serverFunctions;
291                 // tslint:disable-next-line: prefer-for-of
292                 for (let i = 0; i < functions.length; i++) {
293                     if (functions[i].modelName === nodeName) {
294                         // tslint:disable: no-string-literal
295                         console.log(functions[i].definition['interfaces']);
296                         this.getInputFields(functions[i].definition['interfaces'], 'outputs');
297                         this.getInputFields(functions[i].definition['interfaces'], 'inputs');
298                         break;
299                     }
300                 }
301             });
302     }
303
304     getInputFields(interfaces, type) {
305
306         if (type === 'inputs') {
307             this.requiredInputs = new Map<string, {}>();
308             this.OptionalInputs = new Map<string, {}>();
309         } else {
310             this.requiredOutputs = new Map<string, {}>();
311             this.optionalOutputs = new Map<string, {}>();
312
313         }
314         const nodeName = Object.keys(interfaces)[0];
315         this.interfaceChildName = nodeName;
316         console.log(nodeName + ' ------ ' + type);
317         console.log(interfaces[nodeName]['operations']['process'][type]);
318         const fields = interfaces[nodeName]['operations']['process'][type];
319         this.artifactPrefix = false;
320         for (const [key, value] of Object.entries(fields)) {
321             if (key === 'artifact-prefix-names') {
322                 this.artifactPrefix = true;
323                 // in edit&view mode need to check first if this input||output already exists
324             } else if (key in this.currentFuncion.inputs) {
325                 this.requiredInputs.set(key, Object.assign({}, value));
326             } else if (key in this.currentFuncion.outputs) {
327                 this.requiredOutputs.set(key, Object.assign({}, value));
328             } else if (value['required']) {
329                 console.log('This field is required = ' + key);
330                 if (type === 'inputs') {
331                     this.requiredInputs.set(key, Object.assign({}, value));
332                 } else {
333                     this.requiredOutputs.set(key, Object.assign({}, value));
334                 }
335             } else {
336                 console.log('This field is Optional ' + key);
337                 if (type === 'inputs') {
338                     this.OptionalInputs.set(key, Object.assign({}, value));
339                 } else {
340                     this.optionalOutputs.set(key, Object.assign({}, value));
341                 }
342             }
343         }
344
345         // console.log(this.requiredOutputs);
346     }
347
348
349 }