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