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