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