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>();
54 mappingRes: Mapping[] = [];
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 @ViewChild(MatPaginator, { static: true }) initPaginator: MatPaginator;
77 @ViewChild(MatSort, { static: true }) initSort: MatSort;
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
93 this.initDataSource.paginator = this.initPaginator;
94 this.initDataSource.sort = this.initSort;
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];
110 this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('-'));
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
120 this.mappingRes = [];
121 this.currentMapping = Any;
122 this.resourceDictionaryRes = [];
124 this.templateFileContent = templateInfo.fileContent;
125 this.templateExt = this.templateInfo.ext || this.templateExt;
126 this.currentTemplate = Object.assign({}, templateInfo);
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);
133 this.currentTemplate = Any;
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;
147 console.log('remove ----');
148 this.currentMapping = {};
149 this.currentTemplate = {};
151 this.templateFileContent = '';
152 this.resourceDictionaryRes = [];
153 this.mappingRes = [];
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();
166 setProp(e, propName, index) {
167 if (propName === 'input-param') {
168 this.mappingRes[index][propName] = e.checked;
171 // tslint:disable-next-line: no-string-literal
172 this.mappingRes[index]['property'][propName] = e.checked;
174 // console.log(this.mappingRes[index]);
178 if (this.selectedProps.has(value)) {
179 this.selectedProps.delete(value);
181 this.selectedProps.add(value);
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);
199 // if all items are already selected, unselect them
200 if (this.mappingRes.length === this.selectedProps.size) {
201 this.selectedProps = new Set<string>();
203 this.mappingRes.forEach(prop => {
204 // console.log(prop);
205 this.selectedProps.add(prop.name);
211 let currentResDictionary = [];
212 if (this.selectedProps && this.selectedProps.size > 0) {
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';
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;
232 this.toastr.success(message, 'Success');
233 this.selectedProps = new Set();
235 this.toastr.error('Error');
242 switch (this.templateExt) {
254 fileExtensionFromString(filename: string): string {
255 const fileExtension = filename.substring(filename.lastIndexOf('.') + 1);
256 return fileExtension;
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);
266 public dropped(files: NgxFileDropEntry[]) {
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);
279 this.uploadedFiles.splice(index, 1);
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);
289 this.packageCreationStore.state.templates.files.size > 0 ||
290 this.packageCreationStore.state.mapping.files.size > 0
297 this.dependancies.clear();
298 this.dependanciesSource.clear();
299 if (this.allowedExt.includes('.csv') || this.allowedExt.includes('.xml')) {
300 this.fetchkeysfromfile();
302 this.setTemplateFilesToStore();
304 $('.btn-cancel').click();
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(',');
316 const parser = new XmlParser();
317 this.variables = parser.getVariables(fileReader.result.toString());
319 console.log('variables = ' + this.variables);
320 this.getMappingTableFromTemplate(null);
323 fileReader.readAsText(file);
326 this.uploadedFiles = [];
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());
335 console.log(mapArray);
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);
346 console.log(mapArray);
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);
360 fileReader.readAsText(file);
363 this.uploadedFiles = [];
366 textChanges(code: any, fileName: string) {
367 // this.packageCreationStore.addTemplate(fileName, code);
368 // this.templateFileContent = code;
371 public fileOver(event) {
375 public fileLeave(event) {
379 resetTheUploadedFiles() {
380 this.uploadedFiles = [];
384 console.log('open List view');
385 this.showListView.emit('tell parent to open create views');
389 console.log('close creation view');
390 this.showCreationView.emit('close create form and open list');
393 identify(index, item) {
396 setVelocity(index, value) {
397 // tslint:disable-next-line: no-string-literal
398 this.mappingRes[index].property['metadata'] = {
399 'transform-template': value
401 console.log(this.resourceDictionaryRes[index]);
404 getMappingTableFromTemplate(e) {
405 console.log('-' + this.templateFileContent + '-');
406 this.resourceDictionaryRes = [];
410 this.variables = this.getTemplateVariable(this.templateFileContent);
411 console.log('variables = ' + this.variables);
412 if (this.variables && this.variables.length > 0) {
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);
422 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length <= 0) {
423 message = 'No values for those attributes';
425 this.toastr.success(message, 'Success');
427 this.toastr.error('Error');
430 this.toastr.error('Empty or Invalid file format. Validate your file first');
435 if (!this.dependanciesSource.has(key)) {
436 this.dependanciesSource.set(key, map.key);
442 this.templateFileContent = '';
443 this.resourceDictionaryRes = [];
444 this.mappingRes = [];
445 this.currentMapping = {};
446 this.currentTemplate = {};
447 // this.closeCreationForm();
453 objectToString(object) {
455 return JSON.stringify(object);
460 const filename = this.fileName;
462 // check file duplication
463 console.log('----------- mode ' + this.edit);
464 const fileContent = this.templateFileContent;
466 (!(this.packageCreationStore.fileExist('Templates/' + filename + '-mapping.json')
467 || this.packageCreationStore.fileExist('Templates/' + filename + '-template' + this.getFileExtension())))
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)))
476 this.packageCreationStore.addMapping('Templates/' + filename + '-mapping.json',
477 JSON.stringify(mapArray));
479 this.packageCreationStore.addMapping('Templates/' + filename + '-mapping.json',
480 this.packageCreationUtils.transformToJson(this.jsonConvert.serialize(mapArray)));
482 this.mappingRes = [];
484 // Save Template to store
485 // if (this.templateFileContent) {
486 this.packageCreationStore.addTemplate('Templates/' + filename + '-template' + this.getFileExtension(),
488 this.templateFileContent = '';
491 this.toastr.success('File is created', 'success');
493 if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') {
494 this.tourService.goto('tm-templateEdit');
497 console.log('this file already exist');
498 this.toastr.error('File name already exist', 'Error');
501 this.toastr.error('Add the file name', 'Error');
506 selectSource(dict, e) {
507 const source = e.target.value;
508 let keyDepend = null;
509 this.dependancies.set(dict.name, null);
511 keyDepend = dict.sources[source].properties['key-dependencies'] || null;
516 this.dependancies.set(dict.name, keyDepend);
518 // this.dependancies.delete(dict.name);
519 // this.dependanciesSource.delete(dict.name);
521 this.dependanciesSource.set(dict.name, source);
522 console.log(this.dependancies);
523 console.log(this.dependanciesSource);
526 getKeys(map: Map<string, any>) {
527 return Array.from(map.keys());
531 return this.dependancies.get(key);
535 this.initDataSource = new MatTableDataSource(this.mappingRes);
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.
540 this.initPaginator.pageSize = this.mappingRes.length;
541 this.initDataSource.paginator = this.initPaginator;
542 this.initDataSource.sort = this.initSort;
545 ngOnDestroy(): void {
546 // Do not forget to unsubscribe the event
547 this.dtTrigger.unsubscribe();
548 this.resTableDtTrigger.unsubscribe();
549 // this.templateStore.unsubscribe();