2971ecad9d837a60f7e31bc67758bb6edef3c9d5
[ccsdk/cds.git] /
1 import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core';
2 import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop';
3 import { PackageCreationStore } from '../../package-creation.store';
4 import { TemplateInfo, TemplateStore } from '../../template.store';
5 import { Subject } from 'rxjs';
6 import { ResourceDictionary } from '../../mapping-models/ResourceDictionary.model';
7 import { DataTableDirective } from 'angular-datatables';
8 import { Mapping, MappingAdapter } from '../../mapping-models/mappingAdapter.model';
9 import { PackageCreationUtils } from '../../package-creation.utils';
10 import { JsonConvert, Any } from 'json2typescript';
11 import { ToastrService } from 'ngx-toastr';
12 import { SharedService } from '../shared-service';
13 import { XmlParser } from '../utils/ParserFactory/XmlParser';
14 import { TourService } from 'ngx-tour-md-menu';
15 import { PackageCreationService } from '../../package-creation.service';
16 import { ParserFactory } from '../utils/ParserFactory/ParserFactory';
17 import { TemplateType, FileExtension } from '../utils/TemplateType';
18 declare var $: any;
19
20 @Component({
21     selector: 'app-templ-mapp-creation',
22     templateUrl: './templ-mapp-creation.component.html',
23     styleUrls: ['./templ-mapp-creation.component.css']
24 })
25 export class TemplMappCreationComponent implements OnInit, OnDestroy {
26     @Output() showListView = new EventEmitter<any>();
27     @Output() showCreationView = new EventEmitter<any>();
28     public uploadedFiles: FileSystemFileEntry[] = [];
29     fileNames: Set<string> = new Set();
30     jsonConvert = new JsonConvert();
31     public files: NgxFileDropEntry[] = [];
32     fileName: any;
33     templateInfo = new TemplateInfo();
34     variables: string[] = [];
35     dtOptions: DataTables.Settings = {};
36     initDtOptions: DataTables.Settings = {};
37     // We use this trigger because fetching the list of persons can be quite long,
38     // thus we ensure the data is fetched before rendering
39     dtTrigger = new Subject();
40     resTableDtTrigger = new Subject();
41     resourceDictionaryRes: ResourceDictionary[] = [];
42     allowedExt = ['.vtl'];
43     @ViewChild(DataTableDirective, { static: false })
44     dtElement: DataTableDirective;
45     MappingAdapter: MappingAdapter;
46     mapping = new Map();
47     templateFileContent: string;
48     templateExt = 'vtl';
49     dependancies = new Map<string, Array<string>>();
50     dependanciesSource = new Map<string, string>();
51     mappingRes = [];
52     currentTemplate: any;
53     currentMapping: any;
54     edit = false;
55     fileToDelete: any = {};
56     parserFactory: ParserFactory;
57     selectedProps: Set<string>;
58
59     constructor(
60         private packageCreationStore: PackageCreationStore,
61         private templateStore: TemplateStore,
62         private packageCreationUtils: PackageCreationUtils,
63         private toastr: ToastrService,
64         private sharedService: SharedService,
65         private packageCreationService: PackageCreationService,
66         private tourService: TourService,
67     ) {
68     }
69
70     ngOnInit() {
71         this.selectedProps = new Set<string>();
72         this.parserFactory = new ParserFactory();
73         this.templateStore.state$.subscribe(templateInfo => {
74             // init Template&mapping vars
75             console.log('Oninit');
76             console.log(templateInfo);
77             this.templateInfo = templateInfo;
78             this.fileToDelete = templateInfo.fileName;
79             this.fileName = templateInfo.fileName.split('/')[1];
80             if (this.fileName) {
81                 this.fileName = this.fileName.split('-')[0];
82             }
83             if (templateInfo.type === 'mapping' || templateInfo.type.includes('mapping')) {
84                 this.mappingRes = templateInfo.mapping;
85                 this.currentMapping = Object.assign({}, templateInfo);
86                 this.resourceDictionaryRes = [];
87                 this.resTableDtTrigger.next();
88             } else {
89                 this.mappingRes = [];
90                 this.currentMapping = Any;
91                 this.resourceDictionaryRes = [];
92             }
93             this.templateFileContent = templateInfo.fileContent;
94             this.templateExt = this.templateInfo.ext || this.templateExt;
95             this.currentTemplate = Object.assign({}, templateInfo);
96
97             if (templateInfo.type === 'template' || templateInfo.type.includes('template')) {
98                 console.log('template extension ' + this.templateExt);
99                 this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.' + this.templateExt;
100                 console.log(this.currentTemplate.fileName);
101             } else {
102                 this.currentTemplate = Any;
103             }
104
105         });
106
107
108         this.sharedService.isEdit().subscribe(res => {
109             console.log('------------------------....');
110             console.log(res);
111             this.edit = res;
112
113             if (!this.edit) {
114                 console.log('remove ----');
115                 this.currentMapping = {};
116                 this.currentTemplate = {};
117                 this.fileName = '';
118                 this.templateFileContent = '';
119                 this.resourceDictionaryRes = [];
120                 this.mappingRes = [];
121             }
122         });
123
124         this.initDtOptions = {
125             pagingType: 'full_numbers',
126             pageLength: 25,
127             destroy: true,
128             retrieve: true,
129             columnDefs: [
130                 {
131                     targets: [0, 1, 2], // column or columns numbers
132                     orderable: false, // set orderable for selected columns
133                     searchable: false,
134                 },
135
136             ],
137         };
138         this.dtOptions = {
139             pagingType: 'full_numbers',
140             pageLength: 25,
141             destroy: true,
142             retrieve: true,
143         };
144     }
145
146     setProp(e, propName, index) {
147         this.resourceDictionaryRes[index][propName] = e.checked;
148         console.log(this.resourceDictionaryRes[index]);
149     }
150     selectProp(value) {
151         console.log(value);
152         if (this.selectedProps.has(value)) {
153             this.selectedProps.delete(value);
154         } else {
155             this.selectedProps.add(value);
156         }
157     }
158
159     removeProps() {
160         console.log(this.selectedProps);
161         this.selectedProps.forEach(prop => {
162             this.resourceDictionaryRes.forEach((res, index) => {
163                 if (res.name === prop) {
164                     console.log('delete...');
165                     this.resourceDictionaryRes.splice(index, 1);
166                     this.selectedProps.delete(prop);
167                 }
168             });
169         });
170     }
171     selectAllProps() {
172         if (this.resourceDictionaryRes.length === this.selectedProps.size) {
173             this.selectedProps = new Set<string>();
174         } else {
175             this.resourceDictionaryRes.forEach(prop => {
176                 console.log(prop);
177                 this.selectedProps.add(prop.name);
178             });
179         }
180
181     }
182     reMap() {
183         let currentResDictionary = [];
184         if (this.selectedProps && this.selectedProps.size > 0) {
185             console.log('base');
186             this.packageCreationService.getTemplateAndMapping([...this.selectedProps]).subscribe(res => {
187                 let message = 'Re-Auto mapping';
188                 this.mappingRes = [];
189                 currentResDictionary = res;
190                 console.log(currentResDictionary);
191                 if (currentResDictionary && currentResDictionary.length <= 0) {
192                     message = 'No values for those attributes';
193                 }
194
195                 // Replcae new values with the old ones
196                 currentResDictionary.forEach(curr => {
197                     for (let i = 0; i < this.resourceDictionaryRes.length; i++) {
198                         if (this.resourceDictionaryRes[i].name === curr.name) {
199                             this.resourceDictionaryRes[i] = curr;
200                         }
201                     }
202                 });
203                 this.rerender();
204                 this.toastr.success(message, 'Success');
205             }, err => {
206                 this.toastr.error('Error');
207             });
208         }
209
210     }
211
212     getFileExtension() {
213         switch (this.templateExt) {
214             case 'vtl':
215                 return '.vtl';
216             case 'kt':
217                 return '.ktl';
218             case 'j2':
219                 return '.j2';
220             default:
221                 return '.vtl';
222         }
223     }
224
225     fileExtensionFromString(filename: string): string {
226         const fileExtension = filename.substring(filename.lastIndexOf('.') + 1);
227         return fileExtension;
228     }
229
230     public getTemplateVariable(fileContent: string) {
231         // TODO: implement factory Pattern for parser
232         console.log('start parsing........ ' + this.templateExt);
233         const parser = this.parserFactory.getParser(fileContent, this.templateExt);
234         return parser.getVariables(fileContent);
235     }
236
237     public dropped(files: NgxFileDropEntry[]) {
238         this.files = files;
239         for (const droppedFile of files) {
240             // Is it a file? & Not added before
241             if (droppedFile.fileEntry.isFile) {
242                 const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
243                 this.uploadedFiles.push(fileEntry);
244                 this.fileNames.add(fileEntry.name);
245
246             }
247         }
248     }
249     removeFile(index) {
250         this.uploadedFiles.splice(index, 1);
251     }
252
253     confirmDelete() {
254         // Delete from templates
255         this.sharedService.deleteFromList(this.fileName);
256         this.packageCreationStore.state.templates.files.delete(this.fileToDelete);
257         // Delete from Mapping
258         this.packageCreationStore.state.mapping.files.delete(this.fileToDelete);
259         if (
260             this.packageCreationStore.state.templates.files.size > 0 ||
261             this.packageCreationStore.state.mapping.files.size > 0
262         ) {
263             this.openListView();
264         }
265
266     }
267     uploadFile() {
268         this.dependancies.clear();
269         this.dependanciesSource.clear();
270         if (this.allowedExt.includes('.csv') || this.allowedExt.includes('.xml')) {
271             this.fetchkeysfromfile();
272         } else {
273             this.setTemplateFilesToStore();
274         }
275         $('.btn-cancel').click();
276     }
277
278     fetchkeysfromfile() {
279         for (const droppedFile of this.uploadedFiles) {
280             droppedFile.file((file: File) => {
281                 const fileReader = new FileReader();
282                 fileReader.onload = (e) => {
283                     const fileExt = this.fileExtensionFromString(droppedFile.name);
284                     if (fileExt === 'csv') {
285                         this.variables = fileReader.result.toString().split(',');
286                     } else {
287                         const parser = new XmlParser();
288                         this.variables = parser.getVariables(fileReader.result.toString());
289                     }
290                     console.log(this.variables);
291                     this.getMappingTableFromTemplate(null);
292
293                 };
294                 fileReader.readAsText(file);
295             });
296         }
297         this.uploadedFiles = [];
298     }
299
300     private convertDictionaryToMap(resourceDictionaries: ResourceDictionary[]): Mapping[] {
301         const mapArray: Mapping[] = [];
302         for (const resourceDictionary of resourceDictionaries) {
303             this.MappingAdapter = new MappingAdapter(resourceDictionary, this.dependancies, this.dependanciesSource);
304             mapArray.push(this.MappingAdapter.ToMapping());
305         }
306         console.log(mapArray);
307         return mapArray;
308     }
309
310     setTemplateFilesToStore() {
311         for (const droppedFile of this.uploadedFiles) {
312             droppedFile.file((file: File) => {
313                 const fileReader = new FileReader();
314                 fileReader.onload = (e) => {
315                     this.templateFileContent = fileReader.result.toString();
316                     // this.variables = this.getTemplateVariable(this.templateFileContent);
317                     // console.log(this.variables);
318
319                 };
320                 fileReader.readAsText(file);
321             });
322         }
323         this.uploadedFiles = [];
324     }
325
326     textChanges(code: any, fileName: string) {
327         //  this.packageCreationStore.addTemplate(fileName, code);
328         this.templateFileContent = code;
329     }
330
331     public fileOver(event) {
332         console.log(event);
333     }
334
335     public fileLeave(event) {
336         console.log(event);
337     }
338     //
339     resetTheUploadedFiles() {
340         this.uploadedFiles = [];
341     }
342
343     openListView() {
344         console.log('open List view');
345         this.showListView.emit('tell parent to open create views');
346     }
347
348     openCreationView() {
349         console.log('close creation view');
350         this.showCreationView.emit('close create form and open list');
351     }
352
353     identify(index, item) {
354         return item.name;
355     }
356     setVelocity(index, value) {
357         // console.log('velocity value = ' + value);
358         // console.log(this.resourceDictionaryRes[index]);
359         // tslint:disable-next-line: no-string-literal
360         this.resourceDictionaryRes[index].definition.property['metadata'] = {
361             'transform-template': value
362         };
363         console.log(this.resourceDictionaryRes[index]);
364     }
365
366     getMappingTableFromTemplate(e) {
367         console.log('-' + this.templateFileContent + '-');
368         this.resourceDictionaryRes = [];
369         if (e) {
370             e.preventDefault();
371         }
372         this.variables = this.getTemplateVariable(this.templateFileContent);
373         console.log(this.variables);
374         if (this.variables && this.variables.length > 0) {
375             console.log('base');
376             this.packageCreationService.getTemplateAndMapping(this.variables).subscribe(res => {
377                 let message = 'Attributes are Fetched';
378                 this.mappingRes = [];
379                 this.resourceDictionaryRes = res;
380                 console.log(this.resourceDictionaryRes);
381                 this.rerender();
382                 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length <= 0) {
383                     message = 'No values for those attributes';
384                 }
385                 this.toastr.success(message, 'Success');
386             }, err => {
387                 this.toastr.error('Error');
388             });
389         } else {
390             this.toastr.error('Empty or Invalid file format. Validate your file first');
391         }
392     }
393
394     initMap(key, map) {
395         if (!this.dependanciesSource.has(key)) {
396             this.dependanciesSource.set(key, map.key);
397         }
398         return map.key;
399     }
400     cancel() {
401         this.fileName = '';
402         this.templateFileContent = '';
403         this.resourceDictionaryRes = [];
404         this.mappingRes = [];
405         this.currentMapping = {};
406         this.currentTemplate = {};
407         //   this.closeCreationForm();
408     }
409     saveToStore() {
410         if (this.fileName) {
411             // check file duplication
412             console.log('----------- mode ' + this.edit);
413             if (
414                 (!(this.packageCreationStore.fileExist('Templates/' + this.fileName + '-mapping.json')
415                     || this.packageCreationStore.fileExist('Templates/' + this.fileName + '-template' + this.getFileExtension())))
416                 || this.edit
417             ) {
418                 // Save Mapping to Store
419                 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length > 0) {
420                     const mapArray = this.convertDictionaryToMap(this.resourceDictionaryRes);
421                     this.packageCreationStore.addMapping('Templates/' + this.fileName + '-mapping.json',
422                         this.packageCreationUtils.transformToJson(this.jsonConvert.serialize(mapArray)));
423                     this.resourceDictionaryRes = [];
424                 }
425                 // Save Template to store
426                 // if (this.templateFileContent) {
427                 this.packageCreationStore.addTemplate('Templates/' + this.fileName + '-template' + this.getFileExtension(),
428                     this.templateFileContent);
429                 this.templateFileContent = '';
430                 //  }
431                 this.fileName = '';
432                 this.toastr.success('File is created', 'success');
433                 this.openListView();
434                 if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') {
435                     this.tourService.goto('tm-templateEdit');
436                 }
437             } else {
438                 console.log('this file already exist');
439                 this.toastr.error('File name already exist', 'Error');
440             }
441         } else {
442             this.toastr.error('Add the file name', 'Error');
443         }
444     }
445
446
447     selectSource(dict, e) {
448         const source = e.target.value;
449         let keyDepend = null;
450         this.dependancies.set(dict.name, null);
451         try {
452             keyDepend = dict.definition.sources[source].properties['key-dependencies'] || null;
453         } catch (e) { }
454         console.log(dict);
455         console.log(source);
456         if (keyDepend) {
457             this.dependancies.set(dict.name, keyDepend);
458         } else {
459             // this.dependancies.delete(dict.name);
460             // this.dependanciesSource.delete(dict.name);
461         }
462         this.dependanciesSource.set(dict.name, source);
463         console.log(this.dependancies);
464         console.log(this.dependanciesSource);
465     }
466
467     getKeys(map: Map<string, any>) {
468         return Array.from(map.keys());
469     }
470
471     getValue(key) {
472         return this.dependancies.get(key);
473     }
474
475     rerender(): void {
476         this.dtTrigger.next();
477     }
478
479     ngOnDestroy(): void {
480         // Do not forget to unsubscribe the event
481         this.dtTrigger.unsubscribe();
482         this.resTableDtTrigger.unsubscribe();
483         // this.templateStore.unsubscribe();
484     }
485 }
486
487 class DependancyVal {
488     source: string;
489     keyDepend: any;
490     constructor(
491         source: string,
492         keyDepend: any
493     ) {
494         this.source = source;
495         this.keyDepend = keyDepend;
496     }
497 }