changing json handling with function inputs
[ccsdk/cds.git] / cds-ui / designer-client / src / app / modules / feature-modules / packages / designer / functions-attribute / functions-attribute.component.ts
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     init() {
121         this.selectedTemplates = new Map(this.finalTemplates);
122     }
123
124     toNodeProcess(nodeTemplate, functionName) {
125         console.log(nodeTemplate);
126         this.currentFuncion['instance-name'] = functionName;
127         // tslint:disable-next-line: no-string-literal
128         this.currentFuncion['type'] = nodeTemplate['type'];
129         if (nodeTemplate.interfaces && Object.keys(nodeTemplate.interfaces).length > 0) {
130             const nodeName = Object.keys(nodeTemplate.interfaces)[0];
131             // console.log(Object.keys(nodeTemplate.interfaces));
132             // tslint:disable-next-line: no-string-literal
133             const inputs = nodeTemplate.interfaces[nodeName]['operations']['process']['inputs'];
134             // tslint:disable-next-line: no-string-literal
135             const outputs = nodeTemplate.interfaces[nodeName]['operations']['process']['outputs'];
136
137             // console.log(inputs);
138
139             if (inputs) {
140                 for (const [key, value] of Object.entries(inputs)) {
141                     console.log(key + ' - ' + value);
142                    /* if (typeof value === 'object' || this.isValidJson(value)) {
143                         this.currentFuncion.inputs[key] = JSON.stringify(value);
144                     } else {*/
145                     this.currentFuncion.inputs[key] = value;
146                    // }
147                 }
148             }
149             if (outputs) {
150                 for (const [key, value] of Object.entries(outputs)) {
151                     console.log(key + '-' + value);
152                     this.currentFuncion.outputs[key] = value;
153                 }
154             }
155         }
156     }
157
158     isValidJson(val) {
159         console.log(val);
160         try {
161             JSON.parse(val + '');
162             return true;
163         } catch (e) {
164             console.log(e);
165         }
166         return false;
167     }
168
169     jsonToStr(json) {
170         return JSON.stringify(json);
171     }
172
173     bind(key, e) {
174         const val = JSON.parse(e.target.value);
175         this.currentFuncion.inputs[key] = {
176             ...val
177         };
178     }
179     ngOnDestroy() {
180         this.ngUnsubscribe.next();
181         this.ngUnsubscribe.complete();
182     }
183
184     addTemplates() {
185         this.finalTemplates = new Map(this.selectedTemplates);
186     }
187     cancel() {
188         this.selectedTemplates = new Map<string, TemplateAndMapping>();
189     }
190
191     saveFunctionData() {
192         this.nodeTemplates = new NodeTemplate('');
193         // tslint:disable-next-line: variable-name
194         const node_templates = {};
195         const finalFunctionData = this.currentFuncion;
196         // tslint:disable-next-line: no-string-literal
197         const type = finalFunctionData['type'];
198         const instanceName = finalFunctionData['instance-name'];
199         // insert selected templates in nodeTemplates.artifacts
200         this.selectedTemplates.forEach((value, key) => {
201             console.log(key);
202             console.log(value);
203             console.log(finalFunctionData.inputs['artifact-prefix-names']);
204
205             if (finalFunctionData.inputs['artifact-prefix-names'] === undefined) {
206                 finalFunctionData.inputs['artifact-prefix-names'] = [key];
207             } else if (
208                 Array.isArray(finalFunctionData.inputs['artifact-prefix-names']) &&
209                 !finalFunctionData.inputs['artifact-prefix-names'].includes(key)
210             ) {
211                 finalFunctionData.inputs['artifact-prefix-names'].push(key);
212             }
213
214             if (value.isMapping) {
215                 this.nodeTemplates.artifacts[key + '-mapping'] = {
216                     type: 'artifact-mapping-resource',
217                     file: 'Templates/' + key + '-mapping.json'
218                 };
219             }
220
221             if (value.isTemplate) {
222                 this.nodeTemplates.artifacts[key + '-template'] = {
223                     type: 'artifact-template-velocity',
224                     file: 'Templates/' + key + '-template.vtl'
225                 };
226             }
227         });
228         // instantiate the final node_template object to save
229
230         this.nodeTemplates.type = type;
231         delete this.nodeTemplates.properties;
232         node_templates[finalFunctionData['instance-name']] = this.nodeTemplates;
233
234         delete finalFunctionData['instance-name'];
235         // tslint:disable-next-line: no-string-literal
236         delete finalFunctionData['type'];
237
238         if (finalFunctionData.outputs === {} || Object.keys(finalFunctionData.outputs).length <= 0) {
239             delete finalFunctionData.outputs;
240         }
241
242         this.nodeTemplates.interfaces = {
243             [this.interfaceChildName]: {
244                 operations: {
245                     process: {
246                         ...finalFunctionData,
247                     }
248                 }
249             }
250         };
251         console.log(finalFunctionData);
252         console.log(node_templates);
253         // save function to store
254         // tslint:disable-next-line: no-unused-expression
255         this.designerStore.addNodeTemplate(instanceName, type, node_templates[instanceName]);
256         // create a new package
257         this.saveEvent.emit('save');
258     }
259     // Template logic
260     private setIsMappingOrTemplate(key: string, templateAndMapping: TemplateAndMapping, isFromTemplate: boolean) {
261         const nameOfFile = isFromTemplate ?
262             key.split('/')[1].split('.')[0].split('-template')[0]
263             : key.split('/')[1].split('.')[0].split('-mapping')[0];
264         // const fullName = nameOfFile + ',' + key.split('.');
265         if (this.templateAndMappingMap.has(nameOfFile)) {
266             const templateAndMappingExisted = this.templateAndMappingMap.get(nameOfFile);
267             !isFromTemplate ? templateAndMappingExisted.isMapping = true : templateAndMappingExisted.isTemplate = true;
268             this.templateAndMappingMap.set(nameOfFile, templateAndMappingExisted);
269         } else {
270             this.templateAndMappingMap.set(nameOfFile, templateAndMapping);
271         }
272
273     }
274
275     setArtifact(predefined: boolean) {
276         if (predefined) {
277             this.currentFuncion.inputs['artifact-prefix-names'] = [];
278         } else {
279             this.currentFuncion.inputs['artifact-prefix-names'] = { get_input: 'template-prefix' };
280         }
281     }
282     addToInputs(optionalInput) {
283         this.requiredInputs.set(optionalInput, this.OptionalInputs.get(optionalInput));
284         this.OptionalInputs.delete(optionalInput);
285     }
286
287     setTemplate(file: string) {
288         if (this.selectedTemplates.has(file)) {
289             this.selectedTemplates.delete(file);
290         } else {
291             this.selectedTemplates.set(file, this.templateAndMappingMap.get(file));
292         }
293         console.log(this.selectedTemplates);
294     }
295
296     getKeys(map: Map<string, any>) {
297         return Array.from(map.keys());
298     }
299     getValue(file: string, map: Map<string, any>) {
300         return map.get(file);
301     }
302
303     getObjectKey(object) {
304         // console.log(object);
305         return Object.keys(object);
306     }
307     getObjectValue(object) {
308         return Object.values(object);
309     }
310
311     getNodeType(nodeName: string) {
312         this.functionStore.state$
313             .subscribe(state => {
314                 console.log(state);
315                 console.log(nodeName);
316                 const functions = state.serverFunctions;
317                 // tslint:disable-next-line: prefer-for-of
318                 for (let i = 0; i < functions.length; i++) {
319                     if (functions[i].modelName === nodeName) {
320                         // tslint:disable: no-string-literal
321                         console.log(functions[i].definition['interfaces']);
322                         this.getInputFields(functions[i].definition['interfaces'], 'outputs');
323                         this.getInputFields(functions[i].definition['interfaces'], 'inputs');
324                         break;
325                     }
326                 }
327             });
328     }
329
330     getInputFields(interfaces, type) {
331
332         if (type === 'inputs') {
333             this.requiredInputs = new Map<string, {}>();
334             this.OptionalInputs = new Map<string, {}>();
335         } else {
336             this.requiredOutputs = new Map<string, {}>();
337             this.optionalOutputs = new Map<string, {}>();
338
339         }
340         const nodeName = Object.keys(interfaces)[0];
341         this.interfaceChildName = nodeName;
342         console.log(nodeName + ' ------ ' + type);
343         console.log(interfaces[nodeName]['operations']['process'][type]);
344         const fields = interfaces[nodeName]['operations']['process'][type];
345         this.artifactPrefix = false;
346         for (const [key, value] of Object.entries(fields)) {
347             if (key === 'artifact-prefix-names') {
348                 this.artifactPrefix = true;
349                 // in edit&view mode need to check first if this input||output already exists
350             } else if (key in this.currentFuncion.inputs) {
351                 this.requiredInputs.set(key, Object.assign({}, value));
352             } else if (key in this.currentFuncion.outputs) {
353                 this.requiredOutputs.set(key, Object.assign({}, value));
354             } else if (value['required']) {
355                 console.log('This field is required = ' + key);
356                 if (type === 'inputs') {
357                     this.requiredInputs.set(key, Object.assign({}, value));
358                 } else {
359                     this.requiredOutputs.set(key, Object.assign({}, value));
360                 }
361             } else {
362                 console.log('This field is Optional ' + key);
363                 if (type === 'inputs') {
364                     this.OptionalInputs.set(key, Object.assign({}, value));
365                 } else {
366                     this.optionalOutputs.set(key, Object.assign({}, value));
367                 }
368             }
369         }
370
371         // console.log(this.requiredOutputs);
372     }
373
374
375 }