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';
24 selector: 'app-templ-mapp-creation',
25 templateUrl: './templ-mapp-creation.component.html',
26 styleUrls: ['./templ-mapp-creation.component.css']
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[] = [];
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;
50 templateFileContent: string;
52 dependancies = new Map<string, Array<string>>();
53 dependanciesSource = new Map<string, string>();
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',
69 initColumn: string[] = ['select', ...this.resColumns];
73 // displayedColumns: string[] = ['id', 'name', 'progress', 'color'];
74 dataSource: MatTableDataSource<{}>;
75 initDataSource: MatTableDataSource<{}>;
76 // dataSource = new MatTableDataSource();
77 @ViewChild('paginate', { static: true }) paginator: MatPaginator;
78 @ViewChild('sort', { static: true }) sort: MatSort;
79 @ViewChild(MatPaginator, { static: true }) initPaginator: MatPaginator;
80 @ViewChild(MatSort, { static: true }) initSort: MatSort;
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
96 this.dataSource.paginator = this.paginator;
97 this.dataSource.sort = this.sort;
98 this.initDataSource.paginator = this.initPaginator;
99 this.initDataSource.sort = this.initSort;
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];
115 this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('-'));
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;
129 this.mappingRes = [];
130 this.currentMapping = Any;
131 this.resourceDictionaryRes = [];
133 this.templateFileContent = templateInfo.fileContent;
134 this.templateExt = this.templateInfo.ext || this.templateExt;
135 this.currentTemplate = Object.assign({}, templateInfo);
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);
142 this.currentTemplate = Any;
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;
156 console.log('remove ----');
157 this.currentMapping = {};
158 this.currentTemplate = {};
160 this.templateFileContent = '';
161 this.resourceDictionaryRes = [];
162 this.mappingRes = [];
168 setProp(e, propName, index) {
169 this.resourceDictionaryRes[index][propName] = e.checked;
170 console.log(this.resourceDictionaryRes[index]);
174 if (this.selectedProps.has(value)) {
175 this.selectedProps.delete(value);
177 this.selectedProps.add(value);
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();
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();
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);
211 if (this.resourceDictionaryRes.length === this.selectedProps.size) {
212 this.selectedProps = new Set<string>();
214 this.resourceDictionaryRes.forEach(prop => {
216 this.selectedProps.add(prop.name);
222 let currentResDictionary = [];
223 if (this.selectedProps && this.selectedProps.size > 0) {
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';
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;
243 this.toastr.success(message, 'Success');
245 this.toastr.error('Error');
252 switch (this.templateExt) {
264 fileExtensionFromString(filename: string): string {
265 const fileExtension = filename.substring(filename.lastIndexOf('.') + 1);
266 return fileExtension;
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);
276 public dropped(files: NgxFileDropEntry[]) {
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);
289 this.uploadedFiles.splice(index, 1);
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);
299 this.packageCreationStore.state.templates.files.size > 0 ||
300 this.packageCreationStore.state.mapping.files.size > 0
307 this.dependancies.clear();
308 this.dependanciesSource.clear();
309 if (this.allowedExt.includes('.csv') || this.allowedExt.includes('.xml')) {
310 this.fetchkeysfromfile();
312 this.setTemplateFilesToStore();
314 $('.btn-cancel').click();
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(',');
326 const parser = new XmlParser();
327 this.variables = parser.getVariables(fileReader.result.toString());
329 console.log('variables = ' + this.variables);
330 this.getMappingTableFromTemplate(null);
333 fileReader.readAsText(file);
336 this.uploadedFiles = [];
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());
345 console.log(mapArray);
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);
359 fileReader.readAsText(file);
362 this.uploadedFiles = [];
365 textChanges(code: any, fileName: string) {
366 // this.packageCreationStore.addTemplate(fileName, code);
367 // this.templateFileContent = code;
370 public fileOver(event) {
374 public fileLeave(event) {
378 resetTheUploadedFiles() {
379 this.uploadedFiles = [];
383 console.log('open List view');
384 this.showListView.emit('tell parent to open create views');
388 console.log('close creation view');
389 this.showCreationView.emit('close create form and open list');
392 identify(index, item) {
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
402 console.log(this.resourceDictionaryRes[index]);
405 getMappingTableFromTemplate(e) {
406 console.log('-' + this.templateFileContent + '-');
407 this.resourceDictionaryRes = [];
411 this.variables = this.getTemplateVariable(this.templateFileContent);
412 console.log('variables = ' + this.variables);
413 if (this.variables && this.variables.length > 0) {
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);
421 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length <= 0) {
422 message = 'No values for those attributes';
424 this.toastr.success(message, 'Success');
426 this.toastr.error('Error');
429 this.toastr.error('Empty or Invalid file format. Validate your file first');
434 if (!this.dependanciesSource.has(key)) {
435 this.dependanciesSource.set(key, map.key);
441 this.templateFileContent = '';
442 this.resourceDictionaryRes = [];
443 this.mappingRes = [];
444 this.currentMapping = {};
445 this.currentTemplate = {};
446 // this.closeCreationForm();
452 const filename = this.fileName;
454 // check file duplication
455 console.log('----------- mode ' + this.edit);
456 const fileContent = this.templateFileContent;
458 (!(this.packageCreationStore.fileExist('Templates/' + this.fileName + '-mapping.json')
459 || this.packageCreationStore.fileExist('Templates/' + this.fileName + '-template' + this.getFileExtension())))
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 = [];
469 // Save Template to store
470 // if (this.templateFileContent) {
471 this.packageCreationStore.addTemplate('Templates/' + filename + '-template' + this.getFileExtension(),
473 this.templateFileContent = '';
476 this.toastr.success('File is created', 'success');
478 if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') {
479 this.tourService.goto('tm-templateEdit');
482 console.log('this file already exist');
483 this.toastr.error('File name already exist', 'Error');
486 this.toastr.error('Add the file name', 'Error');
491 selectSource(dict, e) {
492 const source = e.target.value;
493 let keyDepend = null;
494 this.dependancies.set(dict.name, null);
496 keyDepend = dict.definition.sources[source].properties['key-dependencies'] || null;
501 this.dependancies.set(dict.name, keyDepend);
503 // this.dependancies.delete(dict.name);
504 // this.dependanciesSource.delete(dict.name);
506 this.dependanciesSource.set(dict.name, source);
507 console.log(this.dependancies);
508 console.log(this.dependanciesSource);
511 getKeys(map: Map<string, any>) {
512 return Array.from(map.keys());
516 return this.dependancies.get(key);
520 this.initDataSource = new MatTableDataSource(this.resourceDictionaryRes);
521 // this.cdr.detectChanges();
523 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,
524 as result some function are not working well like save and you have to move to other pages to fix that.
526 this.initPaginator.pageSize = this.resourceDictionaryRes.length;
527 this.initDataSource.paginator = this.initPaginator;
528 this.initDataSource.sort = this.initSort;
531 ngOnDestroy(): void {
532 // Do not forget to unsubscribe the event
533 this.dtTrigger.unsubscribe();
534 this.resTableDtTrigger.unsubscribe();
535 // this.templateStore.unsubscribe();
539 class DependancyVal {
546 this.source = source;
547 this.keyDepend = keyDepend;