61ea374a3b0208b252faf5335fc9e1915a34c04d
[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/XmlParser';
14 declare var $: any;
15
16 @Component({
17     selector: 'app-templ-mapp-creation',
18     templateUrl: './templ-mapp-creation.component.html',
19     styleUrls: ['./templ-mapp-creation.component.css']
20 })
21 export class TemplMappCreationComponent implements OnInit, OnDestroy {
22     @Output() showListView = new EventEmitter<any>();
23     @Output() showCreationView = new EventEmitter<any>();
24     public uploadedFiles: FileSystemFileEntry[] = [];
25     fileNames: Set<string> = new Set();
26     jsonConvert = new JsonConvert();
27     public files: NgxFileDropEntry[] = [];
28     fileName: any;
29     templateInfo = new TemplateInfo();
30     variables: string[] = [];
31     dtOptions: DataTables.Settings = {};
32     initDtOptions: DataTables.Settings = {};
33     // We use this trigger because fetching the list of persons can be quite long,
34     // thus we ensure the data is fetched before rendering
35     dtTrigger = new Subject();
36     resTableDtTrigger = new Subject();
37     resourceDictionaryRes: ResourceDictionary[] = [];
38     allowedExt = ['.vtl'];
39     @ViewChild(DataTableDirective, { static: false })
40     dtElement: DataTableDirective;
41     MappingAdapter: MappingAdapter;
42     mapping = new Map();
43     templateFileContent: string;
44     templateExt = 'Velcoity';
45     dependancies = new Map<string, Array<string>>();
46     dependanciesSource = new Map<string, string>();
47     mappingRes = [];
48     currentTemplate: any;
49     currentMapping: any;
50     edit = false;
51     fileToDelete: any = {};
52
53     constructor(
54         private packageCreationStore: PackageCreationStore,
55         private templateStore: TemplateStore,
56         private packageCreationUtils: PackageCreationUtils,
57         private toastr: ToastrService,
58         private sharedService: SharedService
59     ) {
60     }
61
62     ngOnInit() {
63         this.templateStore.state$.subscribe(templateInfo => {
64             // init Template&mapping vars
65             console.log('Oninit');
66             console.log(templateInfo);
67             this.templateInfo = templateInfo;
68             this.fileToDelete = templateInfo.fileName;
69             this.fileName = templateInfo.fileName.split('/')[1];
70             if (this.fileName) {
71                 this.fileName = this.fileName.split('-')[0];
72             }
73             if (templateInfo.type === 'mapping' || templateInfo.type.includes('mapping')) {
74                 this.mappingRes = templateInfo.mapping;
75                 this.currentMapping = Object.assign({}, templateInfo);
76                 this.resourceDictionaryRes = [];
77                 this.resTableDtTrigger.next();
78             } else {
79                 this.mappingRes = [];
80                 this.currentMapping = Any;
81             }
82             this.templateFileContent = templateInfo.fileContent;
83             this.currentTemplate = Object.assign({}, templateInfo);
84
85             if (templateInfo.type === 'template' || templateInfo.type.includes('template')) {
86                 this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.vtl';
87             } else {
88                 this.currentTemplate = Any;
89             }
90
91         });
92
93         this.sharedService.isEdit().subscribe(res => {
94             console.log('------------------------');
95             console.log(res);
96             this.edit = res;
97
98             if (!this.edit) {
99                 console.log('remove ----');
100                 this.currentMapping = {};
101                 this.currentTemplate = {};
102                 this.fileName = '';
103                 this.templateFileContent = '';
104                 this.resourceDictionaryRes = [];
105                 this.mappingRes = [];
106             }
107         });
108
109         this.initDtOptions = {
110             pagingType: 'full_numbers',
111             pageLength: 25,
112             destroy: true,
113             retrieve: true,
114         };
115         this.dtOptions = {
116             pagingType: 'full_numbers',
117             pageLength: 25,
118             destroy: true,
119             retrieve: true,
120         };
121     }
122
123     getFileExtension() {
124         switch (this.templateExt) {
125             case 'Velcoity':
126                 return '.vtl';
127             case 'Koltin':
128                 return '.ktl';
129             case 'Jinja':
130                 return '.j2';
131             default:
132                 return '.vtl';
133         }
134     }
135
136     fileExtensionFromString(filename: string): string {
137         const fileExtension = filename.substring(filename.lastIndexOf('.') + 1);
138         return fileExtension;
139     }
140
141     public getTemplateVariable(fileContent: string) {
142         const variables: string[] = [];
143         const stringsSlittedByBraces = fileContent.split('${');
144         const stringsDefaultByDollarSignOnly = fileContent.split('"$');
145
146         for (let i = 1; i < stringsSlittedByBraces.length; i++) {
147             const element = stringsSlittedByBraces[i];
148             if (element) {
149                 const firstElement = element.split('}')[0];
150                 if (!variables.includes(firstElement)) {
151                     variables.push(firstElement);
152                 } else {
153                     console.log(firstElement);
154                 }
155             }
156         }
157
158         for (let i = 1; i < stringsDefaultByDollarSignOnly.length; i++) {
159             const element = stringsDefaultByDollarSignOnly[i];
160             if (element && !element.includes('$')) {
161                 const firstElement = element.split('"')[0]
162                     .replace('{', '')
163                     .replace('}', '').trim();
164                 if (!variables.includes(firstElement)) {
165                     variables.push(firstElement);
166                 }
167             }
168         }
169         return variables;
170     }
171
172     public dropped(files: NgxFileDropEntry[]) {
173         this.files = files;
174         for (const droppedFile of files) {
175             // Is it a file? & Not added before
176             if (droppedFile.fileEntry.isFile) {
177                 const fileEntry = droppedFile.fileEntry as FileSystemFileEntry;
178                 this.uploadedFiles.push(fileEntry);
179                 this.fileNames.add(fileEntry.name);
180
181             }
182         }
183     }
184     removeFile(index) {
185         this.uploadedFiles.splice(index, 1);
186     }
187
188     confirmDelete() {
189         // Delete from templates
190         this.sharedService.deleteFromList(this.fileName);
191         this.packageCreationStore.state.templates.files.delete(this.fileToDelete);
192         // Delete from Mapping
193         this.packageCreationStore.state.mapping.files.delete(this.fileToDelete);
194         if (
195             this.packageCreationStore.state.templates.files.size > 0 ||
196             this.packageCreationStore.state.mapping.files.size > 0
197         ) {
198             this.openListView();
199         }
200
201     }
202     uploadFile() {
203         this.dependancies.clear();
204         this.dependanciesSource.clear();
205         if (this.allowedExt.includes('.csv') || this.allowedExt.includes('.xml')) {
206             this.fetchkeysfromfile();
207         } else {
208             this.setTemplateFilesToStore();
209         }
210         $('.btn-cancel').click();
211     }
212
213     fetchkeysfromfile() {
214         for (const droppedFile of this.uploadedFiles) {
215             droppedFile.file((file: File) => {
216                 const fileReader = new FileReader();
217                 fileReader.onload = (e) => {
218                     const fileExt = this.fileExtensionFromString(droppedFile.name);
219                     if (fileExt === 'csv') {
220                         this.variables = fileReader.result.toString().split(',');
221                     } else {
222                         const parser = new XmlParser();
223                         this.variables = parser.getVariables(fileReader.result.toString());
224                     }
225                     console.log(this.variables);
226                     this.getMappingTableFromTemplate(null);
227
228                 };
229                 fileReader.readAsText(file);
230             });
231         }
232         this.uploadedFiles = [];
233     }
234
235     private convertDictionaryToMap(resourceDictionaries: ResourceDictionary[]): Mapping[] {
236         const mapArray: Mapping[] = [];
237         for (const resourceDictionary of resourceDictionaries) {
238             this.MappingAdapter = new MappingAdapter(resourceDictionary, this.dependancies, this.dependanciesSource);
239             mapArray.push(this.MappingAdapter.ToMapping());
240         }
241         console.log(mapArray);
242         return mapArray;
243     }
244
245     setTemplateFilesToStore() {
246         for (const droppedFile of this.uploadedFiles) {
247             droppedFile.file((file: File) => {
248                 const fileReader = new FileReader();
249                 fileReader.onload = (e) => {
250                     this.templateFileContent = fileReader.result.toString();
251                     this.variables = this.getTemplateVariable(this.templateFileContent);
252
253                 };
254                 fileReader.readAsText(file);
255             });
256         }
257         this.uploadedFiles = [];
258     }
259
260     textChanges(code: any, fileName: string) {
261         //  this.packageCreationStore.addTemplate(fileName, code);
262         this.templateFileContent = code;
263     }
264
265     public fileOver(event) {
266         console.log(event);
267     }
268
269     public fileLeave(event) {
270         console.log(event);
271     }
272     //
273     resetTheUploadedFiles() {
274         this.uploadedFiles = [];
275     }
276
277     openListView() {
278         console.log('open List view');
279         this.showListView.emit('tell parent to open create views');
280     }
281
282     openCreationView() {
283         console.log('close creation view');
284         this.showCreationView.emit('close create form and open list');
285     }
286
287     getMappingTableFromTemplate(e) {
288         console.log('-' + this.templateFileContent + '-');
289         this.resourceDictionaryRes = [];
290         if (e) {
291             e.preventDefault();
292         }
293         if (this.variables && this.variables.length > 0) {
294             console.log('base');
295             this.packageCreationStore.getTemplateAndMapping(this.variables).subscribe(res => {
296                 let message = 'Attributes are Fetched';
297                 this.mappingRes = [];
298                 this.resourceDictionaryRes = res;
299                 console.log(this.resourceDictionaryRes);
300                 this.rerender();
301                 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length <= 0) {
302                     message = 'No values for those attributes';
303                 }
304                 this.toastr.success(message, 'Success');
305             }, err => {
306                 this.toastr.error('Error');
307             });
308         }
309     }
310
311     initMap(key, map) {
312         if (!this.dependanciesSource.has(key)) {
313             this.dependanciesSource.set(key, map.key);
314         }
315         return map.key;
316     }
317     cancel() {
318         this.fileName = '';
319         this.templateFileContent = '';
320         this.resourceDictionaryRes = [];
321         this.mappingRes = [];
322         this.currentMapping = {};
323         this.currentTemplate = {};
324         //   this.closeCreationForm();
325     }
326     saveToStore() {
327         if (this.fileName) {
328             // check file duplication
329             console.log('----------- mode ' + this.edit);
330             if (
331                 (!(this.packageCreationStore.fileExist('Templates/' + this.fileName + '-mapping.json')
332                     || this.packageCreationStore.fileExist('Templates/' + this.fileName + '-template' + this.getFileExtension())))
333                 || this.edit
334             ) {
335                 // Save Mapping to Store
336                 if (this.resourceDictionaryRes && this.resourceDictionaryRes.length > 0) {
337                     const mapArray = this.convertDictionaryToMap(this.resourceDictionaryRes);
338                     this.packageCreationStore.addMapping('Templates/' + this.fileName + '-mapping.json',
339                         this.packageCreationUtils.transformToJson(this.jsonConvert.serialize(mapArray)));
340                     this.resourceDictionaryRes = [];
341                 }
342                 // Save Template to store
343                 // if (this.templateFileContent) {
344                 this.packageCreationStore.addTemplate('Templates/' + this.fileName + '-template' + this.getFileExtension(),
345                     this.templateFileContent);
346                 this.templateFileContent = '';
347                 //  }
348                 this.fileName = '';
349                 this.toastr.success('File is created', 'success');
350                 this.openListView();
351             } else {
352                 console.log('this file already exist');
353                 this.toastr.error('File name already exist', 'Error');
354             }
355         } else {
356             this.toastr.error('Add the file name', 'Error');
357         }
358     }
359
360
361     selectSource(dict, e) {
362         const source = e.target.value;
363         let keyDepend = null;
364         this.dependancies.set(dict.name, null);
365         try {
366             keyDepend = dict.definition.sources[source].properties['key-dependencies'] || null;
367         } catch (e) { }
368         console.log(dict);
369         console.log(source);
370         if (keyDepend) {
371             this.dependancies.set(dict.name, keyDepend);
372         } else {
373             // this.dependancies.delete(dict.name);
374             // this.dependanciesSource.delete(dict.name);
375         }
376         this.dependanciesSource.set(dict.name, source);
377         console.log(this.dependancies);
378         console.log(this.dependanciesSource);
379     }
380
381     getKeys(map: Map<string, any>) {
382         return Array.from(map.keys());
383     }
384
385     getValue(key) {
386         return this.dependancies.get(key);
387     }
388
389     rerender(): void {
390         this.dtTrigger.next();
391
392         // if (this.dtElement.dtInstance) {
393         //     console.log('rerender');
394         //     this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => {
395         //         dtInstance.destroy();
396         //         this.dtElement.dtOptions = this.dtOptions;
397         //         this.dtElement.dtTrigger.next();
398         //         dtInstance.draw();
399         //     });
400         // } else {
401         //     this.dtTrigger.next();
402         // }
403     }
404
405     ngOnDestroy(): void {
406         // Do not forget to unsubscribe the event
407         this.dtTrigger.unsubscribe();
408         this.resTableDtTrigger.unsubscribe();
409     }
410 }
411
412 class DependancyVal {
413     source: string;
414     keyDepend: any;
415     constructor(
416         source: string,
417         keyDepend: any
418     ) {
419         this.source = source;
420         this.keyDepend = keyDepend;
421     }
422 }