diff options
Diffstat (limited to 'cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation')
31 files changed, 1139 insertions, 260 deletions
diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts index f739ceb2e..adae66244 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts @@ -37,9 +37,11 @@ export class DesignerCreationMode extends PackageCreationModes { } private createDefinitionsFolder(cbaPackage: CBAPackage, packageCreationUtils: PackageCreationUtils) { - cbaPackage.definitions.imports.forEach((valueOfFile, key) => { - FilesContent.putData(key, valueOfFile); - }); + if (cbaPackage.definitions.imports && cbaPackage.definitions.imports.size > 0) { + cbaPackage.definitions.imports.forEach((valueOfFile, key) => { + FilesContent.putData(key, valueOfFile); + }); + } const filenameEntry = 'Definitions/' + cbaPackage.metaData.name + '.json'; const vlbDefinition: VlbDefinition = new VlbDefinition(); @@ -51,42 +53,52 @@ export class DesignerCreationMode extends PackageCreationModes { metadata['author-email'] = 'shaaban.eltanany.ext@orange.com'; metadata['user-groups'] = 'test'; metadata.template_description = cbaPackage.metaData.description; - cbaPackage.metaData.mapOfCustomKey.forEach((customKeyValue, key) => { - metadata[key] = customKeyValue; - }); + if (cbaPackage.metaData.mapOfCustomKey && cbaPackage.metaData.mapOfCustomKey.size > 0) { + cbaPackage.metaData.mapOfCustomKey.forEach((customKeyValue, key) => { + metadata[key] = customKeyValue; + }); + } // create Tags let fullTags = ''; let setCount = 0; - cbaPackage.metaData.templateTags.forEach(val => { - setCount++; - if (setCount === cbaPackage.metaData.templateTags.size) { - fullTags += val; - } else { - fullTags += val + ', '; - } - }); + if (cbaPackage.metaData.templateTags && cbaPackage.metaData.templateTags.size > 0) { + cbaPackage.metaData.templateTags.forEach(val => { + setCount++; + if (setCount === cbaPackage.metaData.templateTags.size) { + fullTags += val; + } else { + fullTags += val + ', '; + } + }); + } metadata.template_tags = fullTags; vlbDefinition.metadata = metadata; const files: Import[] = []; - cbaPackage.definitions.imports.forEach((valueOfFile, key) => { - if (!key.includes(cbaPackage.metaData.name)) { - files.push({file: key}); - } - }); - console.log(vlbDefinition); - vlbDefinition.imports = files; - console.log(cbaPackage.definitions.dslDefinition.content); - if (cbaPackage.definitions.dslDefinition.content) { + let insideVlbDefinition: VlbDefinition = null; + if (cbaPackage.definitions.imports && cbaPackage.definitions.imports.size > 0) { + cbaPackage.definitions.imports.forEach((valueOfFile, key) => { + if (!key.includes(cbaPackage.metaData.name)) { + files.push({file: key}); + } else { + insideVlbDefinition = JSON.parse(valueOfFile); + } + }); + } + + if (cbaPackage.definitions && cbaPackage.definitions.dslDefinition && + cbaPackage.definitions.dslDefinition.content) { vlbDefinition.dsl_definitions = JSON.parse(cbaPackage.definitions.dslDefinition.content); } - if (cbaPackage.templateTopology.content) { + + vlbDefinition.imports = files; + if (cbaPackage.templateTopology && cbaPackage.templateTopology.content) { vlbDefinition.topology_template = JSON.parse(cbaPackage.templateTopology.content); + } else if (insideVlbDefinition && insideVlbDefinition.topology_template) { + vlbDefinition.topology_template = insideVlbDefinition.topology_template; } - console.log(vlbDefinition); + const value = packageCreationUtils.transformToJson(vlbDefinition); FilesContent.putData(filenameEntry, value); - console.log('hello there'); console.log(FilesContent.getMapOfFilesNamesAndContent()); - } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts index 6b80358fd..8b82cc0eb 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts @@ -1,7 +1,7 @@ -import { CBAPackage } from '../mapping-models/CBAPacakge.model'; -import { ModeType } from '../mapping-models/ModeType'; -import { FilesContent, MetaDataTabModel } from '../mapping-models/metadata/MetaDataTab.model'; -import { PackageCreationUtils } from '../package-creation.utils'; +import {CBAPackage} from '../mapping-models/CBAPacakge.model'; +import {ModeType} from '../mapping-models/ModeType'; +import {FilesContent, MetaDataTabModel} from '../mapping-models/metadata/MetaDataTab.model'; +import {PackageCreationUtils} from '../package-creation.utils'; export abstract class PackageCreationModes { @@ -21,25 +21,28 @@ export abstract class PackageCreationModes { public static mapModeType(cbaPackage: CBAPackage) { console.log(cbaPackage.metaData.mode); - if (cbaPackage.metaData.mode.includes('Scripting')) { - cbaPackage.metaData.mode = ModeType.Scripting; - } else if (cbaPackage.metaData.mode.includes('Designer') || cbaPackage.metaData.mode.includes('DEFAULT') ) { - cbaPackage.metaData.mode = ModeType.Designer; - } else { - cbaPackage.metaData.mode = ModeType.Generic; - } + /* if (cbaPackage.metaData.mode.includes('Scripting')) { + cbaPackage.metaData.mode = ModeType.Scripting; + } else if (cbaPackage.metaData.mode.includes('Designer') || cbaPackage.metaData.mode.includes('DEFAULT') ) { + cbaPackage.metaData.mode = ModeType.Designer; + } else { + cbaPackage.metaData.mode = ModeType.Generic; + }*/ + cbaPackage.metaData.mode = ModeType.Designer; return cbaPackage; } getValueOfMetaData(metaDataTab: MetaDataTabModel): string { let tags = ''; let count = 0; - for (const tag of metaDataTab.templateTags) { - count++; - if (count === metaDataTab.templateTags.size) { - tags += tag; - } else { - tags += tag + ', '; + if (metaDataTab.templateTags && metaDataTab.templateTags.size > 0) { + for (const tag of metaDataTab.templateTags) { + count++; + if (count === metaDataTab.templateTags.size) { + tags += tag; + } else { + tags += tag + ', '; + } } } return 'TOSCA-Meta-File-Version: 1.0.0\n' + diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html index 8f2b554d9..641caf2ad 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html @@ -74,7 +74,7 @@ <div [id]="'id-'+mapIndex" class="collapse" [attr.aria-labelledby]="'head-'+mapIndex" data-parent="#accordion"> <div class="card-body"> - <ace-editor [(text)]="file.value" (textChange)="textChanges($event,file.key)" [mode]="'json'" + <ace-editor [(text)]="file.value" readOnly="true" (textChange)="textChanges($event,file.key)" [mode]="'json'" [autoUpdateContent]="true" [durationBeforeCallback]="1000" [theme]="'eclipse'" #editor style="height:300px;"> </ace-editor> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts index f82310872..7a029fb3f 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts @@ -1,8 +1,11 @@ -import { Any, JsonObject, JsonProperty } from 'json2typescript'; +import {JsonObject, JsonProperty} from 'json2typescript'; @JsonObject('topology_template') export class TemplateTopology { - public content: string; + // tslint:disable-next-line:variable-name + public node_templates: object; + public workflows: object; + public content: string ; } @JsonObject @@ -22,26 +25,27 @@ export class VlbDefinition { export class DslContent { } + // Refactor varaibles name and use JsonConverteri @JsonObject('metadata') export class Metadata { @JsonProperty('template_author') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_author: string; 'author-email': string; 'user-groups': string; @JsonProperty('template_name') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_name: string; @JsonProperty('template_version') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_version: string; @JsonProperty('template_tag') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_tags: string; @JsonProperty('dictionary_group') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name dictionary_group: string; @JsonProperty('template_tags') templateTags: string; diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts index b4de578b9..e63b17fa2 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts @@ -10,11 +10,14 @@ export class MappingAdapter { private dependanciesSource: Map<string, string>) { } ToMapping(): Mapping { + // console.log(this.resourceDictionary.definition.property); const mapping = new Mapping(); mapping.name = this.resourceDictionary.name; mapping.dictionaryName = this.resourceDictionary.name; - mapping.property = this.resourceDictionary.definition.property; - mapping.inputParam = false; + mapping.property = Object.assign({}, this.resourceDictionary.definition.property); + mapping.inputParam = this.resourceDictionary['input-param'] || false; + // tslint:disable-next-line: no-string-literal + mapping.property['required'] = this.resourceDictionary['required'] || false; mapping.dictionarySource = this.dependanciesSource.get(mapping.name); if (this.dependancies.get(mapping.name)) { mapping.dependencies = this.dependancies.get(mapping.name); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html index f2e5eedf1..16bf7fccd 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html @@ -33,7 +33,7 @@ <div class="single-line-model"> <label class="label-name">Name <span>*</span></label> <div class="label-input"> - <input tourAnchor="mt-packageName" type="input" (change)="checkRequiredElements()" + <input tourAnchor="mt-packageName" type="input" [readOnly]="!isNameEditable" (change)="checkRequiredElements()" [(ngModel)]="metaDataTab.name" placeholder="Package name"> </div> <!--<div class="model-note-container error-message"> @@ -49,6 +49,7 @@ [(ngModel)]="metaDataTab.version" (input)="validatePackageNameAndVersion()" pattern="(\d+)\.(\d+)\.(\d+)" placeholder="Example: 1.0.0"> </div> + <div class="model-note-container tag-notes">Must follow this format (1.0.0)</div> <div class="model-note-container error-message">{{errorMessage}}</div> </div> <div class="single-line-model"> @@ -123,4 +124,4 @@ </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts index af5b875f7..a46d2a3ec 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts @@ -23,6 +23,7 @@ export class MetadataTabComponent implements OnInit { metaDataTab: MetaDataTabModel = new MetaDataTabModel(); errorMessage: string; versionPattern = '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$'; + isNameEditable = false; constructor( private route: ActivatedRoute, @@ -36,7 +37,7 @@ export class MetadataTabComponent implements OnInit { this.metaDataTab.templateTags = this.tags; this.metaDataTab.mapOfCustomKey = this.customKeysMap; this.metaDataTab.mode = this.modeType; - + this.isNameEditable = this.route.snapshot.paramMap.get('id') == null; this.packageCreationStore.state$.subscribe(element => { if (element && element.metaData) { @@ -47,7 +48,6 @@ export class MetadataTabComponent implements OnInit { this.tags = element.metaData.templateTags; this.tags.delete(''); this.metaDataTab.templateTags = this.tags; - console.log(element); if (element.metaData.mode && element.metaData.mode.includes('DEFAULT')) { this.metaDataTab.mode = 'Designer Mode'; this.modeType = this.metaDataTab.mode; @@ -55,8 +55,12 @@ export class MetadataTabComponent implements OnInit { this.customKeysMap = element.metaData.mapOfCustomKey; this.metaDataTab.mapOfCustomKey = this.customKeysMap; + /* if (this.isNameEditable) { + this.validatePackageNameAndVersion(); + }*/ // this.tags = element.metaData.templateTags; + } }); } @@ -98,6 +102,8 @@ export class MetadataTabComponent implements OnInit { } validatePackageNameAndVersion() { + console.log('in validate'); + console.log('in this.metaDataTab.name' + this.metaDataTab.name); if (this.metaDataTab.name && this.metaDataTab.version) { this.packageCreationService.checkBluePrintNameAndVersion(this.metaDataTab.name, this.metaDataTab.version).then(element => { if (element) { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts new file mode 100644 index 000000000..232590c62 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts @@ -0,0 +1,163 @@ +import {Injectable, ViewChild} from '@angular/core'; +import {MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; +import {TemplateTopology, VlbDefinition} from './mapping-models/definitions/VlbDefinition'; +import {DslDefinition} from './mapping-models/CBAPacakge.model'; +import {PackageCreationStore} from './package-creation.store'; +import * as JSZip from 'jszip'; +import {PackageCreationUtils} from './package-creation.utils'; +import {MetadataTabComponent} from './metadata-tab/metadata-tab.component'; +import {DesignerStore} from '../designer/designer.store'; +import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; + +@Injectable({ + providedIn: 'root' +}) +export class PackageCreationExtractionService { + + private zipFile: JSZip; + private entryDefinitionKeys: string[] = ['template_tags', 'user-groups', + 'author-email', 'template_version', 'template_name', 'template_author', 'template_description']; + + private toscaMetaDataKeys: string[] = ['TOSCA-Meta-File-Version', 'CSAR-Version', + 'Created-By', 'Entry-Definitions', 'Template-Name', 'Template-Version', 'Template-Type', 'Template-Tags']; + @ViewChild(MetadataTabComponent, {static: false}) + private metadataTabComponent: MetadataTabComponent; + + constructor( + private packageCreationStore: PackageCreationStore, + private packageCreationUtils: PackageCreationUtils, + private designerStore: DesignerStore + ) { + + } + + public extractBlobToStore(blob) { + this.zipFile = new JSZip(); + let packageName = null; + this.zipFile.loadAsync(blob).then((zip) => { + Object.keys(zip.files).filter(fileName => fileName.includes('TOSCA-Metadata/')) + .forEach((filename) => { + zip.files[filename].async('string').then((fileData) => { + if (fileData) { + if (filename.includes('TOSCA-Metadata/')) { + + const metaDataTabInfo: MetaDataTabModel = this.getMetaDataTabInfo(fileData); + packageName = metaDataTabInfo.name; + this.setMetaData(metaDataTabInfo); + console.log('found file ' + packageName); + } + } + }); + }); + }); + + this.zipFile.loadAsync(blob).then((zip) => { + Object.keys(zip.files).forEach((filename) => { + zip.files[filename].async('string').then((fileData) => { + console.log(filename); + if (fileData) { + if (filename.includes('Scripts/')) { + this.setScripts(filename, fileData); + } else if (filename.includes('Templates/')) { + if (filename.includes('-mapping.')) { + this.setMapping(filename, fileData); + } else if (filename.includes('-template.')) { + this.setTemplates(filename, fileData); + } + + } else if (filename.includes('Definitions/')) { + this.setImports(filename, fileData, packageName); + } + } + }); + }); + }); + } + + public setScripts(filename: string, fileData: any) { + this.packageCreationStore.addScripts(filename, fileData); + } + + public setImports(filename: string, fileData: any, packageName: string) { + console.log(filename); + if (filename.includes('Definitions/' + packageName.trim() + '.json')) { + let definition = new VlbDefinition(); + definition = fileData as VlbDefinition; + definition = JSON.parse(fileData); + const dslDefinition = new DslDefinition(); + dslDefinition.content = this.packageCreationUtils.transformToJson(definition.dsl_definitions); + const mapOfCustomKeys = new Map<string, string>(); + for (const metadataKey in definition.metadata) { + if (!this.entryDefinitionKeys.includes(metadataKey + '')) { + mapOfCustomKeys.set(metadataKey + '', definition.metadata[metadataKey + '']); + } + } + + this.packageCreationStore.changeDslDefinition(dslDefinition); + this.packageCreationStore.setCustomKeys(mapOfCustomKeys); + this.setPackageDescription(definition.metadata.template_description); + console.log(definition); + console.log(definition.topology_template); + const content = {}; + const workflow = 'workflows'; + content[workflow] = definition.topology_template ? definition.topology_template.workflows : {}; + const nodeTemplates = 'node_templates'; + content[nodeTemplates] = definition.topology_template ? definition.topology_template.node_templates : {}; + this.designerStore.saveSourceContent(JSON.stringify(content)); + if (definition.topology_template) { + this.packageCreationStore.addTopologyTemplate(definition.topology_template); + } else { + this.packageCreationStore.addTopologyTemplate(new TemplateTopology()); + } + + + } + this.packageCreationStore.addDefinition(filename, fileData); + + } + + public setTemplates(filename: string, fileData: any) { + this.packageCreationStore.addTemplate(filename, fileData); + } + + public setMapping(fileName: string, fileData: string) { + this.packageCreationStore.addMapping(fileName, fileData); + } + + private setMetaData(metaDataObject: MetaDataTabModel) { + this.packageCreationStore.changeMetaData(metaDataObject); + } + + public setMetaDataWithObject(metaDataObject: MetaDataTabModel, bluePrintDetailModel: BluePrintDetailModel) { + metaDataObject.description = bluePrintDetailModel.artifactDescription; + this.packageCreationStore.changeMetaData(metaDataObject); + + } + + public getMetaDataTabInfo(fileData: string) { + const metaDataTabModel = new MetaDataTabModel(); + + const arrayOfLines = fileData.split('\n'); + const map = new Map<string, string>(); + for (const currentLine of arrayOfLines) { + const currentKey = currentLine.split(':')[0]; + const currentValue = currentLine.split(':')[1]; + map.set(currentKey, currentValue); + } + metaDataTabModel.entryFileName = map.get(this.toscaMetaDataKeys[3]); + metaDataTabModel.name = map.get(this.toscaMetaDataKeys[4]); + metaDataTabModel.version = map.get(this.toscaMetaDataKeys[5]).trim(); + metaDataTabModel.mode = map.get(this.toscaMetaDataKeys[6]); + if (map.get(this.toscaMetaDataKeys[7])) { + metaDataTabModel.templateTags = new Set<string>(map.get(this.toscaMetaDataKeys[7]).split(',')); + } + return metaDataTabModel; + } + + private setPackageDescription(templateDescription: string) { + const metaData = this.packageCreationStore.getMetaData(); + metaData.description = templateDescription; + this.setMetaData(metaData); + + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html index a09951cd2..e42304ad6 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html @@ -19,6 +19,16 @@ <input class="dropdown-toggle" type="text"> <div class="dropdown-text"><i class="icon-info" aria-hidden="true"></i></div> <ul class="dropdown-content"> + <li> + <i class="icon-get_started" aria-hidden="true"></i> + <p> + <input id="clicker3" type="checkbox" /> + <label for="clicker"> + Getting Started + <span>Quick steps to help you get started</span> + </label> + </p> + </li> <!-- <li> <i class="icon-get_started" aria-hidden="true"></i> <p> @@ -83,8 +93,9 @@ <div class="nav nav-tabs " id="nav-tab" role="tablist"> <a (click)="openTourGuide('metadataTab')" tourAnchor="metadataTab" class="nav-item nav-link active" id="nav-metadata-tab" data-toggle="tab" href="#nav-metadata" role="tab" aria-controls="nav-metadata" - aria-selected="false" autofocus #nameit (focusout)="saveMetaData()" - [classList]="metadataClasses">METADATA</a> + aria-selected="false" autofocus #nameit (focusout)="saveMetaData()" [classList]="metadataClasses">METADATA</a> + + <a (click)="openTourGuide('tm-templateTab')" tourAnchor="tm-templateTab" class="nav-item nav-link" id="nav-template-tab" data-toggle="tab" href="#nav-template" role="tab" aria-controls="nav-template" aria-selected="false">TEMPLATE & @@ -134,4 +145,4 @@ </div> </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts index 4145e0f8e..c7285774e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts @@ -19,19 +19,22 @@ limitations under the License. ============LICENSE_END============================================ */ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { FilesContent, FolderNodeElement, MetaDataTabModel } from './mapping-models/metadata/MetaDataTab.model'; +import {Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {FilesContent, FolderNodeElement, MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; import * as JSZip from 'jszip'; -import { PackageCreationStore } from './package-creation.store'; -import { Definition } from './mapping-models/CBAPacakge.model'; -import { PackageCreationModes } from './creationModes/PackageCreationModes'; -import { PackageCreationBuilder } from './creationModes/PackageCreationBuilder'; -import { PackageCreationUtils } from './package-creation.utils'; -import { MetadataTabComponent } from './metadata-tab/metadata-tab.component'; -import { Router } from '@angular/router'; -import { ToastrService } from 'ngx-toastr'; -import { TourService } from 'ngx-tour-md-menu'; +import {PackageCreationStore} from './package-creation.store'; +import {CBAPackage, Definition} from './mapping-models/CBAPacakge.model'; +import {PackageCreationModes} from './creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from './creationModes/PackageCreationBuilder'; +import {PackageCreationUtils} from './package-creation.utils'; +import {MetadataTabComponent} from './metadata-tab/metadata-tab.component'; +import {Router} from '@angular/router'; +import {ToastrService} from 'ngx-toastr'; +import {TourService} from 'ngx-tour-md-menu'; +import {PackageCreationService} from './package-creation.service'; +import {ComponentCanDeactivate} from '../../../../common/core/canDactivate/ComponentCanDeactivate'; +import {DesignerStore} from '../designer/designer.store'; @Component({ @@ -39,23 +42,28 @@ import { TourService } from 'ngx-tour-md-menu'; templateUrl: './package-creation.component.html', styleUrls: ['./package-creation.component.css'] }) -export class PackageCreationComponent implements OnInit { +export class PackageCreationComponent extends ComponentCanDeactivate implements OnInit, OnDestroy { + // adding initial referencing to designer mode constructor( private packageCreationStore: PackageCreationStore, + private packageCreationService: PackageCreationService, private packageCreationUtils: PackageCreationUtils, private router: Router, private tourService: TourService, - private toastService: ToastrService) { + private toastService: ToastrService, + private designerStore: DesignerStore) { + + super(); } counter = 0; modes: object[] = [ - { name: 'Designer Mode', style: 'mode-icon icon-designer-mode' }, - { name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode' }]; + {name: 'Designer Mode', style: 'mode-icon icon-designer-mode'}, + {name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode'}]; metaDataTab: MetaDataTabModel = new MetaDataTabModel(); folder: FolderNodeElement = new FolderNodeElement(); zipFile: JSZip = new JSZip(); @@ -63,18 +71,22 @@ export class PackageCreationComponent implements OnInit { definition: Definition = new Definition(); isSaveEnabled = false; - @ViewChild(MetadataTabComponent, { static: false }) + @ViewChild(MetadataTabComponent, {static: false}) metadataTabComponent: MetadataTabComponent; - @ViewChild('nameit', { static: true }) + @ViewChild('nameit', {static: true}) elementRef: ElementRef; versionPattern = '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$'; metadataClasses = 'nav-item nav-link active complete'; + private cbaPackage: CBAPackage; ngOnInit() { this.elementRef.nativeElement.focus(); const regexp = RegExp(this.versionPattern); this.packageCreationStore.state$.subscribe(cbaPackage => { + console.log(cbaPackage); + console.log('abbaaaas' + cbaPackage.metaData.name); + this.cbaPackage = cbaPackage; if (cbaPackage && cbaPackage.metaData && cbaPackage.metaData.description && cbaPackage.metaData.name && cbaPackage.metaData.version && regexp.test(cbaPackage.metaData.version)) { @@ -96,18 +108,17 @@ export class PackageCreationComponent implements OnInit { } saveBluePrint() { - this.packageCreationStore.state$.subscribe( - cbaPackage => { - console.log(cbaPackage); - FilesContent.clear(); - let packageCreationModes: PackageCreationModes; - cbaPackage = PackageCreationModes.mapModeType(cbaPackage); - cbaPackage.metaData = PackageCreationModes.setEntryPoint(cbaPackage.metaData); - packageCreationModes = PackageCreationBuilder.getCreationMode(cbaPackage); - packageCreationModes.execute(cbaPackage, this.packageCreationUtils); - this.filesData.push(this.folder.TREE_DATA); - this.saveBluePrintToDataBase(); - }); + console.log(this.cbaPackage); + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + + // this.cbaPackage.templateTopology.content = this.designerStore.state.sourceContent; + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); + this.saveBluePrintToDataBase(); } @@ -115,13 +126,14 @@ export class PackageCreationComponent implements OnInit { saveBluePrintToDataBase() { this.create(); - this.zipFile.generateAsync({ type: 'blob' }) + this.zipFile.generateAsync({type: 'blob'}) .then(blob => { - this.packageCreationStore.saveBluePrint(blob).subscribe( + this.packageCreationService.savePackage(blob).subscribe( bluePrintDetailModels => { if (bluePrintDetailModels) { const id = bluePrintDetailModels.toString().split('id')[1].split(':')[1].split('"')[1]; this.toastService.info('package updated successfully '); + this.isSaveEnabled = false; this.router.navigate(['/packages/package/' + id]); } }, error => { @@ -150,4 +162,12 @@ export class PackageCreationComponent implements OnInit { this.metadataTabComponent.saveMetaDataToStore(); } + + canDeactivate(): boolean { + return this.isSaveEnabled; + } + + ngOnDestroy(): void { + + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts index e7ccbb39a..ed3db4286 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts @@ -21,28 +21,46 @@ limitations under the License. import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; +import {Observable, Subject} from 'rxjs'; import {ApiService} from '../../../../common/core/services/api.service'; import {BlueprintURLs, ResourceDictionaryURLs} from '../../../../common/constants/app-constants'; import {PackagesApiService} from '../packages-api.service'; import {PackagesStore} from '../packages.store'; import {ResourceDictionary} from './mapping-models/ResourceDictionary.model'; +import {FilesContent, FolderNodeElement} from './mapping-models/metadata/MetaDataTab.model'; +import {PackageCreationModes} from './creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from './creationModes/PackageCreationBuilder'; +import {PackageCreationStore} from './package-creation.store'; +import {CBAPackage} from './mapping-models/CBAPacakge.model'; +import {PackageCreationUtils} from './package-creation.utils'; +import * as JSZip from 'jszip'; +import {DesignerStore} from '../designer/designer.store'; @Injectable({ providedIn: 'root' }) export class PackageCreationService { - - - constructor(private api: ApiService, private packagesListService: PackagesApiService, private packagesStore: PackagesStore) { + private cbaPackage: CBAPackage; + folder: FolderNodeElement = new FolderNodeElement(); + filesData: any = []; + zipFile: JSZip = new JSZip(); + + constructor(private api: ApiService, private packagesListService: PackagesApiService, + private packagesStore: PackagesStore, private designerStore: DesignerStore, + private packageCreationStore: PackageCreationStore, private packageCreationUtils: PackageCreationUtils + ) { + this.packageCreationStore.state$.subscribe( + cbaPackage => { + this.cbaPackage = cbaPackage; + }); } - private saveBlueprint(body: any | null, options?: any): Observable<any> { + private saveBlueprint(body: any | null, options?: any): Observable<string> { return this.api.post(BlueprintURLs.save, body, {responseType: 'text'}); } private enrichBlueprint(body: any | null, options?: any): Observable<any> { - return this.api.post(BlueprintURLs.enrich, body, {responseType: 'text'}); + return this.api.post(BlueprintURLs.enrich, body, {responseType: 'blob'}); } private deployBluePrint(body: any | null, options?: any): Observable<any> { @@ -58,7 +76,7 @@ export class PackageCreationService { this.packagesStore.getAll(); } - savePackage(blob) { + public savePackage(blob): Observable<string> { const formData = this.getFormData(blob); return this.saveBlueprint(formData); } @@ -83,5 +101,69 @@ export class PackageCreationService { return this.api.post(ResourceDictionaryURLs.searchResourceDictionaryByNames, variables); } + downloadPackage(id) { + return this.api.getCustomized(BlueprintURLs.download + id, {responseType: 'blob'}); + } + + public saveBluePrintToDataBase(): Observable<string> { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.savePackage(blob).subscribe(bluePrintModel => { + subject.next(bluePrintModel); + }); + }); + return subject.asObservable(); + } + + public deployCurrentPackage() { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.deploy(blob).subscribe(bluePrintModel => { + subject.next(bluePrintModel); + }); + }); + return subject.asObservable(); + } + + public enrichCurrentPackage() { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + return this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + return this.enrichPackage(blob).pipe(); + }); + // return subject.asObservable(); + + } + + private create() { + this.zipFile = new JSZip(); + FilesContent.getMapOfFilesNamesAndContent().forEach((value, key) => { + this.zipFile.folder(key.split('/')[0]); + this.zipFile.file(key, value); + }); + + } + + private formTreeData() { + + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + this.designerStore.state$.subscribe(state => { + this.cbaPackage.templateTopology.content = this.packageCreationUtils.transformToJson(state.template); + }); + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts index b60831238..77867e55e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts @@ -24,11 +24,7 @@ import {Injectable} from '@angular/core'; import {Store} from '../../../../common/core/stores/Store'; import {CBAPackage, DslDefinition} from './mapping-models/CBAPacakge.model'; -import {PackageCreationService} from './package-creation.service'; import {MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; -import {Observable} from 'rxjs'; -import {ResourceDictionary} from './mapping-models/ResourceDictionary.model'; -import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; import {TemplateTopology} from './mapping-models/definitions/VlbDefinition'; @@ -38,7 +34,7 @@ import {TemplateTopology} from './mapping-models/definitions/VlbDefinition'; export class PackageCreationStore extends Store<CBAPackage> { - constructor(private packageCreationService: PackageCreationService) { + constructor() { super(new CBAPackage()); } @@ -98,17 +94,6 @@ export class PackageCreationStore extends Store<CBAPackage> { this.state.definitions.imports.delete(filename); } - saveBluePrint(blob): Observable<BluePrintDetailModel> { - return this.packageCreationService.savePackage(blob); - } - - enrichBluePrint(blob): Observable<any> { - return this.packageCreationService.enrichPackage(blob); - } - - deployBluePrint(blob): Observable<BluePrintDetailModel> { - return this.packageCreationService.deploy(blob); - } addTemplate(filePath: string, fileContent: string) { this.setState({ @@ -124,12 +109,10 @@ export class PackageCreationStore extends Store<CBAPackage> { }); } - getTemplateAndMapping(variables: string[]): Observable<ResourceDictionary[]> { - return this.packageCreationService.getTemplateAndMapping(variables); - } - clear() { + console.log('clearing the store'); this.setState(new CBAPackage()); + console.log('it should be empty'); } setEntryDefinition(data: string) { @@ -142,4 +125,8 @@ export class PackageCreationStore extends Store<CBAPackage> { templateTopology }); } + + getMetaData() { + return this.state.metaData; + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts index c3704365c..2653d739c 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts @@ -24,6 +24,7 @@ export class ScriptsTabComponent implements OnInit { ngOnInit() { + this.packageCreationStore.state$.subscribe(cbaPackage => { if (cbaPackage.scripts && cbaPackage.scripts.files && cbaPackage.scripts.files.size > 0) { this.scriptsFiles = cbaPackage.scripts.files; diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts index 57c2bcbfa..47128130c 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts @@ -10,11 +10,17 @@ export class SharedService { // based on edit Mode, edit=false mode = new BehaviorSubject(false); list = new BehaviorSubject(''); + modeState: Observable<boolean>; + listState: Observable<string>; constructor() { + this.mode = new BehaviorSubject(false); + this.list = new BehaviorSubject(''); + this.modeState = this.mode.asObservable(); + this.listState = this.list.asObservable(); } isEdit(): Observable<boolean> { - return this.mode.asObservable(); + return this.modeState; } enableEdit() { this.mode.next(true); @@ -28,7 +34,7 @@ export class SharedService { this.list.next(filename); } listAction(): Observable<string> { - return this.list.asObservable(); + return this.listState; } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts deleted file mode 100644 index 17a4bfae6..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum TemplateType { - Velocity = 'vtl', - Koltin = 'kt', - Jinja = 'Unknown' -} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html index 4b0ef8b49..de97a4679 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html @@ -5,12 +5,14 @@ class="fa fa-chevron-left mr-2"></i>Template List</button> </div> <div class="col text-right"> + <button (click)="cancel()" [hidden]="!templatesExist || edit" class="btn btn-outline-danger" + title="Delete Template">Cancel</button> <button data-toggle="modal" [hidden]="!edit" data-target="#templateDeletionModal2" class="btn btn-outline-danger" title="Delete Template">Delete</button> - <button (click)="cancel()" [hidden]="fileName?.length <=0 || edit" + <button (click)="clear()" [hidden]="fileName?.length <=0 || edit" class="btn btn-outline-secondary">Clear</button> - <button tourAnchor="tm-templateFinish" (click)="saveToStore()" [disabled]="fileName?.length <=0" title="Submit template and close" - class="btn btn-primary">Finish</button> + <button tourAnchor="tm-templateFinish" (click)="saveToStore()" [disabled]="fileName?.length <=0" + title="Submit template and close" class="btn btn-primary">Finish</button> </div> </div> <div class="card creat-card"> @@ -31,8 +33,8 @@ <div class="card"> <div class="card-header" id="headingOne"> <h5 class="mb-0 d-flex justify-content-between"> - <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" - aria-controls="collapseOne"> + <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" id="templateTab" + aria-expanded="true" aria-controls="collapseOne"> 1. Template <span class="accordian-title">{{currentTemplate?.fileName?.split('/')[1]}}</span> </button> @@ -44,24 +46,25 @@ <div tourAnchor="tm-templateType" class="single-line"> <label class="label-name">Template Type</label> <div class="label-input"> - <label name="trst" (click)="allowedExt=['.vtl']"> + <label name="trst" (click)="allowedExt=['.vtl'];templateExt='vtl'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Velcoity> + name="exampleRadios" id="exampleRadios1" value=vtl> <span> - Velcoity + Velocity </span> </label> - <label name="trst" (click)="allowedExt=['.j2','.jinja2']"> + <label name="trst" (click)="allowedExt=['.j2','.jinja2'];templateExt='j2'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Jinja> + name="exampleRadios" id="exampleRadios1" value=j2> <span> Jinja </span> </label> - <label tourAnchor="tm-templateContent" name="trst" (click)="allowedExt=['.kt']"> + <label tourAnchor="tm-templateContent" name="trst" + (click)="allowedExt=['.kt'];templateExt='kt'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Kotlin> + name="exampleRadios" id="exampleRadios1" value=kt> <span> Kotlin @@ -70,7 +73,7 @@ </div> </div> <div class="create-template-import">Use the editor to add parameters or you can also - <a href="#" data-toggle="modal" (click)="allowedExt=[getFileExtension()]" + <a href="#" data-toggle="modal" (click)="allowedExt=['.'+templateExt]" data-target="#templateModal"><b>Import File</b></a>. <br /> <span class="templateNote"><i class="icon-info" aria-hidden="true"></i> When you import new file, the new attributes will replace @@ -86,8 +89,9 @@ <div class="card"> <div class="card-header" id="headingTwo"> <h5 class="mb-0"> - <button tourAnchor="tm-mappingContent" class="btn btn-link collapsed" id="mappingTab" data-toggle="collapse" - data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> + <button tourAnchor="tm-mappingContent" class="btn btn-link collapsed" id="mappingTab" + data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" + aria-controls="collapseTwo"> 2. Manage Mapping <span class="accordian-title">{{currentMapping?.fileName?.split('/')[1]}}</span> </button> @@ -97,8 +101,8 @@ <div class="card-body"> <p class="text-center"><b>Select a source to load config parameters</b></p> <div class="text-center"> - <button [disabled]="!(variables?.length>0 && templateFileContent?.trim()?.length > 0)" - (click)="getMappingTableFromTemplate($event)" class="mapping-source-load" [ngClass]="variables?.length>0 && templateFileContent?.trim()?.length > 0 + <button [disabled]="!(templateFileContent?.trim()?.length > 0)" + (click)="getMappingTableFromTemplate($event)" class="mapping-source-load" [ngClass]="templateFileContent?.trim()?.length > 0 ?'hover-enable':'hover-disable'"> <i class="icon-use-attributes"></i> <br /> @@ -122,28 +126,68 @@ </div> + </div> + <div id="mapping-table" [hidden]="resourceDictionaryRes?.length == 0" class="mapping-table mx-4 my-2"> + <div class="btn-group mapping-editBar" role="group"> + <div class="custom-control custom-checkbox" tooltip="Select All" placement="bottom"> + <input type="checkbox" (click)="selectAllProps()" class="custom-control-input" + id="customCheck1" + [checked]="resourceDictionaryRes.length>0&&resourceDictionaryRes.length === this.selectedProps.size"> + <label class="custom-control-label" for="customCheck1"></label> + </div> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="reMap()" + tooltip="Re-mapping" placement="bottom"><i class="icon-autoMap"></i></button> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="removeProps()" + tooltip="Remove" placement="bottom"><i class="icon-delete-sm"></i></button> + <div style="line-height: 35px;font-size: 10px;"> + <span>{{selectedProps.size}} selected </span> + <span>({{resourceDictionaryRes.length}} attributes in total)</span> + </div> + </div> <table datatable [dtOptions]="initDtOptions" [dtTrigger]="dtTrigger" class="row-border hover"> <thead> <tr> + <th></th> <th>Required</th> + <th>Template Input</th> <th>Parameter Name</th> <th>Dictionary Name</th> <th>Dictionary Source</th> <th>Dependancies</th> <th>Default</th> + <th>Velocity</th> <th>Data Type</th> <th>Entry Schema</th> </tr> </thead> <tbody> - <tr *ngFor="let dict of resourceDictionaryRes"> + <tr *ngFor="let dict of resourceDictionaryRes;let i=index;trackBy: identify"> + <td> + <div class="custom-control custom-checkbox" tooltip="Select" placement="bottom"> + <input type="checkbox" class="custom-control-input" + id="customCheck-{{dict.name}}" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"> + <label class="custom-control-label" for="customCheck-{{dict.name}}"></label> + </div> + <!-- <input type="checkbox" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"></td> --> + </td> <td> - <img *ngIf="dict.definition?.property?.required" - src="/assets/img/icon-required-yes.svg"> - <img *ngIf="!dict.definition?.property?.required" - src="/assets/img/icon-required-no.svg"> + <div class="custom-control custom-checkbox reuiredInput"> + <input type="checkbox" class="custom-control-input" #requiredInput + (click)="setProp(requiredInput,'required',i)" + id="requiredCheck-{{dict.name}}"> + <label class="custom-control-label" for="requiredCheck-{{dict.name}}"></label> + </div> + </td> + <td> + <div class="custom-control custom-checkbox reuiredInput"> + <input type="checkbox" class="custom-control-input" #tempInput + (click)="setProp(tempInput,'input-param',i)" id="inputCheck-{{dict.name}}"> + <label class="custom-control-label" for="inputCheck-{{dict.name}}"></label> + </div> </td> <td>{{ dict.name }}</td> <td>{{ dict.name }}</td> @@ -159,12 +203,13 @@ <!-- <select class="custom-select"> <option *ngFor="let val of getKeys(dependancies)"> {{ getValue(dict.name)}}</option> - </select> --> <input type="text" class="form-control" [ngModel]="getValue(dict.name)"> <!-- {{ dict.definition.sources }} --> </td> <td>{{ dict.definition?.property?.default }}</td> + <td><input type="text" class="form-control" #velocity + (input)="setVelocity(i,velocity.value)"></td> <td>{{ dict.definition?.property?.type }}</td> <td>{{ dict.definition?.property['entry_schema'] }}</td> </tr> @@ -173,26 +218,51 @@ </div> <div id="mapping-table-res" [hidden]="mappingRes?.length == 0" class="mapping-table mx-4 my-2"> + <!-- <div class="btn-group mapping-editBar" role="group"> + <div class="custom-control custom-checkbox" tooltip="Select All" placement="bottom"> + <input type="checkbox" (click)="selectAllProps()" class="custom-control-input" + id="customCheck2" + [checked]="resourceDictionaryRes.length>0&&resourceDictionaryRes.length === this.selectedProps.size"> + <label class="custom-control-label" for="customCheck2"></label> + </div> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="reMap()" + tooltip="Re-mapping" placement="bottom"><i class="icon-autoMap"></i></button> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="removeProps()" + tooltip="Remove" placement="bottom"><i class="icon-delete-sm"></i></button> + </div> --> <table datatable [dtOptions]="dtOptions" [dtTrigger]="resTableDtTrigger" class="row-border hover"> <thead> <tr> + <!-- <th></th> --> <th>Required</th> + <th>Template Input</th> <th>Parameter Name</th> <th>Dictionary Name</th> <th>Dictionary Source</th> <th>Dependancies</th> <th>Default</th> + <th>Velocity</th> <th>Data Type</th> <th>Entry Schema</th> </tr> </thead> <tbody> <tr *ngFor="let dict of mappingRes"> + <!-- <td> + <div class="custom-control custom-checkbox" tooltip="Select" placement="bottom"> + <input type="checkbox" class="custom-control-input" + id="customCheck2-{{dict.name}}" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"> + <label class="custom-control-label" for="customCheck2-{{dict.name}}"></label> + </div> + </td> --> <td> - <img *ngIf="dict.definition?.property?.required" - src="/assets/img/icon-required-yes.svg"> - <img *ngIf="!dict.definition?.property?.required" - src="/assets/img/icon-required-no.svg"> + <img *ngIf="dict?.property?.required" src="/assets/img/icon-required-yes.svg"> + <img *ngIf="!dict?.property?.required" src="/assets/img/icon-required-no.svg"> + </td> + <td> + <img *ngIf="dict['input-param']" src="/assets/img/icon-required-yes.svg"> + <img *ngIf="!dict['input-param']" src="/assets/img/icon-required-no.svg"> </td> <td>{{ dict['name'] }}</td> <td>{{ dict['name'] }}</td> @@ -206,6 +276,10 @@ <!-- {{ dict.definition.sources }} --> </td> <td>{{ dict['property']['default'] }}</td> + <td *ngIf="dict?.property?.metadata"> + {{dict?.property?.metadata['transform-template']}} + </td> + <td *ngIf="!dict?.property?.metadata"></td> <td>{{ dict['property']['type'] }}</td> <td>{{ dict['property']['entry_schema'] }}</td> </tr> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts index 3e7cfea7b..56ed0422a 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts @@ -10,8 +10,11 @@ import { PackageCreationUtils } from '../../package-creation.utils'; import { JsonConvert, Any } from 'json2typescript'; import { ToastrService } from 'ngx-toastr'; import { SharedService } from '../shared-service'; -import { XmlParser } from '../utils/XmlParser'; +import { XmlParser } from '../utils/ParserFactory/XmlParser'; import { TourService } from 'ngx-tour-md-menu'; +import { PackageCreationService } from '../../package-creation.service'; +import { ParserFactory } from '../utils/ParserFactory/ParserFactory'; +import { TemplateType, FileExtension } from '../utils/TemplateType'; declare var $: any; @Component({ @@ -42,14 +45,17 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { MappingAdapter: MappingAdapter; mapping = new Map(); templateFileContent: string; - templateExt = 'Velcoity'; + templateExt = 'vtl'; dependancies = new Map<string, Array<string>>(); dependanciesSource = new Map<string, string>(); mappingRes = []; currentTemplate: any; currentMapping: any; edit = false; + templatesExist = false; fileToDelete: any = {}; + parserFactory: ParserFactory; + selectedProps: Set<string>; constructor( private packageCreationStore: PackageCreationStore, @@ -57,11 +63,14 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { private packageCreationUtils: PackageCreationUtils, private toastr: ToastrService, private sharedService: SharedService, + private packageCreationService: PackageCreationService, private tourService: TourService, ) { } ngOnInit() { + this.selectedProps = new Set<string>(); + this.parserFactory = new ParserFactory(); this.templateStore.state$.subscribe(templateInfo => { // init Template&mapping vars console.log('Oninit'); @@ -70,7 +79,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.fileToDelete = templateInfo.fileName; this.fileName = templateInfo.fileName.split('/')[1]; if (this.fileName) { - this.fileName = this.fileName.split('-')[0]; + this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('-')); } if (templateInfo.type === 'mapping' || templateInfo.type.includes('mapping')) { this.mappingRes = templateInfo.mapping; @@ -80,20 +89,27 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } else { this.mappingRes = []; this.currentMapping = Any; + this.resourceDictionaryRes = []; } this.templateFileContent = templateInfo.fileContent; + this.templateExt = this.templateInfo.ext || this.templateExt; this.currentTemplate = Object.assign({}, templateInfo); if (templateInfo.type === 'template' || templateInfo.type.includes('template')) { - this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.vtl'; + console.log('template extension ' + this.templateExt); + this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.' + this.templateExt; + console.log(this.currentTemplate.fileName); } else { this.currentTemplate = Any; } }); + this.sharedService.isEdit().subscribe(res => { - console.log('------------------------'); + console.log('------------------------....'); + this.templatesExist = this.packageCreationStore.state.templates.files.size > 0 + || this.packageCreationStore.state.mapping.files.size > 0; console.log(res); this.edit = res; @@ -113,6 +129,14 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { pageLength: 25, destroy: true, retrieve: true, + columnDefs: [ + { + targets: [0, 1, 2], // column or columns numbers + orderable: false, // set orderable for selected columns + searchable: false, + }, + + ], }; this.dtOptions = { pagingType: 'full_numbers', @@ -122,13 +146,79 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { }; } + setProp(e, propName, index) { + this.resourceDictionaryRes[index][propName] = e.checked; + console.log(this.resourceDictionaryRes[index]); + } + selectProp(value) { + console.log(value); + if (this.selectedProps.has(value)) { + this.selectedProps.delete(value); + } else { + this.selectedProps.add(value); + } + } + + removeProps() { + console.log(this.selectedProps); + this.selectedProps.forEach(prop => { + this.resourceDictionaryRes.forEach((res, index) => { + if (res.name === prop) { + console.log('delete...'); + this.resourceDictionaryRes.splice(index, 1); + this.selectedProps.delete(prop); + } + }); + }); + } + selectAllProps() { + if (this.resourceDictionaryRes.length === this.selectedProps.size) { + this.selectedProps = new Set<string>(); + } else { + this.resourceDictionaryRes.forEach(prop => { + console.log(prop); + this.selectedProps.add(prop.name); + }); + } + + } + reMap() { + let currentResDictionary = []; + if (this.selectedProps && this.selectedProps.size > 0) { + console.log('base'); + this.packageCreationService.getTemplateAndMapping([...this.selectedProps]).subscribe(res => { + let message = 'Re-Auto mapping'; + this.mappingRes = []; + currentResDictionary = res; + console.log(currentResDictionary); + if (currentResDictionary && currentResDictionary.length <= 0) { + message = 'No values for those attributes'; + } + + // Replcae new values with the old ones + currentResDictionary.forEach(curr => { + for (let i = 0; i < this.resourceDictionaryRes.length; i++) { + if (this.resourceDictionaryRes[i].name === curr.name) { + this.resourceDictionaryRes[i] = curr; + } + } + }); + this.rerender(); + this.toastr.success(message, 'Success'); + }, err => { + this.toastr.error('Error'); + }); + } + + } + getFileExtension() { switch (this.templateExt) { - case 'Velcoity': + case 'vtl': return '.vtl'; - case 'Koltin': + case 'kt': return '.ktl'; - case 'Jinja': + case 'j2': return '.j2'; default: return '.vtl'; @@ -141,34 +231,10 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } public getTemplateVariable(fileContent: string) { - const variables: string[] = []; - const stringsSlittedByBraces = fileContent.split('${'); - const stringsDefaultByDollarSignOnly = fileContent.split('"$'); - - for (let i = 1; i < stringsSlittedByBraces.length; i++) { - const element = stringsSlittedByBraces[i]; - if (element) { - const firstElement = element.split('}')[0]; - if (!variables.includes(firstElement)) { - variables.push(firstElement); - } else { - console.log(firstElement); - } - } - } - - for (let i = 1; i < stringsDefaultByDollarSignOnly.length; i++) { - const element = stringsDefaultByDollarSignOnly[i]; - if (element && !element.includes('$')) { - const firstElement = element.split('"')[0] - .replace('{', '') - .replace('}', '').trim(); - if (!variables.includes(firstElement)) { - variables.push(firstElement); - } - } - } - return variables; + // TODO: implement factory Pattern for parser + console.log('start parsing........ ' + this.templateExt); + const parser = this.parserFactory.getParser(fileContent, this.templateExt); + return parser.getVariables(fileContent); } public dropped(files: NgxFileDropEntry[]) { @@ -224,7 +290,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { const parser = new XmlParser(); this.variables = parser.getVariables(fileReader.result.toString()); } - console.log(this.variables); + console.log('variables = ' + this.variables); this.getMappingTableFromTemplate(null); }; @@ -250,7 +316,8 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { const fileReader = new FileReader(); fileReader.onload = (e) => { this.templateFileContent = fileReader.result.toString(); - this.variables = this.getTemplateVariable(this.templateFileContent); + // this.variables = this.getTemplateVariable(this.templateFileContent); + // console.log(this.variables); }; fileReader.readAsText(file); @@ -286,15 +353,30 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.showCreationView.emit('close create form and open list'); } + identify(index, item) { + return item.name; + } + setVelocity(index, value) { + // console.log('velocity value = ' + value); + // console.log(this.resourceDictionaryRes[index]); + // tslint:disable-next-line: no-string-literal + this.resourceDictionaryRes[index].definition.property['metadata'] = { + 'transform-template': value + }; + console.log(this.resourceDictionaryRes[index]); + } + getMappingTableFromTemplate(e) { console.log('-' + this.templateFileContent + '-'); this.resourceDictionaryRes = []; if (e) { e.preventDefault(); } + this.variables = this.getTemplateVariable(this.templateFileContent); + console.log('variables = ' + this.variables); if (this.variables && this.variables.length > 0) { console.log('base'); - this.packageCreationStore.getTemplateAndMapping(this.variables).subscribe(res => { + this.packageCreationService.getTemplateAndMapping(this.variables).subscribe(res => { let message = 'Attributes are Fetched'; this.mappingRes = []; this.resourceDictionaryRes = res; @@ -307,6 +389,8 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { }, err => { this.toastr.error('Error'); }); + } else { + this.toastr.error('Empty or Invalid file format. Validate your file first'); } } @@ -316,7 +400,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } return map.key; } - cancel() { + clear() { this.fileName = ''; this.templateFileContent = ''; this.resourceDictionaryRes = []; @@ -325,6 +409,9 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.currentTemplate = {}; // this.closeCreationForm(); } + cancel() { + this.openListView(); + } saveToStore() { if (this.fileName) { // check file duplication @@ -350,8 +437,9 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.fileName = ''; this.toastr.success('File is created', 'success'); this.openListView(); - console.log(this.tourService.getStatus()); - this.tourService.goto('tm-templateEdit'); + if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') { + this.tourService.goto('tm-templateEdit'); + } } else { console.log('this file already exist'); this.toastr.error('File name already exist', 'Error'); @@ -392,24 +480,13 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { rerender(): void { this.dtTrigger.next(); - - // if (this.dtElement.dtInstance) { - // console.log('rerender'); - // this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => { - // dtInstance.destroy(); - // this.dtElement.dtOptions = this.dtOptions; - // this.dtElement.dtTrigger.next(); - // dtInstance.draw(); - // }); - // } else { - // this.dtTrigger.next(); - // } } ngOnDestroy(): void { // Do not forget to unsubscribe the event this.dtTrigger.unsubscribe(); this.resTableDtTrigger.unsubscribe(); + // this.templateStore.unsubscribe(); } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts index 70e35939b..3a05bcfc5 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { PackageCreationStore } from '../../package-creation.store'; import { Mapping, Template } from '../../mapping-models/CBAPacakge.model'; import { TemplateInfo, TemplateStore } from '../../template.store'; @@ -6,6 +6,7 @@ import { TemplateAndMapping } from '../TemplateAndMapping'; import { ActivatedRoute } from '@angular/router'; import { SharedService } from '../shared-service'; import { TourService } from 'ngx-tour-md-menu'; +import { TemplateType } from '../utils/TemplateType'; @Component({ @@ -13,7 +14,7 @@ import { TourService } from 'ngx-tour-md-menu'; templateUrl: './templ-mapp-listing.component.html', styleUrls: ['./templ-mapp-listing.component.css'] }) -export class TemplMappListingComponent implements OnInit { +export class TemplMappListingComponent implements OnInit, OnDestroy { @Output() showCreationView = new EventEmitter<any>(); @Output() showListView = new EventEmitter<any>(); templateAndMappingMap = new Map<string, TemplateAndMapping>(); @@ -22,7 +23,7 @@ export class TemplMappListingComponent implements OnInit { isCreate = true; currentFile: string; edit = false; - fileToDelete: any = {}; + fileToDelete = ''; constructor( private packageCreationStore: PackageCreationStore, @@ -30,11 +31,17 @@ export class TemplMappListingComponent implements OnInit { private route: ActivatedRoute, private sharedService: SharedService, private tourService: TourService, - ) { } + ngOnDestroy(): void { + // this.templateStore.unsubscribe(); + // this.packageCreationStore.unsubscribe(); + } + ngOnInit() { + this.templateAndMappingMap = new Map<string, TemplateAndMapping>(); + this.edit = false; if (this.route.snapshot.paramMap.has('id')) { this.isCreate = false; this.sharedService.isEdit().subscribe(res => { @@ -73,7 +80,9 @@ export class TemplMappListingComponent implements OnInit { } private setIsMappingOrTemplate(key: string, templateAndMapping: TemplateAndMapping, isFromTemplate: boolean) { - const nameOfFile = key.split('/')[1].split('.')[0].split('-')[0]; + const nameOfFile = isFromTemplate ? + key.split('/')[1].split('.')[0].split('-template')[0] + : key.split('/')[1].split('.')[0].split('-mapping')[0]; // const fullName = nameOfFile + ',' + key.split('.'); if (this.templateAndMappingMap.has(nameOfFile)) { const templateAndMappingExisted = this.templateAndMappingMap.get(nameOfFile); @@ -102,12 +111,16 @@ export class TemplMappListingComponent implements OnInit { createNewTemplate() { this.openCreationView(); this.sharedService.disableEdit(); - this.tourService.goto('tm-templateName'); + if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') { + this.tourService.goto('tm-templateName'); + } } + openCreationView() { this.showCreationView.emit('tell parent to open create views'); console.log('disable edit mode'); } + openListView() { console.log('open list view'); this.showListView.emit('show full view'); @@ -115,19 +128,25 @@ export class TemplMappListingComponent implements OnInit { setSourceCodeEditor(key: string) { this.currentFile = key; - const templateKey = 'Templates/' + key + '-template.vtl'; + const templateKey = 'Templates/' + key + '-template'; this.packageCreationStore.state$.subscribe(cba => { console.log('cba ------'); console.log(cba); console.log(key); console.log(this.templateAndMappingMap); const templateInfo = new TemplateInfo(); - if (cba.templates && cba.templates.files.has(templateKey)) { - const fileContent = cba.templates.getValue(templateKey.trim()); - console.log(fileContent); - templateInfo.fileContent = fileContent; - templateInfo.fileName = templateKey; - templateInfo.type = 'template'; + // tslint:disable-next-line: forin + for (const templateType in TemplateType) { + const fileName = templateKey + '.' + TemplateType[templateType]; + if (cba.templates && cba.templates.files.has(fileName)) { + const fileContent = cba.templates.getValue(fileName.trim()); + console.log(templateType + '......ccccccc.... ' + fileName); + templateInfo.fileContent = fileContent; + templateInfo.fileName = fileName; + templateInfo.ext = TemplateType[templateType]; + templateInfo.type = 'template'; + break; + } } const mappingKey = 'Templates/' + key + '-mapping.json'; if (cba.mapping && cba.mapping.files.has(mappingKey)) { @@ -138,7 +157,9 @@ export class TemplMappListingComponent implements OnInit { } this.templateStore.changeTemplateInfo(templateInfo); this.openCreationView(); - this.sharedService.enableEdit(); + if (templateInfo.fileName && templateInfo.fileName.length > 0) { + this.sharedService.enableEdit(); + } }); } @@ -149,20 +170,34 @@ export class TemplMappListingComponent implements OnInit { getValue(file: string) { return this.templateAndMappingMap.get(file); } + initDelete(file) { console.log(file); - this.fileToDelete = file; + const templateKey = 'Templates/' + file + '-template'; + // tslint:disable-next-line: forin + for (const templateType in TemplateType) { + const fileName = templateKey + '.' + TemplateType[templateType]; + if (this.packageCreationStore.state.templates.files.has(fileName)) { + this.fileToDelete = fileName; + break; + } + } + } + condifrmDelete() { - console.log(this.templateAndMappingMap); - this.templateAndMappingMap.delete(this.fileToDelete); + const fullName = this.fileToDelete.split('/')[1]; + const file = fullName.substr(0, fullName.lastIndexOf('-')); + const ext = fullName.substr(fullName.lastIndexOf('.') + 1); + this.templateAndMappingMap.delete(file); if (this.templateAndMappingMap.size <= 0) { this.openCreationView(); } // Delete from templates - this.packageCreationStore.state.templates.files.delete('Templates/' + this.fileToDelete + '-template.vtl'); + this.packageCreationStore.state.templates.files.delete('Templates/' + file + '-template.' + ext); // Delete from Mapping - this.packageCreationStore.state.mapping.files.delete('Templates/' + this.fileToDelete + '-mapping.json'); + this.packageCreationStore.state.mapping.files.delete('Templates/' + file + '-mapping.json'); + console.log(this.templateAndMappingMap); } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts index 341d29f66..15361b8ad 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { PackageCreationStore } from '../package-creation.store'; import { SharedService } from './shared-service'; @@ -8,7 +8,7 @@ import { SharedService } from './shared-service'; templateUrl: './template-mapping.component.html', styleUrls: ['./template-mapping.component.css'] }) -export class TemplateMappingComponent implements OnInit { +export class TemplateMappingComponent implements OnInit, OnDestroy { creationView = false; listView = true; @@ -18,6 +18,11 @@ export class TemplateMappingComponent implements OnInit { private sharedService: SharedService ) { } + ngOnDestroy(): void { + // this.sharedService.list.unsubscribe(); + // this.sharedService.mode.unsubscribe(); + // this.pakcageStore.unsubscribe(); + } ngOnInit() { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts deleted file mode 100644 index e90377e0c..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { XmlParser } from './XmlParser'; - -fdescribe('ImportsTabComponent', () => { - const parser: XmlParser = new XmlParser(); - - - beforeEach(() => { - }); - - it('Test xml Parser', () => { - const fileContent = `<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> - <vdns-instances> - <vdns-instance> - <ip-addr>$vdns_int_private_ip_0</ip-addr> - <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> - <enabled>false</enabled> - <tag>dddd</tag> - </vdns-instance> - </vdns-instances> - </vlb-business-vnf-onap-plugin>`; - - const res = parser.getVariables(fileContent); - console.log(res); - expect(res.length).toEqual(2); - expect(res[0]).toEqual('vdns_int_private_ip_0'); - expect(res[1]).toEqual('vdns_onap_private_ip_0'); - }); -}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts new file mode 100644 index 000000000..c9e0a1891 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts @@ -0,0 +1,19 @@ +import { Parser } from './Parser'; + +export class ASCIIParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('$(')) { + const xmlSplit = fileContent.split('$('); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf(')')); + if (res && res.length > 0) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts new file mode 100644 index 000000000..cb1359aa0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts @@ -0,0 +1,31 @@ +import { Parser } from './Parser'; + +export class JinjaXMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('>[')) { + const xmlSplit = fileContent.split('>['); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf(']</')); + if (res && res.length > 0) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} + +/* + +<?xml version="1.0" encoding="UTF-8"?> +<configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> +<system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> +<host-name operation="delete" /> +<host-name operation="create">[hostname]</host-name> +</system> +</configuration> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts new file mode 100644 index 000000000..6ecee9070 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts @@ -0,0 +1,43 @@ +import { Parser } from './Parser'; + +export class JinjaYMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('{{')) { + // '[{]+[ ]*.[V-v]alues.' old regex + const xmlSplit = fileContent.split(new RegExp('[{]+[ ]*.')); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf('}}')); + if (res && res.length > 0) { + console.log(res); + if (res.includes('Value')) { + this.variables.add(this.extractValues(res.trim())); + } else { + this.variables.add(this.extractParent(res.trim()).toLowerCase()); + } + } + } + } + return [...this.variables]; + } + + extractValues(value) { + return value.split('Values.')[1]; + } + extractParent(value): string { + return value.split('.')[0]; + } + +} + +/* +vf-module-name: {{ .Values.vpg_name_0 }} +<?xml version="1.0" encoding="UTF-8"?> +<configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> +<system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> +<host-name operation="delete" /> +<host-name operation="create">[hostname]</host-name> +</system> +</configuration> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts new file mode 100644 index 000000000..3a1880c99 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts @@ -0,0 +1,153 @@ +import { XmlParser } from './XmlParser'; +import { ParserFactory } from './ParserFactory'; +import { FileExtension } from '../TemplateType'; +import { JinjaXMLParser } from './JinjaXML'; + +fdescribe('ImportsTabComponent', () => { + + const parserFactory = new ParserFactory(); + + + beforeEach(() => { + }); + + it('Test xml Parser', () => { + const fileContent = `<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> + </vlb-business-vnf-onap-plugin>`; + + const parser = parserFactory.getParser(fileContent, FileExtension.XML); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(2); + expect(res[0]).toEqual('vdns_int_private_ip_0'); + expect(res[1]).toEqual('vdns_onap_private_ip_0'); + }); + + it('Test J2 XML Parser', () => { + const fileContent = `<?xml version="1.0" encoding="UTF-8"?> + <configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> + <system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> + <host-name operation="delete" /> + <host-name operation="create">[hostname]</host-name> + </system> + </configuration>`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(typeof (res)); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('hostname'); + + }); + + it('Test J2 YML Parser', () => { + const fileContent = `apiVersion: v1 + kind: Service + metadata: + name: {{ .Values.vpg_name_0 }}-ssh + labels: + vnf-name: {{ .Values.vnf_name }} + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }} + spec: + type: NodePort + ports: + port: 22 + nodePort: \${vpg-management-port} + selector: + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }}`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(4); + expect(res[0]).toEqual('vpg_name_0'); + expect(res[1]).toEqual('vnf_name'); + + }); + + it('Test ASCII Parser', () => { + const fileContent = ` + config system interface + edit "internal" + set vdom "root" + set ip $(subnet1_fgt_ip) 255.255.255.0 #1 + set allowaccess ping https ssh http fgfm capwap + set type hard-switch + set stp enable + set role lan + next + end + config system dhcp server + edit 1 + set dns-service default + set default-gateway $(subnet1_fgt_ip) #2 + set netmask 255.255.255.0 + set interface "internal" + config ip-range + edit 1 + set start-ip $(subnet1_fgt_ip)4,150 #3 + set end-ip $(subnet1_fgt_ip)4,200 #4 + next + end + next + end + Options + `; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('subnet1_fgt_ip'); + + + }); + + + + + + it('Test Velocity YML Parser', () => { + const fileContent = `apiVersion: v1 + kind: Service + metadata: + name: {{ .Values.vpg_name_0 }}-ssh + labels: + vnf-name: {{ .Values.vnf_name }} + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }} + spec: + type: NodePort + ports: + port: 22 + nodePort: \${vpg-management-port} + selector: + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }}`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Velocity); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('vpg-management-port'); + + }); + + + +}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.ts index 495c64307..f189a84ca 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.ts @@ -1,3 +1,4 @@ export interface Parser { + variables: Set<string>; getVariables(fileContent: string): string[]; } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts new file mode 100644 index 000000000..b64afeed0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts @@ -0,0 +1,73 @@ + +import { XmlParser } from './XmlParser'; +import { Parser } from './Parser'; +import { VtlParser } from './VtlParser'; +import { FileExtension } from '../TemplateType'; +import { JinjaXMLParser } from './JinjaXML'; +import { VtlYMLParser } from './VtlYMLParser'; +import { JinjaYMLParser } from './JinjaYML'; +import { ASCIIParser } from './ASCII-Parser'; + +export class ParserFactory { + + getParser(fileContent: string, fileExtension: string): Parser { + let parser: Parser; + console.log('file extension =' + fileExtension); + + if (fileExtension === FileExtension.Velocity) { + + if (this.isXML(fileContent)) { + parser = new XmlParser(); + } else if (this.isJSON(fileContent)) { + parser = new VtlParser(); + } else if (this.isASCII(fileContent)) { + parser = new ASCIIParser(); + } else { + console.log('Velocity YML parser....'); + parser = new VtlYMLParser(); + } + + } else if (fileExtension === FileExtension.Jinja) { + + if (this.isXML(fileContent)) { + parser = new JinjaXMLParser(); + } else if (this.isJSON(fileContent)) { + // TODO: implement JSON parser + } else if (this.isASCII(fileContent)) { + parser = new ASCIIParser(); + } else { + console.log('Jinja YML parser....'); + parser = new JinjaYMLParser(); + } + + } else if (fileExtension === FileExtension.XML) { + parser = new XmlParser(); + } + return parser; + } + + private isXML(fileContent: string): boolean { + return fileContent.includes('<?xml version="1.0" encoding="UTF-8"?>'); + } + + private isJSON(fileContent: string): boolean { + try { + JSON.parse(fileContent); + } catch (e) { + return false; + } + return true; + } + + private isASCII(fileContent: string): boolean { + if ( + fileContent.includes('end') && + fileContent.includes('set') && + fileContent.includes('$(') + ) { + return true; + } + + return false; + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts new file mode 100644 index 000000000..ca80a297c --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts @@ -0,0 +1,53 @@ +import { Parser } from './Parser'; + +export class VtlParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + const variables: string[] = []; + const stringsSlittedByBraces = fileContent.split('${'); + const stringsDefaultByDollarSignOnly = fileContent.split('"$'); + + for (let i = 1; i < stringsSlittedByBraces.length; i++) { + const element = stringsSlittedByBraces[i]; + if (element) { + const firstElement = element.split('}')[0]; + if (!variables.includes(firstElement)) { + variables.push(firstElement); + } else { + console.log(firstElement); + } + } + } + + for (let i = 1; i < stringsDefaultByDollarSignOnly.length; i++) { + const element = stringsDefaultByDollarSignOnly[i]; + if (element && !element.includes('$')) { + const firstElement = element.split('"')[0] + .replace('{', '') + .replace('}', '').trim(); + if (!variables.includes(firstElement)) { + variables.push(firstElement); + } + } + } + this.variables = new Set(variables); + return [...variables]; + } + +} + +/* + +<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <tag>aaaa</tag> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> +</vlb-business-vnf-onap-plugin> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts new file mode 100644 index 000000000..6c3a0e0fd --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts @@ -0,0 +1,35 @@ +import { Parser } from './Parser'; + +export class VtlYMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('${')) { + const xmlSplit = fileContent.split('${'); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf('}')); + if (res && res.length > 0 && !res.includes('{')) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} + +/* + +<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <tag>aaaa</tag> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> +</vlb-business-vnf-onap-plugin> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/XmlParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/XmlParser.ts index 4feb7032a..69bc8b627 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/XmlParser.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/XmlParser.ts @@ -1,18 +1,17 @@ import { Parser } from './Parser'; -import { variable } from '@angular/compiler/src/output/output_ast'; export class XmlParser implements Parser { + variables: Set<string> = new Set(); getVariables(fileContent: string): string[] { - const variables = []; const xmlSplit = fileContent.split('$'); for (const val of xmlSplit) { const res = val.substring(0, val.indexOf('</')); if (res && res.length > 0) { - variables.push(res); + this.variables.add(res); } } - return variables; + return [...this.variables]; } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts new file mode 100644 index 000000000..04a829e8a --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts @@ -0,0 +1,13 @@ +export enum TemplateType { + Velocity = 'vtl', + Koltin = 'kt', + Jinja = 'j2', +} + +export enum FileExtension { + Velocity = 'vtl', + Koltin = 'kt', + Jinja = 'j2', + CSV = 'csv', + XML = 'xml' +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts index 9c8775514..4b12bb130 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts @@ -28,6 +28,7 @@ export class TemplateInfo { fileName: string; fileContent: string; type: string; + ext: string; mapping = []; @@ -35,6 +36,7 @@ export class TemplateInfo { this.fileName = ''; this.fileContent = ''; this.type = ''; + this.ext = ''; } |