diff options
Diffstat (limited to 'cds-ui/designer-client/src')
62 files changed, 2897 insertions, 855 deletions
diff --git a/cds-ui/designer-client/src/app/common/constants/app-constants.ts b/cds-ui/designer-client/src/app/common/constants/app-constants.ts index 387c35342..14cb001c8 100644 --- a/cds-ui/designer-client/src/app/common/constants/app-constants.ts +++ b/cds-ui/designer-client/src/app/common/constants/app-constants.ts @@ -106,6 +106,7 @@ export const ResourceDictionaryURLs = { saveResourceDictionary: '/resourcedictionary/save', searchResourceDictionaryByTags: '/resourcedictionary/search', searchResourceDictionaryByName: '', + searchResourceDictionaryByNames: '/resourcedictionary/search/by-names', getSources: '/resourcedictionary/source-mapping', getModelType: '/resourcedictionary/model-type', getResourceDictionary: '/resourcedictionary/model-type/by-definition' @@ -117,3 +118,6 @@ export const ControllerCatalogURLs = { getDefinition: '/controllercatalog/model-type/by-definition', getDerivedFrom: '/controllercatalog/model-type/by-derivedfrom' }; + + +export const ActionElementTypeName = 'app.ActionElement'; diff --git a/cds-ui/designer-client/src/app/common/core/services/api.typed.service.ts b/cds-ui/designer-client/src/app/common/core/services/api.typed.service.ts index 9c9477f33..d4851ded5 100644 --- a/cds-ui/designer-client/src/app/common/core/services/api.typed.service.ts +++ b/cds-ui/designer-client/src/app/common/core/services/api.typed.service.ts @@ -22,9 +22,9 @@ limitations under the License. ============LICENSE_END============================================ */ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpHeaders, HttpResponse, HttpHeaderResponse, HttpParams } from '@angular/common/http'; -import { Observable, of } from 'rxjs'; +import {Injectable} from '@angular/core'; +import {HttpClient, HttpParams} from '@angular/common/http'; +import {Observable} from 'rxjs'; @Injectable() export class ApiService<T> { @@ -60,4 +60,8 @@ export class ApiService<T> { const options = {params: httpParams}; return this.httpClient.get<T>(url, options); } + + getCustomized(url: string, params?: any): Observable<any> { + return this.httpClient.get(url, params); + } } diff --git a/cds-ui/designer-client/src/app/common/core/stores/Store.ts b/cds-ui/designer-client/src/app/common/core/stores/Store.ts index 1d5b0afc1..0be804270 100644 --- a/cds-ui/designer-client/src/app/common/core/stores/Store.ts +++ b/cds-ui/designer-client/src/app/common/core/stores/Store.ts @@ -1,4 +1,4 @@ -import {Observable, BehaviorSubject} from 'rxjs'; +import { Observable, BehaviorSubject } from 'rxjs'; import { Injectable } from '@angular/core'; export class Store<T> { @@ -19,4 +19,8 @@ export class Store<T> { this.subject.next(nextState); } + public unsubscribe() { + this.subject.unsubscribe(); + } + } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.html index 804aad057..df1911a7d 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.html @@ -1,7 +1,133 @@ -<app-header> -</app-header> -<p>package-viewing works! +<app-header></app-header> +<div class="new-wrapper"> + <div class="container-fluid main-container"> + <header class="page-title"> + <div class="row"> + <h2 class="col m-0"> + <ul class="breadcrumb-header"> + <li><a routerLink="/packages">CBA Packages</a></li> + <li>Package Name</li> + </ul> + </h2> + <div class="col d-flex justify-content-end header-button-save"> + <button class="float btn btn-sm btn-outline-secondary" (click)="goBacktoDashboard()">Discard + Changes</button> + <button class="float btn btn-sm btn-primary" (click)="editBluePrint()">Apply Changes</button> + </div> + </div> + </header> - {{viewedPackage!.artifactName}}} -</p> + + + <div class="container-fluid body-container"> + + <div class="container"> + <!-- <div class="creat-action-container"> + <a href="#" class="action-button"> + <i class="icon-clone" aria-hidden="true"></i> + <span>Clone</span> + </a> + + <a href="#" class="action-button"> + <i class="icon-archive" aria-hidden="true"></i> + <span>Archive</span> + </a> + + <a href="#" class="action-button delete"> + <i class="icon-delete" aria-hidden="true"></i> + <span>Delete</span> + </a> + </div>--> + + <div class="card creat-card view-package-container"> + <div class="row"> + <div class="col-8"> + <div class="row"> + <div class="col d-flex"> + <i class="package-type-icon icon-designer-mode"></i> + <div class="package-name-container"> + <div class="row"> + <div class="col-12 package-name deployed"> + {{viewedPackage.artifactName}} + <span>.vLB.CDS</span> + <i class="icon-deploy"></i> + </div> + <div class="col-12 package-description"> + Last modified {{ viewedPackage.createdDate | date:'short' }} By + {{viewedPackage.updatedBy}} + </div> + </div> + + </div> + </div> + </div> + </div> + <div class="col-4 package-view-button"> + <button class="btn btn-sm btn-outline-secondary" (click)="deployCurrentPackage()"><i + class="fa fa-play-circle"></i> Deploy</button> + <button class="btn btn-sm btn-outline-secondary" + (click)="downloadPackage(viewedPackage.artifactName,viewedPackage.artifactVersion)"><i + class="fa"></i> Download</button> + + <button class="btn btn-sm btn-primary" (click)="goToDesignerMode()">Designer Mode</button> + </div> + </div> + + </div> + + <nav class="row"> + <!--Nav Tabs--> + <div class="col"> + <div class="nav nav-tabs " id="nav-tab" role="tablist"> + <a class="nav-item nav-link active" id="nav-metadata-tab" data-toggle="tab" + href="#nav-metadata" role="tab" aria-controls="nav-metadata" aria-selected="true" + autofocus #nameit (focusout)="saveMetaData()">METADATA</a> + <a 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 & MAPPING</a> + <a class="nav-item nav-link" id="nav-scripts-tab" data-toggle="tab" href="#nav-scripts" + role="tab" aria-controls="nav-scripts" aria-selected="false">SCRIPTS</a> + <a class="nav-item nav-link" id="nav-imports-tab" data-toggle="tab" href="#nav-imports" + role="tab" aria-controls="nav-imports" aria-selected="false">IMPORTS</a> + <a class="nav-item nav-link" id="nav-authentication-tab" data-toggle="tab" + href="#nav-authentication" role="tab" aria-controls="nav-authentication" + aria-selected="false">EXTERNAL SYSTEM AUTHENTICATION PROPERTIES</a> + </div> + </div> + + </nav> + <div class="row mt-4"> + <div class="col"> + <div class="tab-content" id="nav-tabContent"> + <div class="tab-pane fade show active" id="nav-metadata" role="tabpanel" + aria-labelledby="nav-metadata-tab"> + <app-metadata-tab></app-metadata-tab> + </div> + <div class="tab-pane fade" id="nav-template" role="tabpanel" + aria-labelledby="nav-template-tab"> + <app-template-mapping></app-template-mapping> + </div> + <div class="tab-pane fade" id="nav-scripts" role="tabpanel" + aria-labelledby="nav-scripts-tab"> + <app-scripts-tab></app-scripts-tab> + </div> + <div class="tab-pane fade" id="nav-imports" role="tabpanel" + aria-labelledby="nav-imports-tab"> + <app-imports-tab></app-imports-tab> + + </div> + <div class="tab-pane fade" id="nav-authentication" role="tabpanel" + aria-labelledby="nav-authentication-tab"> + <div class="card creat-card"> + <div class="editor-container"> + <app-dsl-definitions-tab></app-dsl-definitions-tab> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.ts index 84fdafb36..6de76f949 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.component.ts @@ -1,8 +1,18 @@ -import {Component, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; -import {PackageStore} from './package.store'; +import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; - +import {PackageCreationStore} from '../package-creation/package-creation.store'; +import {FilesContent, FolderNodeElement, MetaDataTabModel} from '../package-creation/mapping-models/metadata/MetaDataTab.model'; +import {MetadataTabComponent} from '../package-creation/metadata-tab/metadata-tab.component'; +import * as JSZip from 'jszip'; +import {ConfigurationDashboardService} from './configuration-dashboard.service'; +import {VlbDefinition} from '../package-creation/mapping-models/definitions/VlbDefinition'; +import {DslDefinition} from '../package-creation/mapping-models/CBAPacakge.model'; +import {PackageCreationUtils} from '../package-creation/package-creation.utils'; +import {PackageCreationModes} from '../package-creation/creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from '../package-creation/creationModes/PackageCreationBuilder'; +import {saveAs} from 'file-saver'; +import {DesignerStore} from '../designer/designer.store'; @Component({ selector: 'app-configuration-dashboard', @@ -11,24 +21,192 @@ import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; }) export class ConfigurationDashboardComponent implements OnInit { viewedPackage: BluePrintDetailModel = new BluePrintDetailModel(); + @ViewChild(MetadataTabComponent, {static: false}) + private metadataTabComponent: MetadataTabComponent; + + entryDefinitionKeys: string[] = ['template_tags', 'user-groups', + 'author-email', 'template_version', 'template_name', 'template_author']; + @ViewChild('nameit', {static: true}) + private elementRef: ElementRef; + + private zipFile: JSZip = new JSZip(); + private filesData: any = []; + private folder: FolderNodeElement = new FolderNodeElement(); - constructor(private route: ActivatedRoute, private configurationStore: PackageStore) { + private currentBlob = new Blob(); + + constructor(private route: ActivatedRoute, private configurationDashboardService: ConfigurationDashboardService, + private packageCreationStore: PackageCreationStore, + private packageCreationUtils: PackageCreationUtils, + private router: Router, + private designerStore: DesignerStore) { + } + ngOnInit() { + this.elementRef.nativeElement.focus(); const id = this.route.snapshot.paramMap.get('id'); - this.configurationStore.getPagedPackages(id); - this.configurationStore.state$.subscribe( - el => { - if (el && el.configuration) { - this.viewedPackage = el.configuration; + this.configurationDashboardService.getPagedPackages(id).subscribe( + (bluePrintDetailModels) => { + if (bluePrintDetailModels) { + this.viewedPackage = bluePrintDetailModels[0]; + this.downloadCBAPackage(bluePrintDetailModels); } + }); + } + + + private downloadCBAPackage(bluePrintDetailModels: BluePrintDetailModel) { + this.configurationDashboardService.downloadResource( + bluePrintDetailModels[0].artifactName + '/' + bluePrintDetailModels[0].artifactVersion).subscribe(response => { + const blob = new Blob([response], {type: 'application/octet-stream'}); + this.currentBlob = blob; + this.zipFile.loadAsync(blob).then((zip) => { + Object.keys(zip.files).forEach((filename) => { + console.log(filename); + zip.files[filename].async('string').then((fileData) => { + 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); + } else if (filename.includes('TOSCA-Metadata/')) { + const metaDataTabInfo: MetaDataTabModel = this.getMetaDataTabInfo(fileData); + // console.log(metaDataTabInfo); + this.setMetaData(metaDataTabInfo, bluePrintDetailModels[0]); + } + } + }); + }); + }); + }); + } + + private setScripts(filename: string, fileData: any) { + this.packageCreationStore.addScripts(filename, fileData); + } + + private setImports(filename: string, fileData: any) { + if (filename.includes('blueprint.json') || filename.includes('vLB_CDS.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); + // console.log(definition.topology_template.content); + if (definition.topology_template.content) { + this.designerStore.saveSourceContent(definition.topology_template.content); } - ); + } else { + this.packageCreationStore.addDefinition(filename, fileData); + } + } + private setTemplates(filename: string, fileData: any) { + this.packageCreationStore.addTemplate(filename, fileData); } - ngOnInit() { + private setMapping(fileName: string, fileData: string) { + this.packageCreationStore.addMapping(fileName, fileData); + } + + editBluePrint() { + 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(); + }); + } + + private setMetaData(metaDataObject: MetaDataTabModel, bluePrintDetailModel: BluePrintDetailModel) { + metaDataObject.description = bluePrintDetailModel.artifactDescription; + this.packageCreationStore.changeMetaData(metaDataObject); + + } + + saveMetaData() { + this.metadataTabComponent.saveMetaDataToStore(); + } + + getMetaDataTabInfo(fileData: string) { + const metaDataTabModel = new MetaDataTabModel(); + const arrayOfLines = fileData.split('\n'); + metaDataTabModel.entryFileName = arrayOfLines[3].split(':')[1]; + metaDataTabModel.name = arrayOfLines[4].split(':')[1]; + metaDataTabModel.version = arrayOfLines[5].split(':')[1]; + metaDataTabModel.mode = arrayOfLines[6].split(':')[1]; + metaDataTabModel.templateTags = new Set<string>(arrayOfLines[7].split(':')[1].split(',')); + console.log(metaDataTabModel.mode); + return metaDataTabModel; + } + saveBluePrintToDataBase() { + this.create(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.packageCreationStore.saveBluePrint(blob); + this.router.navigate(['/packages']); + }); } + + create() { + FilesContent.getMapOfFilesNamesAndContent().forEach((value, key) => { + this.zipFile.folder(key.split('/')[0]); + this.zipFile.file(key, value); + }); + + } + + goBacktoDashboard() { + this.router.navigate(['/packages']); + } + + downloadPackage(artifactName: string, artifactVersion: string) { + this.configurationDashboardService.downloadResource(artifactName + '/' + artifactVersion).subscribe(response => { + const blob = new Blob([response], {type: 'application/octet-stream'}); + saveAs(blob, artifactName + '-' + artifactVersion + '-CBA.zip'); + }); + } + + deployCurrentPackage() { + console.log('happened'); + /* this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + const formData = new FormData(); + formData.append('file', this.currentBlob); + this.configurationDashboardService.deployPost(formData) + .subscribe(data => { + }, error => { + }); + this.router.navigate(['/packages']); + }); + */ + this.router.navigate(['/packages']); + } + + goToDesignerMode() { + this.router.navigate(['/packages/designer']); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.service.ts index 51d0e9db1..164d76601 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/configuration-dashboard.service.ts @@ -9,14 +9,23 @@ import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; providedIn: 'root' }) export class ConfigurationDashboardService { - - constructor(private api: ApiService<BluePrintDetailModel>) { } - getBluePrintModel(id: string): Observable<BluePrintDetailModel> { + private getBluePrintModel(id: string): Observable<BluePrintDetailModel> { return this.api.getOne(BlueprintURLs.getOneBlueprint + '/' + id); + } + + getPagedPackages(id: string) { + return this.getBluePrintModel(id); + } + + public downloadResource(path: string) { + return this.api.getCustomized(BlueprintURLs.download + path, {responseType: 'blob'}); + } + deployPost(body: any | null): Observable<any> { + return this.api.post(BlueprintURLs.deploy, body, {responseType: 'text'}); } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css index 799407093..37a6f9235 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.css @@ -268,7 +268,7 @@ p.compType-4{ color: #fff; } .actionBtns .btn:last-child{ - padding-left: 34px; + padding-left: 34px !important; background: url(src/assets/img/icon-import-blue.svg) 12px center #fff no-repeat; border: solid 1px #D0DFF1; color: #1B3E6F; @@ -279,6 +279,8 @@ p.compType-4{ } .componentsList{ padding-bottom: 0; + height: calc( 100vh - 218px)!important; + overflow: scroll; } .custom-control.custom-checkbox:hover, .custom-control-label:hover{ @@ -342,11 +344,11 @@ p.compType-4{ /*CANVAS*/ .editBar{ - width: 350px; + width: 200px; margin: 0 auto 0; padding: 6px 10px; background:#F4F9FE; - border: solid 1px #E8EFF8; + /* border: solid 1px #E8EFF8; */ box-shadow: 0 2px 6px rgba(47, 83, 151, .1); } .editBar .btn-group{ @@ -366,7 +368,7 @@ p.compType-4{ } .viewBtns .btn{ background-position: 10px center; - padding-left: 30px; + padding-left: 30px!important; } .viewBtns .topologySource{ background-image: url(src/assets/img/icon-topologyView-active.svg); @@ -548,3 +550,30 @@ p.compType-4{ font-size: 10px; } +.source-button{ + position: absolute; + z-index: 9999999; + top: 69px; + left: 50%; +} +/*jointjs paper*/ +/* #board-paper { + position: relative; + border: 1px solid gray; + display: inline-block; + background: transparent; + overflow: hidden; +} +#board-paper svg { + background: transparent; +} +#board-paper svg .link { + z-index: 2; +} +.html-element { + position: absolute; + background: #F4F9FE; + pointer-events: none; + -webkit-user-select: none; + z-index: 2; +} */ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html index 8ec735aec..1a2219bab 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.html @@ -55,26 +55,27 @@ </div> </div> </header> +<div class="source-button editBar"> + <div class="btn-group viewBtns" role="group"> + <button type="button" class="btn btn-secondary topologySource active">Designer</button> + <button [routerLink]="['/designer/source']" type="button" class="btn btn-secondary topologyView">Scripting</button> + </div> +</div> <ng-sidebar-container class="sidebar-container"> <!-- Controller SideBar --> <ng-sidebar [(opened)]="controllerSideBar" [sidebarClass]="'demo-sidebar controllerSidebar container-fluid'" [mode]="'push'" #sidebarLeft> <div class="row"> - <div class="col-12 p-0"> - <form> - <input type="text" class="form-control input-search-controller" - placeholder="Search actions and functions"> - </form> - </div> + <h1 class="col-12">Actions</h1> <div class="col-12 text-center p-0"> <div class="btn-group actionBtns" role="group"> <button (click)="insertCustomActionIntoBoard()" type="button" class="btn">Insert Custom</button> - <button type="button" class="btn">Import Action</button> + <!-- <button type="button" class="btn">Import Action</button> --> </div> </div> - <div class="col-12 actionsList"> + <!-- <div class="col-12 actionsList"> <b>Select from other packages:</b> <div class="actions-scroll"> <div class="custom-control custom-checkbox"> @@ -106,32 +107,16 @@ <button type="button" class="btn btn-secondary mr-3">Insert</button> <button type="button" class="btn btn-secondary">Cancel</button> </div> - </div> + </div> --> <h1 class="col-12">Functions</h1> + <b>Drag and drop function to Action’s box</b> <div id="palette-paper" class="col-12 componentsList"> - <b>Drag and drop function to Action’s box</b> - <ul class="list-group actions-scroll"> - <!-- <li class="list-group-item" *ngFor="let function of viewedFunctions"> - <p class="compType-1">{{function.modelName}}</p> - </li> --> - <li class="list-group-item"> - <p class="compType-2">component-netconf-executor</p> - </li> - <li class="list-group-item"> - <p class="compType-3">component-remote-ansible-executor</p> - </li> - <li class="list-group-item"> - <p class="compType-4">dg-generic</p> - </li> - <li class="list-group-item"> - <p class="compType-1">component-resource-resolution</p> - </li> - </ul> </div> </div> </ng-sidebar> <!-- Page content --> + <div ng-sidebar-content id="board-paper"> <button class="rotate" (click)="_toggleSidebar1()"> <span> @@ -139,6 +124,7 @@ <i class="fa fa-angle-double-left"></i> </span> </button> + <!-- Canvas --> <div class="editBar text-center"> <div class="btn-group mr-2" role="group" aria-label="First group"> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts index b19f5699b..5adce7ea0 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.component.ts @@ -1,9 +1,39 @@ -import { Component, OnInit, ViewEncapsulation } from '@angular/core'; +/* +============LICENSE_START========================================== +=================================================================== +Copyright (C) 2019 Orange. All rights reserved. +=================================================================== + +Unless otherwise specified, all software contained herein is licensed +under the Apache License, Version 2.0 (the License); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +============LICENSE_END============================================ +*/ + +import dagre from 'dagre'; +import graphlib from 'graphlib'; +import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core'; import * as joint from 'jointjs'; import './jointjs/elements/palette.function.element'; import './jointjs/elements/action.element'; import './jointjs/elements/board.function.element'; - +import { DesignerStore } from './designer.store'; +import { ActionElementTypeName } from 'src/app/common/constants/app-constants'; +import { GraphUtil } from './graph.util'; +import { GraphGenerator } from './graph.generator.util'; +import { FunctionsStore } from './functions.store'; +import { Subject } from 'rxjs'; +import { takeUntil } from 'rxjs/operators'; +import { distinctUntilChanged } from 'rxjs/operators'; @Component({ @@ -12,23 +42,26 @@ import './jointjs/elements/board.function.element'; styleUrls: ['./designer.component.css'], encapsulation: ViewEncapsulation.None }) -export class DesignerComponent implements OnInit { +export class DesignerComponent implements OnInit, OnDestroy { private controllerSideBar: boolean; private attributesSideBar: boolean; - //to generate Ids for dragged function elements - private fuctionIdCounter=0; - private actionIdCounter=0; boardGraph: joint.dia.Graph; boardPaper: joint.dia.Paper; paletteGraph: joint.dia.Graph; palettePaper: joint.dia.Paper; + private ngUnsubscribe = new Subject(); + private opt = { tx: 100, ty: 100 }; - constructor() { + constructor(private designerStore: DesignerStore, + private functionStore: FunctionsStore, + private graphUtil: GraphUtil, + private graphGenerator: GraphGenerator) { this.controllerSideBar = true; this.attributesSideBar = false; + } private _toggleSidebar1() { this.controllerSideBar = !this.controllerSideBar; @@ -53,23 +86,66 @@ export class DesignerComponent implements OnInit { ngOnInit() { this.initializeBoard(); this.initializePalette(); - // this.createEditBarOverThePaper(); - const list = [ - { modelName: 'component-netconf-executor'}, - { modelName: 'component-remote-ansible-executor' }, - { modelName: 'dg-generic' }, - { modelName: 'component-resource-resolution' }]; + this.stencilPaperEventListeners(); - const cells = this.buildPaletteGraphFromList(list); - this.paletteGraph.resetCells(cells); + /** + * the code to retrieve from server is commented + */ + this.functionStore.state$ + .pipe( + distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe(state => { + + if (state.serverFunctions) { + console.log('inside subscriotn on functions store -->', state.serverFunctions); + console.log(state); + // this.viewedFunctions = state.functions; + const list = state.serverFunctions; + + const cells = this.graphUtil.buildPaletteGraphFromList(list); + this.paletteGraph.resetCells(cells); + + let idx = 0; + cells.forEach(cell => { + cell.translate(5, (cell.attributes.size.height + 5) * idx++); + }); + } + }); - let idx = 0; - cells.forEach(cell => { - console.log(cell); - cell.translate(5, (cell.attributes.size.height + 5) * idx++); + this.designerStore.state$ + .pipe( + distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe(state => { + if (state.sourceContent) { + console.log('inside desinger.component---> ', state); + // generate graph from store objects if exist + const topologtTemplate = JSON.parse(state.sourceContent); + console.log(topologtTemplate); + delete state.sourceContent; + this.graphGenerator.populate(topologtTemplate, this.boardGraph); + + console.log('all cells', this.boardGraph.getCells()); + /** + * auto arrange elements in graph + * https://resources.jointjs.com/docs/jointjs/v3.1/joint.html#layout.DirectedGraph + */ + joint.layout.DirectedGraph.layout( this.boardGraph.getCells(), { + dagre, + graphlib, + setLinkVertices: false, + marginX: 10, + marginY: 10, + clusterPadding: { top: 100, left: 30, right: 10, bottom: 100 }, + rankDir: 'TB' + }); + } + }); + + // action triggering + this.functionStore.retrieveFuntions(); - }); - this.stencilPaperEventListeners(); } initializePalette() { @@ -78,22 +154,26 @@ export class DesignerComponent implements OnInit { this.palettePaper = new joint.dia.Paper({ el: $('#palette-paper'), model: this.paletteGraph, - height: 300, width: 300, - gridSize: 1, + height: $('#palette-paper').height(), + // background: { + // color: 'rgba(0, 255, 0, 0.3)' + // }, interactive: false + // elements in paletter need to be fixed, please refer to flying paper concept }); } } initializeBoard() { if (!this.boardGraph) { + console.log('initializeBoard...'); this.boardGraph = new joint.dia.Graph(); this.boardPaper = new joint.dia.Paper({ el: $('#board-paper'), model: this.boardGraph, height: 720, - width: 1200, + width: 1100, gridSize: 10, drawGrid: true, // background: { @@ -120,22 +200,21 @@ export class DesignerComponent implements OnInit { this.boardGraph.on('change:position', (cell) => { - var parentId = cell.get('parent'); - if (!parentId) return; + const parentId = cell.get('parent'); + if (!parentId) { + // this is action + return; + } - var parent = this.boardGraph.getCell(parentId); - - var parentBbox = parent.getBBox(); - var cellBbox = cell.getBBox(); + const parent = this.boardGraph.getCell(parentId); - console.log("parent ", parentBbox); - console.log("cell ", cellBbox); + const parentBbox = parent.getBBox(); + const cellBbox = cell.getBBox(); if (parentBbox.containsPoint(cellBbox.origin()) && parentBbox.containsPoint(cellBbox.topRight()) && parentBbox.containsPoint(cellBbox.corner()) && parentBbox.containsPoint(cellBbox.bottomLeft())) { - // All the four corners of the child are inside // the parent area. return; @@ -145,54 +224,18 @@ export class DesignerComponent implements OnInit { cell.set('position', cell.previous('position')); }); } + console.log('done initializing Board...'); } insertCustomActionIntoBoard() { - this.actionIdCounter++; - const element = this.createCustomAction("action_"+ this.actionIdCounter, 'Action' + this.actionIdCounter); - this.boardGraph.addCell(element); - } - - createCustomAction(id: string, label: string) { - const element = new joint.shapes.app.ActionElement({ - id: id - }); - element.attr('#label/text', label); - return element; - } - - buildPaletteGraphFromList(list: any) { - const elements = []; - - console.log(list); - list.forEach(element => { - elements.push(this.createFuctionElementForPalette(element.modelName)); - }); - - return elements; - } - - createFuctionElementForPalette(label: string) { - const element = new joint.shapes.palette.FunctionElement({ - id: label - }); - element.attr('#label/text', label); - element.attr('type', label); - return element; - } - - createFuctionElementForBoard(id :String, label :string, type :string) { - const boardElement = new joint.shapes.board.FunctionElement({ - id: id - }); - boardElement.attr('#label/text', label); - boardElement.attr('#type/text', type); - return boardElement; + console.log('saving action to store action workflow....'); + const actionName = this.graphUtil.generateNewActionName(); + this.graphUtil.createCustomActionWithName(actionName, this.boardGraph); + this.designerStore.addDeclarativeWorkFlow(actionName); } stencilPaperEventListeners() { this.palettePaper.on('cell:pointerdown', (draggedCell, pointerDownEvent, x, y) => { - console.log('pointerdown 2'); $('body').append(` <div id="flyPaper" @@ -232,116 +275,62 @@ export class DesignerComponent implements OnInit { if (mouseupX > target.left && mouseupX < target.left + this.boardPaper.$el.width() && mouseupY > target.top && y < target.top + this.boardPaper.$el.height()) { - // const clonedShape = flyShape.clone(); - const type = flyShape.attributes.attrs.type; - console.log(type); - - //create board function element of the same type of palette function - //board function element is different in design from the palette function element - this.fuctionIdCounter++; - console.log(this.fuctionIdCounter); - const functionElementForBoard = - this.createFuctionElementForBoard("fucntion_" + this.fuctionIdCounter, 'execute', type); - - functionElementForBoard.position(mouseupX - target.left - offset.x, mouseupY - target.top - offset.y); - this.boardGraph.addCell(functionElementForBoard); - const cellViewsBelow = - this.boardPaper.findViewsFromPoint(functionElementForBoard.getBBox().center()); - console.log(cellViewsBelow); - if (cellViewsBelow.length) { - let cellViewBelow; - cellViewsBelow.forEach( cellItem => { - if (cellItem.model.id !== functionElementForBoard.id) { - cellViewBelow = cellItem; + const functionType = this.graphUtil.getFunctionTypeFromPaletteFunction(flyShape); + // step name is CDS realted terminology, please refer to tosca types + const stepName = functionType; + const functionElementForBoard = this.graphUtil.dropFunctionOverActionWithPosition( + stepName, functionType, + mouseupX, mouseupY, + target, offset, + this.boardGraph); + + const parentCell = this.graphUtil.getParent(functionElementForBoard, this.boardPaper); + + if (parentCell && + parentCell.model.attributes.type === ActionElementTypeName && + this.graphUtil.canEmpedMoreChildern(parentCell.model, this.boardGraph)) { + + if (this.graphUtil.isEmptyParent(parentCell.model)) { + // first function in action + const actionName = parentCell.model.attributes.attrs['#label'].text; + this.designerStore.addStepToDeclarativeWorkFlow(actionName, stepName, functionType); + if (functionType === 'dg-generic') { + this.designerStore.addDgGenericNodeTemplate(stepName); + } else { + this.designerStore.addNodeTemplate(stepName, functionType); } - }); + } else { + // second action means there was a dg-generic node before + this.designerStore.addNodeTemplate(stepName, functionType); + // this will fail if multiple dg-generic were added + // TODO prevent multi functions of the same type inside the same action + const dgGenericNode = this.graphUtil.getDgGenericChild(parentCell.model, this.boardGraph)[0]; + const dgGenericNodeName = this.graphUtil.getFunctionNameFromBoardFunction(dgGenericNode); + this.designerStore.addDgGenericDependency(dgGenericNodeName, stepName); + } + // Prevent recursive embedding. - if (cellViewBelow && cellViewBelow.model.get('parent') !== functionElementForBoard.id) { - console.log(cellViewBelow); - cellViewBelow.model.embed(functionElementForBoard); + if (parentCell && + parentCell.model.get('parent') !== functionElementForBoard.id) { + parentCell.model.embed(functionElementForBoard); } - console.log(this.boardGraph); + } else { + console.log('function dropped outside action or not allowed, rolling back...'); + alert('function dropped outside action or not allowed, rolling back...'); + functionElementForBoard.remove(); } - } $('body').off('mousemove.fly').off('mouseup.fly'); // flyShape.remove(); $('#flyPaper').remove(); }); }); + console.log('done stencilPaperEventListeners()...'); } - /** - * this is a way to add the button like zoom in , zoom out , and source over jointjs paper - * may be used if no other way is found - */ - // createEditBarOverThePaper() { - // joint.shapes["html"] = {}; - // joint.shapes["html"].Element = joint.shapes.basic.Rect.extend({ - // defaults: joint.util.deepSupplement({ - // type: 'html.Element' - // }, joint.shapes.basic.Rect.prototype.defaults) - // }); - // joint.shapes["html"].ElementView = joint.dia.ElementView.extend({ - - // template: [ - // '<div>', - // '<div id="editbar" class="editBar text-center">', - // '<div class="btn-group mr-2" role="group" aria-label="First group">', - // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Undo">', - // '<img src="/assets/img/icon-undoActive.svg">', - // '</button>', - // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Redo">', - // '<img src="/assets/img/icon-redo.svg">', - // '</button>', - // '</div>', - // '<div class="btn-group mr-2" role="group" aria-label="Second group">', - // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Zoom Out">', - // '<img src="/assets/img/icon-zoomOut.svg">', - // '</button>', - // '<button type="button" class="btn btn-secondary pl-0 pr-0">100%</button>', - // '<button type="button" class="btn btn-secondary tooltip-bottom" data-tooltip="Zoom In">', - // '<img src="/assets/img/icon-zoomIn.svg">', - // '</button>', - // '</div>', - // '<div class="btn-group viewBtns" role="group" aria-label="Third group">', - // '<button type="button" class="btn btn-secondary topologySource active">View</button>', - // '<button type="button" class="btn btn-secondary topologyView">Source</button>', - // '</div>', - // '</div>', - // '</div>' - // ].join(''), - // initialize: function () { - // _.bindAll(this, 'updateBox'); - // joint.dia.ElementView.prototype.initialize.apply(this, arguments); - - // this.$box = $(_.template(this.template)()); - // // Prevent paper from handling pointerdown. - // this.$box.find('input,select').on('mousedown click', function (evt) { - // evt.stopPropagation(); - // }); - // this.model.on('change', this.updateBox, this); - // this.updateBox(); - // }, - // render: function () { - // joint.dia.ElementView.prototype.render.apply(this, arguments); - // this.paper.$el.prepend(this.$box); - // this.updateBox(); - // return this; - // }, - // updateBox: function () { - // // Set the position and dimension of the box so that it covers the JointJS element. - // var bbox = this.model.getBBox(); - // this.$box.css({ - // width: bbox.width, - // height: bbox.height, - // left: bbox.x, - // top: bbox.y, - // transform: 'rotate(' + (this.model.get('angle') || 0) + 'deg)' - // }); - // } - // }); - - // } + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.service.ts index c4564254f..aa3a6a668 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.service.ts @@ -23,7 +23,7 @@ import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import {ApiService} from '../../../../common/core/services/api.typed.service'; import {ResourceDictionaryURLs} from '../../../../common/constants/app-constants'; -import {ModelType} from '../model/ModelType.model'; +import {ModelType} from './model/ModelType.model'; @Injectable({ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts index be98eec88..ba8b2f0f1 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/designer.store.ts @@ -22,8 +22,9 @@ limitations under the License. import {Injectable} from '@angular/core'; import {Store} from '../../../../common/core/stores/Store'; import {DesignerService} from './designer.service'; -import {ModelType} from '../model/ModelType.model'; -import {DesignerDashboardState} from '../model/designer-dashboard.state'; +import {DesignerDashboardState} from './model/designer.dashboard.state'; +import { DeclarativeWorkflow } from './model/designer.workflow'; +import { NodeTemplate } from './model/desinger.nodeTemplate.model'; @Injectable({ @@ -35,15 +36,109 @@ export class DesignerStore extends Store<DesignerDashboardState> { super(new DesignerDashboardState()); } - public getFuntions() { - const modelDefinitionType = 'node_type'; - this.designerService.getFunctions(modelDefinitionType).subscribe( - (modelType: ModelType[]) => { - console.log(modelType); - this.setState({ - ...this.state, - functions: modelType, - }); - }); + /** + * adds empty workflow with name only. + * called when blank action is added to the board + * declarative workflow just contain the steps but its order is determind by dg-graph + */ + addDeclarativeWorkFlow(workflowName: string) { + this.setState({ + ...this.state, + template: { + ...this.state.template, + workflows: { + ...this.state.template.workflows, + [workflowName]: new DeclarativeWorkflow() + } + } + }); + } + + addStepToDeclarativeWorkFlow(workflowName: string, stepName: string, stepType: string) { + this.setState({ + ...this.state, + template: { + ...this.state.template, + workflows: { + ...this.state.template.workflows, + [workflowName]: { + ...this.state.template.workflows[workflowName], + steps: { + [stepName]: { + target: stepType, + description: '' + } + } + } + } + } + }); + } + + saveSourceContent(code: string) { + const topologyTemplate = JSON.parse(code); + this.setState({ + ...this.state, + sourceContent: code, + template: topologyTemplate + }); + } + + + /** + * adding node tempates is a separate action of adding the steps to the workflow + * you can add node template and don't add workflow step when you add dependencies for the + * dg-generic function for example + */ + addNodeTemplate(nodeTemplateName: string, type: string) { + this.setState({ + ...this.state, + template: { + ...this.state.template, + node_templates: { + ...this.state.template.node_templates, + [nodeTemplateName]: new NodeTemplate(type) + } + } + }); + } + + addDgGenericNodeTemplate(nodeTemplateName: string) { + const node = new NodeTemplate('dg-generic'); + node.properties = { + 'dependency-node-templates': [] + }; + this.setState({ + ...this.state, + template: { + ...this.state.template, + node_templates: { + ...this.state.template.node_templates, + [nodeTemplateName]: node + } + } + }); + } + + addDgGenericDependency(dgGenericNodeName: string, dependency: string) { + const props = this.state.template.node_templates[dgGenericNodeName].properties; + this.setState({ + ...this.state, + template: { + ...this.state.template, + node_templates: { + ...this.state.template.node_templates, + [dgGenericNodeName]: { + ...this.state.template.node_templates[dgGenericNodeName], + properties: { + 'dependency-node-templates': [ + ...props['dependency-node-templates'], + dependency + ] + } + } + } + } + }); } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/package.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts index efbaef8bd..86814179d 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/configuration-dashboard/package.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions.store.ts @@ -21,38 +21,28 @@ limitations under the License. import {Injectable} from '@angular/core'; import {Store} from '../../../../common/core/stores/Store'; -import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; -import {ConfigurationDashboardService} from './configuration-dashboard.service'; -import {PackageDashboardState} from '../model/package-dashboard.state'; +import {DesignerService} from './designer.service'; +import {ModelType} from './model/ModelType.model'; +import { FunctionsState } from './model/functions.state'; @Injectable({ providedIn: 'root' }) -export class PackageStore extends Store<PackageDashboardState> { +export class FunctionsStore extends Store<FunctionsState> { - - constructor(private configurationDashboardService: ConfigurationDashboardService) { - super(new PackageDashboardState()); + constructor(private designerService: DesignerService) { + super(new FunctionsState()); } - getPagedPackages(id: string) { - this.configurationDashboardService.getBluePrintModel(id).subscribe( - (bluePrintDetailModels) => { + public retrieveFuntions() { + const modelDefinitionType = 'node_type'; + this.designerService.getFunctions(modelDefinitionType).subscribe( + (modelTypeList: ModelType[]) => { this.setState({ ...this.state, - configuration: bluePrintDetailModels[0] + serverFunctions: modelTypeList, }); }); - /* bluePrintDetailModels.forEach( - bluePrintDetailModel => { - this.setState({ - ...this.state, - configuration: bluePrintDetailModel - }); - });*/ - - } - } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css deleted file mode 100644 index e69de29bb..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.css +++ /dev/null diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html deleted file mode 100644 index b27f91f49..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.html +++ /dev/null @@ -1,21 +0,0 @@ -<h1 class="col-12">Functions</h1> -<div class="col-12 componentsList"> - <b>Drag and drop function to Action’s box</b> - <ul class="list-group actions-scroll" > - <li class="list-group-item" *ngFor="let function of viewedFunctions"> - <p class="compType-1">{{function.modelName}}</p> - </li> - <!--<li class="list-group-item"> - <p class="compType-2">component-netconf-executor</p> - </li> - <li class="list-group-item"> - <p class="compType-3">component-remote-ansible-executor</p> - </li> - <li class="list-group-item"> - <p class="compType-4">dg-generic</p> - </li> - <li class="list-group-item"> - <p class="compType-1">component-resource-resolution</p> - </li>--> - </ul> -</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts deleted file mode 100644 index eec909b01..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FunctionsComponent } from './functions.component'; - -describe('FunctionsComponent', () => { - let component: FunctionsComponent; - let fixture: ComponentFixture<FunctionsComponent>; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ FunctionsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(FunctionsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts deleted file mode 100644 index 5a86150e8..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions/functions.component.ts +++ /dev/null @@ -1,28 +0,0 @@ -import {Component, OnInit} from '@angular/core'; -import {DesignerStore} from '../designer.store'; -import {ModelType} from '../../model/ModelType.model'; - - -@Component({ - selector: 'app-functions', - templateUrl: './functions.component.html', - styleUrls: ['./functions.component.css'] -}) -export class FunctionsComponent implements OnInit { - viewedFunctions: ModelType[] = []; - - constructor(private designerStore: DesignerStore) { - - this.designerStore.state$.subscribe(state => { - console.log(state); - if (state.functions) { - this.viewedFunctions = state.functions; - } - }); - } - - ngOnInit() { - this.designerStore.getFuntions(); - } - -} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts new file mode 100644 index 000000000..8e1d88907 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.generator.util.ts @@ -0,0 +1,113 @@ +/* +============LICENSE_START========================================== +=================================================================== +Copyright (C) 2019 Orange. All rights reserved. +=================================================================== + +Unless otherwise specified, all software contained herein is licensed +under the Apache License, Version 2.0 (the License); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +============LICENSE_END============================================ +*/ +import { TopologyTemplate } from './model/designer.topologyTemplate.model'; +import { Injectable } from '@angular/core'; +import { GraphUtil } from './graph.util'; +import { NodeTemplate } from './model/desinger.nodeTemplate.model'; + +@Injectable({ + providedIn: 'root' +}) +export class GraphGenerator { + + constructor(private graphUtil: GraphUtil) { + } + + /** + * loops over workflows + * create action element + * from steps --> create function element + * add function element to action element + * example toplogyTemplate + * + * { + * "workflows": { + * "Action1": { + * "steps": { + * "STEP_NAME": { + * "target": "NODE_TEMPLATE_NAME", + * "description": "" + * } + * } + * } + * }, + * "node_templates": { + * "NODE_TEMPLATE_NAME": { + * "type": "dg-generic", + * "properties": { + * "dependency-node-templates": [ + * "component-config-snapshots-executor", + * "component-jython-executor" + * ] + * } + * }, + * "component-config-snapshots-executor": { + * "type": "component-config-snapshots-executor", + * "properties": { } + * }, + * "component-jython-executor": { + * "type": "component-jython-executor", + * "properties": { } + * } + * } + * } + */ + + public populate(topologyTempalte: TopologyTemplate, + boardGraph: joint.dia.Graph) { + + Object.keys(topologyTempalte.workflows).forEach(workFlowName => { + console.log('drawing workflow item --> ', workFlowName); + + // create action element + const actionElement = + this.graphUtil.createCustomActionWithName(workFlowName, boardGraph); + + // create board function elements + const workflow = topologyTempalte.workflows[workFlowName].steps; + const stepName = Object.keys(workflow)[0]; + if (stepName) { + const nodeTemplateName = workflow[stepName].target; + const functionType = topologyTempalte.node_templates[nodeTemplateName].type; + console.log('draw function with ', stepName, functionType); + + this.graphUtil.dropFunctionOverActionRelativeToParent( + actionElement, + stepName , functionType, boardGraph); + + // TODO handle dg-generic case (multi-step in the same action) + if (functionType === 'dg-generic') { + const props = topologyTempalte.node_templates[nodeTemplateName].properties; + console.log('dg props', props); + props['dependency-node-templates'].forEach(dependencyStepName => { + const dependencyType = topologyTempalte.node_templates[dependencyStepName].type; + console.log('dependencyType', dependencyType); + this.graphUtil.dropFunctionOverActionRelativeToParent( + actionElement, + dependencyStepName, dependencyType, boardGraph); + + }); + } + } + }); + + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts new file mode 100644 index 000000000..fd4dd35e4 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/graph.util.ts @@ -0,0 +1,228 @@ +/* +============LICENSE_START========================================== +=================================================================== +Copyright (C) 2019 Orange. All rights reserved. +=================================================================== + +Unless otherwise specified, all software contained herein is licensed +under the Apache License, Version 2.0 (the License); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +============LICENSE_END============================================ +*/ + +import * as joint from 'jointjs'; +import { Injectable } from '@angular/core'; + +@Injectable({ + providedIn: 'root' +}) +export class GraphUtil { + + actionIdCounter = 0; + // to generate Ids for dragged function elements + private fuctionIdCounter = 0; + + createCustomAction(boardGraph: joint.dia.Graph) { + const actionName = this.generateNewActionName(); + const actionId = this.generateNewActionId(); + const element = new joint.shapes.app.ActionElement({ + id: actionId + }); + element.attr('#label/text', actionName); + boardGraph.addCell(element); + return element; + } + + generateNewActionName() { + this.actionIdCounter++; + const actionName = 'Action' + this.actionIdCounter; + return actionName; + } + + private generateNewActionId() { + const actionName = + (Date.now().toString(36) + Math.random().toString(36).substr(2, 5)) + .toUpperCase(); + return actionName; + } + + createCustomActionWithName(actionName: string, boardGraph: joint.dia.Graph) { + const actionId = this.generateNewActionId(); + const element = new joint.shapes.app.ActionElement({ + id: actionId + }); + element.attr('#label/text', actionName); + boardGraph.addCell(element); + return element; + } + + buildPaletteGraphFromList(list: any) { + const elements = []; + list.forEach(element => { + elements.push(this.createFuctionElementForPalette(element.modelName)); + }); + + return elements; + } + + createFuctionElementForPalette(label: string) { + const element = new joint.shapes.palette.FunctionElement({ + id: label + }); + element.attr('#label/text', label); + element.attr('type', label); + return element; + } + + createFuctionElementForBoard( label: string, type: string) { + this.fuctionIdCounter++; + const id = 'fucntion_' + this.fuctionIdCounter; + const boardElement = new joint.shapes.board.FunctionElement({ + id + }); + boardElement.attr('#label/text', label); + boardElement.attr('#type/text', type); + return boardElement; + } + + getParent(functionElementForBoard: joint.shapes.board.FunctionElement, boardPaper: joint.dia.Paper) { + const cellViewsBelow = boardPaper.findViewsFromPoint(functionElementForBoard.getBBox().center()); + let cellViewBelow; + if (cellViewsBelow.length) { + cellViewsBelow.forEach(cellItem => { + if (cellItem.model.id !== functionElementForBoard.id) { + cellViewBelow = cellItem; + } + }); + } + return cellViewBelow; + } + + /** + * trigger actions related to Function dropped over the board: + * - create board function element of the same type of palette function + * as board function element is different from the palette function element + * - save function to parent action in store + */ + dropFunctionOverActionWithPosition( + label: string, type: string, + mouseupX: number, mouseupY: number, + target: JQuery.Coordinates, offset: { x: number; y: number; }, + boardGraph: joint.dia.Graph) { + + const functionElementForBoard = this.dropFunctionOverAction(label, type, boardGraph); + functionElementForBoard.position(mouseupX - target.left - offset.x, mouseupY - target.top - offset.y); + + return functionElementForBoard; + } + + + dropFunctionOverActionRelativeToParent( + parent: joint.shapes.app.ActionElement, + label: string, type: string, + boardGraph: joint.dia.Graph) { + + const functionElementForBoard = this.dropFunctionOverAction(label, type, boardGraph); + parent.embed(functionElementForBoard); + functionElementForBoard.position({ parentRelative: true }); + + return functionElementForBoard; + } + + + dropFunctionOverAction( + label: string, type: string, + boardGraph: joint.dia.Graph) { + + // function name is the same as function type + // actually functionName here refers step name in CDS tosca model + // and function type is the nodeTempalteName + const functionElementForBoard = + this.createFuctionElementForBoard(label, type); + boardGraph.addCell(functionElementForBoard); + return functionElementForBoard; + } + + getFunctionTypeFromPaletteFunction(cell: joint.shapes.palette.FunctionElement) { + return cell.attributes.attrs.type; + } + + getFunctionTypeFromBoardFunction(cell: joint.shapes.board.FunctionElement) { + return cell.attributes.attrs['#type'].text; + } + + getFunctionNameFromBoardFunction(cell: joint.shapes.board.FunctionElement) { + return cell.attributes.attrs['#label'].text; + } + + canEmpedMoreChildern(parentCell: joint.shapes.app.ActionElement, boardGraph: joint.dia.Graph): boolean { + if (!parentCell.get('embeds')) { + return true; + } + const types = this.getChildernTypes(parentCell, boardGraph); + return parentCell.get('embeds').length < 1 || + types.includes('dg-generic'); + } + + + getChildernTypes(parentCell: joint.shapes.app.ActionElement, + boardGraph: joint.dia.Graph): string[] { + if (parentCell.get('embeds')) { + return parentCell.get('embeds').map((cellName) => { + const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement; + const functionType = this.getFunctionTypeFromBoardFunction(child); + console.log('functionType', functionType); + return functionType; + }); + } else { + return []; + } + } + + getDgGenericChild(parentCell: joint.shapes.app.ActionElement, + boardGraph: joint.dia.Graph): + joint.shapes.board.FunctionElement[] { + if (parentCell.get('embeds')) { + return parentCell.get('embeds') + .filter((cellName) => { + const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement; + const functionType = this.getFunctionTypeFromBoardFunction(child); + return functionType === 'dg-generic'; + }) + .map((cellName) => { + const child = boardGraph.getCell(cellName) as joint.shapes.board.FunctionElement; + return child; + }); + } else { + return []; + } + } + + isEmptyParent(parentCell: joint.shapes.app.ActionElement): boolean { + return !parentCell.get('embeds') || parentCell.get('embeds').length < 1; + } + + getActionSiblings(actionCell: joint.shapes.app.ActionElement, + boardGraph: joint.dia.Graph + ): joint.shapes.app.ActionElement[] { + const cellId = actionCell.id; + const siblings = boardGraph.getCells().filter(elem => { + const type = elem.attributes.type; + const elemId = elem.id; + return (type !== undefined && type === 'app.ActionElement' + && elemId !== cellId); + }) as joint.shapes.app.ActionElement[]; + console.log('siblings', siblings); + return siblings; + } + +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/jointjs/elements/action.element.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/jointjs/elements/action.element.ts index 212905814..7960e83d1 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/jointjs/elements/action.element.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/jointjs/elements/action.element.ts @@ -1,4 +1,5 @@ import * as joint from 'jointjs'; +import { ActionElementTypeName } from 'src/app/common/constants/app-constants'; /** * please refer to documentation in file palette.function.element.ts to get more details * about how to create new element type and define it in typescript @@ -18,7 +19,7 @@ const rectWidth = 616; const rectHeight = 381; // custom element implementation // https://resources.jointjs.com/tutorials/joint/tutorials/custom-elements.html#markup -const ActionElement = joint.shapes.standard.Rectangle.define('app.ActionElement', { +const ActionElement = joint.shapes.standard.Rectangle.define(ActionElementTypeName, { size: {width: rectWidth, height: rectHeight} }, { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/ModelType.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/ModelType.model.ts index c8498fa36..c8498fa36 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/ModelType.model.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/ModelType.model.ts diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts new file mode 100644 index 000000000..1a14021f4 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.dashboard.state.ts @@ -0,0 +1,33 @@ +/* +============LICENSE_START========================================== +=================================================================== +Copyright (C) 2019 Orange. All rights reserved. +=================================================================== + +Unless otherwise specified, all software contained herein is licensed +under the Apache License, Version 2.0 (the License); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +============LICENSE_END============================================ +*/ + +import {ModelType} from './ModelType.model'; +import { TopologyTemplate } from './designer.topologyTemplate.model'; + +export class DesignerDashboardState { + + template: TopologyTemplate; + sourceContent: string; + + constructor() { + this.template = new TopologyTemplate(); + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts new file mode 100644 index 000000000..b85a6139a --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.topologyTemplate.model.ts @@ -0,0 +1,13 @@ +import { DeclarativeWorkflow } from './designer.workflow'; +import { NodeTemplate } from './desinger.nodeTemplate.model'; + +export class TopologyTemplate { + + workflows: {}; + 'node_templates': {}; + + constructor() { + this.workflows = {}; + this.node_templates = {}; + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.workflow.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.workflow.ts new file mode 100644 index 000000000..0687c1f47 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/designer.workflow.ts @@ -0,0 +1,14 @@ +export class Workflow { + inputs: {}; + outputs?: {}; +} + +export class DeclarativeWorkflow implements Workflow { + steps: {}; + inputs: {}; + outputs?: {}; + + constructor() { + this.steps = {}; + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts new file mode 100644 index 000000000..8715e44c2 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/desinger.nodeTemplate.model.ts @@ -0,0 +1,15 @@ +export class NodeTemplate { + type: string; + properties?: { + 'dependency-node-templates'?: string[] + }; + interfaces?: {}; + artifacts?: {}; + cabapilities?: {}; + requirements?: {}; + + constructor(type) { + this.type = type; + this.properties = {}; + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/designer-dashboard.state.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts index dc65c009f..329c38deb 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/designer-dashboard.state.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/model/functions.state.ts @@ -21,9 +21,11 @@ limitations under the License. import {ModelType} from './ModelType.model'; -export class DesignerDashboardState { +export class FunctionsState { - functions: ModelType[]; - actions: string[]; + serverFunctions: ModelType[]; + constructor() { + this.serverFunctions = []; + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css new file mode 100644 index 000000000..01ae599a4 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.css @@ -0,0 +1,580 @@ +.dsl-editor { + height: 500px; +} + +body{ + background-image: linear-gradient(-45deg, #000 9%, #fff 0) !important; + background-size: 6px 6px !important; +} + + +/*Header*/ +header{ + height: 60px; + background-color: #1B3E6F; + box-shadow: 0 4px 10px rgba(238, 240, 245, 1.0); +} +.logo{ + float: left; + width: 50px; + height: 60px; + background: url(/assets/img/logo-icon.svg) center center #fff no-repeat; +} + +/**Bread Crumb**/ +.breadcrumb{ + padding: 9px 20px; + background: transparent; + line-height: 40px; +} +.breadcrumb a, +.breadcrumb a:hover{ + color: #fff; +} +.breadcrumb .breadcrumb-item{ + font-size: 12px; + font-weight: bold; +} +.breadcrumb .breadcrumb-item:first-child{ + font-size: 16px; +} +.breadcrumb-item + .breadcrumb-item::before{ + color: #fff; +} +.breadcrumb .breadcrumb-item.active p{ + display: inline; + padding: 4px 10px; + background: #F4F9FE; + border-radius: 10px; + color: #C3CDDB; + font-size: 10px; +} +.sidebar-container{ + height: calc(100vh - 60px) !important; +} +/**Topology Actions**/ +.topology-actions{ + margin: 0; + height: 60px; +} +.topology-actions > li{ + height: 59px; + display: inline-block; + padding: 0 20px; +} +.topology-actions > li:first-child{ + border-right: solid 1px #16396A; +} +.topology-actions .btn-group{ + margin-top: 11px; +} +.btn-topology-action, +.btn-topology-action:hover{ + margin: 0 6px; + padding: 6px 10px; + color: #fff; + border-radius: 50%; + border: solid .5px #fff; +} +.btn-topology-action:last-child{ + margin-right: 0; +} +.btn-topology-action .fa{ + width: 16px; + height: 16px; + text-align: center; +} +.topology-actions .dropdown-text, +.dropdown-toggle:hover ~ .dropdown-text, +.dropdown-toggle:focus ~ .dropdown-text{ + top: 7px; + text-indent: 15px; + background: #1273EB; + border-radius: 15px; + border: 0; + box-shadow: none; + color: #fff; + font-weight: bold; + font-size: 13px; +} +.topology-actions .dropdown-text::after{ + right: 15px; + top: 13px; + border-width: 6px 6px 0 6px; + border-color: #fff transparent transparent transparent; +} +.topology-actions .dropdown-toggle:focus ~ .dropdown-text::after{ + top: 13px; + border-width: 0 6px 6px 6px; + border-color: transparent transparent #fff transparent +} +.topology-actions .dropdown-content:hover, +.topology-actions .dropdown-toggle:focus ~ .dropdown-content{ + padding: 12px 0; + text-indent: 0; + background: #fff; + border: 0; + border-radius: 2px; + box-shadow: 0 2px 6px rgba(47, 83, 151, .15) +} +.topology-actions .dropdown-content a{ + padding: 0 20px; + color: #1B3E6F; + font-size: 13px; +} +.topology-actions .dropdown-content a:hover{ + background: #F4F9FE; + text-decoration: none; +} + + + + + + + + + + + + + + + + + + +/*Rotated Text*/ +button.rotate{ + position: absolute; + margin-top: 1px; + padding: 0; + background: transparent; + border: 0; +} +.rotate{ + vertical-align: bottom; + /* text-align: center; */ +} +.rotate span{ + display: inline-table !important; + -ms-writing-mode: tb-rl; + -webkit-writing-mode: vertical-rl; + writing-mode: vertical-rl !important; + transform: rotate(180deg); + white-space: nowrap; + background: #1B3E6F; + padding: 15px 12px; + font-weight: bold; + font-size: 12px; + color:#fff; + /* border-bottom-left-radius: 2px; */ + border-top-left-radius: 2px; +} +.rotate i{ + margin-right: 3px; + margin-top: 9px; + font-size: 15px; +} +.rotate span:first-child{ + margin-bottom: 0; +} +.rotate a:hover{ + text-decoration: none; +} + +/*ACTIONS & COMPONENTS MENU*/ +.input-search-controller{ + height: 50px; + padding-left: 30px; + background: url(src/assets/img/icon-search-light.svg) #fff 10px center no-repeat; + border-radius: 0; + border: 0; + border-bottom: solid 1px #D7E7F9; + color: #1B3E6F; + font-size: 13px; +} +.input-search-controller::placeholder{ + color: #D0D7E4; + font-size: 11px; +} +.input-search-controller:focus{ + + box-shadow: 0 2px 6px 0 rgba(47, 83, 151, .15); + border-color: #DEE8F3; +} +.actions-scroll{ + max-height: 29vh; + overflow-y: auto; + margin-top: 12px; + margin-bottom: 20px; +} +.componentsList p{ + margin-bottom: 0; + padding-left: 30px; + background-position: left center; + background-repeat: no-repeat; +} +p.compType-1{ + background-image: url(/assets/img/icon-comType1-sm.svg); +} +p.compType-2{ + background-image: url(/assets/img/icon-comType2-sm.svg); +} +p.compType-3{ + background-image: url(/assets/img/icon-comType3-sm.svg); +} +p.compType-4{ + background-image: url(/assets/img/icon-comType4-sm.svg); +} +/*Actions Wrapper*/ +.actions-wrapper{ + position: absolute; + width: 100%; + top: 0; +} +.actions-container{ + width: 92%; + margin: 0 auto; + background: red; +} + +.controllerSidebar{ + width: 320px; + background: #F4F9FE; + border: solid 1px #C1CDDD; + box-shadow: 0 2px 6px rgba(47, 83, 151, .10); +} +.controllerSidebar h1{ + margin-bottom: 15px; + padding: 12px 0 12px 12px; + background: #fff; + font-size: 12px; + font-weight: bold; + text-transform: uppercase; + color: #C3CDDB; +} +.controllerSidebar b{ + font-size: 12px; + color: #C3CDDB; +} +.actionBtns .btn{ + margin: 0 15px 12px; + padding: 9px 20px; + border-radius: 2px !important; + font-size: 12px; + font-weight: bold; +} +.actionBtns .btn:first-child{ + background: #1B3E6F; + border: solid 1px #1B3E6F; + color: #fff; +} +.actionBtns .btn:last-child{ + padding-left: 34px !important; + background: url(src/assets/img/icon-import-blue.svg) 12px center #fff no-repeat; + border: solid 1px #D0DFF1; + color: #1B3E6F; +} +.actionsList, +.componentsList{ + padding: 0 12px 20px; +} +.componentsList{ + padding-bottom: 0; +} +.custom-control.custom-checkbox:hover, +.custom-control-label:hover{ + cursor: pointer; +} +.actionsList .custom-checkbox, +.componentsList .list-group-item{ + margin-bottom: 10px; + padding-left: 40px; + background: #fff; + box-shadow: 0 2px 6px rgba(47, 83, 151, .15); + border-radius: 2px; +} +.actionsList .custom-control-label{ + width: 100%; + padding: 6px; + vertical-align: unset; + color: #1B3E6F; + font-size: 14px; + line-height: 20px; + border-top-right-radius: 2px; + border-bottom-right-radius: 2px; +} +.actionsList .custom-control-label::before, +.actionsList .custom-control-label::after{ + top: 1.25rem; +} +.actionsList .custom-control-label p{ + color: #C7D0DD; + font-size: 12px; +} +.custom-control-input:checked ~ .custom-control-label{ + background-color: #1B3E6F !important; + color: #fff; +} +.inserActionBtns .btn{ + border-radius: 15px !important; + padding: 6px 20px; + font-size: 12px; + font-weight: bold; + border: 0; + +} +.inserActionBtns .btn:first-child{ + background: #1273EB; + border: solid 1px #1273EB; + color: #fff; +} +.inserActionBtns .btn:last-child{ + background: #fff; + border: solid 1px #D9E6F2; + color: #C3CDDB; +} +/*Components List*/ +.componentsList .list-group-item{ + padding-left: 36px; + border: 0; + font-size: 14px; + background: url(src/assets/img/icon-drag.svg) #fff 20px center no-repeat; +} + +/*CANVAS*/ +.editBar{ + width: 200px; + margin: 0 auto 0; + padding: 6px 10px; + background:#F4F9FE; + /* border: solid 1px #E8EFF8; */ + box-shadow: 0 2px 6px rgba(47, 83, 151, .1); +} +.editBar .btn-group{ + box-shadow: 0 2px 6px rgba(47, 83, 151, .15); +} +.editBar .btn{ + background-color: #fff; + background-repeat: no-repeat; + background-position: left center; + border: 0; + color: #1B3E6F; + font-size: 10px; +} +.editBar .btn.active{ + background-color: #1B3E6F !important; + color: #fff; +} +.viewBtns .btn{ + background-position: 10px center; + padding-left: 30px!important; +} +.viewBtns .topologySource{ + background-image: url(src/assets/img/icon-topologyView-active.svg); +} +.viewBtns .topologyView{ + background-image: url(src/assets/img/icon-topologySource.svg); +} +.card.actionContainer{ + margin: 20px 20px 40px 60px; + background: transparent; + border: 0; +} +.actionContainer .card-header{ + padding: 0; + background: transparent; + border: 0; +} +.actionContainer .card-header span{ + padding: 12px 20px; + border-top-left-radius: 2px; + border-top-right-radius: 2px; + font-size: 12px; + line-height: 38px; + font-weight: bold; + color: #1B3E6F; + background: #C3CDDB; +} +.actionContainer .card-body{ + min-height: 170px; + padding: 15px 20px !important; + border: solid 1px #C3CDDB; + background: #fff; + box-shadow: 0 2px 6px rgba(18, 115, 235, .1); +} +.actionContainer a{ + display: inline-block; + width: 230px; + height: 130px; + margin: 20px; + padding: 24px; + background: #1B3E6F; + color: #fff !important; + text-align: center; + border-radius: 2px; + border: solid 1px #1B3E6F; +} +.actionContainer a:hover{ + cursor: pointer; + border: dashed 1px #E9FCC6; +}.componentContainer img{ + height: 38px; +} +.componentContainer h2{ + margin-top: 9px; + font-size: 14px; + font-weight: bold; +} +.componentContainer p{ + font-size: 12px; +} + +/*ATTRIBUTES SIDE BAR*/ +.attributesSideBar{ + width: 396px; + padding: 0; +} +.attributesSideBar .attributesContainer{ + background: #fff; + border: solid 1px #C1CDDD; + box-shadow: 0 2px 6px rgba(47, 83, 151, .1); +} +.closeBar{ + float: right; + width: 90%; + height: 40px; + background: url(/assets/img/icon-close.svg) center center #DCE8F4 no-repeat ; + border: 0; + outline: 0; +} +.closeBar:focus{ + outline: none; +} +.attributesContainer h1{ + margin-bottom: 10px; + padding: 12px 0 12px 15px; + background: #DEE8F3; + font-size: 12px; + font-weight: bold; + text-transform: uppercase; + color: #1B3E6F; +} +.actionName{ + margin-bottom: 21px; +} +.attributesContainer label{ + color: #1B3E6F; + text-transform: uppercase; + font-size: 11px; + font-weight: bold; +} +.attributesContainer .form-group{ + margin-bottom: 9px; +} +.attributesContainer .form-control{ + border-color: #F0F5FC; + border-radius: 2px; + box-shadow: 0 2px 6px rgba(47, 83, 151, .1); + color: #103D73; + font-size: 13px; +} +.attributesContainer .form-control:focus{ + border-color: #66bfff; + box-shadow: 0 0 0 4px rgba(0,149,255,0.15); +} +.attributesContainer .form-control::placeholder{ + color: #CFD7E5; +} +.scrolll{ + max-height: 88.75vh; + overflow-y: auto; +} +.accordion > .card{ + margin-bottom: 0 !important; + border: 0; +} +.accordion > .card .card-header{ + margin: 0; + padding: 0; + background-color: #F4F9FE; + border: 0; + border-radius: 0; +} +.accordion > .card .card-body{ + padding-bottom: 10px !important; +} +.accordion .btn-link{ + padding: 0; + color: #C3CDDB; + font-weight: bold; + font-size: 13px; + text-transform: uppercase; + line-height: 38px; +} +.accordion .btn-link:hover{ + color: #103D73; + text-decoration: unset; +} +.accordion .card-header .btn-link[aria-expanded="true"]:after, +.accordion .card-header .btn-link[aria-expanded="false"]:after{ + margin-right: 9px; + font-family: 'FontAwesome'; + float: left; + font-weight: normal; + font-size: 12px; +} +.accordion .card-header .btn-link[aria-expanded="true"]:after{ + content: "\f078"; +} +.accordion .card-header .btn-link[aria-expanded="false"]:after{ + content: "\f054"; +} +.btn-addAttribute{ + width: 20px; + height: 20px; + background-image: url(/assets/img/icon-add.svg); + background-position: center center; + background-repeat: no-repeat; + vertical-align: sub; +} +.btn-addAttribute:hover{ + background-image: url(/assets/img/icon-add-hover.svg); +} +.btn-deleteAttribute{ + padding: 5px 10px; + background: #FFE6E7; + border: solid .5px #FFC9CB; + border-radius: 2px; + color: #FF6469; + font-size: 10px; + +} +.source-button{ + position: absolute; + z-index: 9999999; + top: 69px; + left: 50%; +} +/*jointjs paper*/ +/* #board-paper { + position: relative; + border: 1px solid gray; + display: inline-block; + background: transparent; + overflow: hidden; +} +#board-paper svg { + background: transparent; +} +#board-paper svg .link { + z-index: 2; +} +.html-element { + position: absolute; + background: #F4F9FE; + pointer-events: none; + -webkit-user-select: none; + z-index: 2; +} */ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html new file mode 100644 index 000000000..2a558517c --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.html @@ -0,0 +1,80 @@ +<header> + <div class="row m-0"> + <div class="col pl-0"> + <p class="logo mb-0"></p> + <nav aria-label="breadcrumb"> + <ol class="breadcrumb mb-0"> + <li class="breadcrumb-item"> + <a href="#">CBA Packages</a> + </li> + <li class="breadcrumb-item"> + <a href="#">Package Name</a> + </li> + <li class="breadcrumb-item active" aria-current="page"> + <p class="mb-0">Topology View</p> + </li> + </ol> + </nav> + </div> + <div class="col pr-0 text-right"> + <ul class="topology-actions"> + <li> + <div class="btn-group" role="group" aria-label="Basic example"> + <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom" + data-tooltip="Preview"> + <i class="fa fa-eye"></i> + </a> + <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom" + data-tooltip="Download"> + <i class="fa fa-download"></i> + </a> + <a href="#" role="button" aria-pressed="true" class="btn-topology-action float tooltip-bottom" + data-tooltip="Share"> + <i class="fa fa-share-square"></i> + </a> + </div> + </li> + <li> + <div class="dropdown"> + <input class="dropdown-toggle" type="text"> + <div class="dropdown-text">Save</div> + <ul class="dropdown-content"> + <li> + <a href="">Save</a> + </li> + <li> + <a href="">Save & Deploy</a> + </li> + </ul> + </div> + </li> + </ul> + + + </div> + </div> +</header> +<div class="source-button editBar"> + <div class="btn-group viewBtns" role="group"> + <button (click)="convertAndOpenInDesingerView()" type="button" class="btn btn-secondary topologySource">Designer</button> + <button type="button" + class="btn btn-secondary topologyView active">Scripting</button> + </div> +</div> +<ng-sidebar-container class="sidebar-container"> + <!-- Controller SideBar --> + <ng-sidebar [(opened)]="controllerSideBar" [sidebarClass]="'demo-sidebar controllerSidebar container-fluid'" + [mode]="'push'" #sidebarLeft> + <div class="row"> + + <h1 class="col-12">Actions</h1> + + + </div> + </ng-sidebar> +<div ng-sidebar-content id="board-paper"> + <ace-editor [(text)]="content" [mode]="'json'" [autoUpdateContent]="true" [durationBeforeCallback]="1000" + [theme]="'tomorrow_night_bright'" #editor style="height:500px"> + </ace-editor> + + </div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts new file mode 100644 index 000000000..34194e42f --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/source-view/source-view.component.ts @@ -0,0 +1,45 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { DesignerStore } from '../designer.store'; +import { PackageCreationUtils } from '../../package-creation/package-creation.utils'; +import { RouterLink, Router } from '@angular/router'; +import { Subject } from 'rxjs'; + +@Component({ + selector: 'app-designer-source-view', + templateUrl: './source-view.component.html', + styleUrls: ['./source-view.component.css'] +}) +export class DesignerSourceViewComponent implements OnInit, OnDestroy { + + content = ''; + lang = 'json'; + private controllerSideBar: boolean; + private ngUnsubscribe = new Subject(); + + constructor(private store: DesignerStore, + private packageCreationUtils: PackageCreationUtils, + private router: Router) { + this.controllerSideBar = true; + } + + ngOnInit() { + this.store.state$.subscribe( + state => { + console.log(state); + this.content = this.packageCreationUtils.transformToJson(state.template); + }); + + } + + convertAndOpenInDesingerView() { + // TODO validate json against scheme + console.log('convertAndOpenInDesingerView ...', this.content); + this.store.saveSourceContent(this.content); + this.router.navigateByUrl('/packages/designer'); + } + + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/package-dashboard.state.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/package-dashboard.state.ts index 638e68c06..b010f7a69 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/package-dashboard.state.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/model/package-dashboard.state.ts @@ -20,9 +20,21 @@ limitations under the License. */ -import {BluePrintDetailModel} from './BluePrint.detail.model'; +import { BluePrintDetailModel } from './BluePrint.detail.model'; +import { Mapping, Scripts, Template } from '../package-creation/mapping-models/CBAPacakge.model'; -export class PackageDashboardState { +export class PackageDashboardState { configuration: BluePrintDetailModel; + public scripts: Scripts; + public templates: Template; + public mapping: Mapping; + public imports: Map<string, string>; + + constructor() { + this.scripts = new Scripts(); + this.templates = new Template(); + this.mapping = new Mapping(); + this.imports = new Map<string, string>(); + } } 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 b44e844be..e1efc3c22 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 @@ -7,6 +7,7 @@ import { PackageCreationUtils } from '../package-creation.utils'; export class DesignerCreationMode extends PackageCreationModes { + // Refactor methods params to be in constructor level constructor() { super(); } @@ -15,6 +16,7 @@ export class DesignerCreationMode extends PackageCreationModes { this.addToscaMetaDataFile(cbaPackage.metaData); this.createDefinitionsFolder(cbaPackage, packageCreationUtils); this.addScriptsFolder(cbaPackage.scripts); + this.addTemplateFolder(cbaPackage); } private addScriptsFolder(scripts: Scripts) { @@ -23,28 +25,50 @@ export class DesignerCreationMode extends PackageCreationModes { }); } + private addTemplateFolder(cbaPackage: CBAPackage) { + // Create Template Files Folder + cbaPackage.templates.files.forEach((value, key) => { + FilesContent.putData(key, value); + }); + // Create Mapping Files Folder + cbaPackage.mapping.files.forEach((value, key) => { + FilesContent.putData(key, value); + }); + } + private createDefinitionsFolder(cbaPackage: CBAPackage, packageCreationUtils: PackageCreationUtils) { cbaPackage.definitions.imports.forEach((valueOfFile, key) => { FilesContent.putData(key, valueOfFile); }); - const filenameEntry = 'Definitions/vLB_CDS.json'; + const filenameEntry = 'Definitions/blueprint.json'; const vlbDefinition: VlbDefinition = new VlbDefinition(); const metadata: Metadata = new Metadata(); metadata.template_author = 'Shaaban Ebrahim'; metadata.template_name = cbaPackage.metaData.name; - metadata.template_tags = cbaPackage.metaData.tags; metadata.template_version = cbaPackage.metaData.version; metadata['author-email'] = 'shaaban.eltanany.ext@orange.com'; metadata['user-groups'] = 'test'; - cbaPackage.definitions.metaDataTab.mapOfCustomKey.forEach((customKeyValue, key) => { + 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 + ', '; + } + }); + metadata.template_tags = fullTags; vlbDefinition.metadata = metadata; const files: Import[] = []; cbaPackage.definitions.imports.forEach((valueOfFile, key) => { - files.push({ file: valueOfFile }); + files.push({ file: key }); }); console.log(vlbDefinition); vlbDefinition.imports = files; 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 2d234958c..8ccf0c39e 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 @@ -11,7 +11,7 @@ export abstract class PackageCreationModes { public static setEntryPoint(metaDataTab: MetaDataTabModel) { if (metaDataTab.mode.startsWith(ModeType.Designer)) { - metaDataTab.entryFileName = 'Definitions/vLB_CDS.json'; + metaDataTab.entryFileName = 'Definitions/blueprint.json'; } else { // TODO Not implemented metaDataTab.entryFileName = ''; @@ -31,6 +31,16 @@ export abstract class PackageCreationModes { } 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 + ', '; + } + } return 'TOSCA-Meta-File-Version: 1.0.0\n' + 'CSAR-Version: 1.0\n' + 'Created-By: Shaaban Ebrahim <shaaban.eltanany.ext@orange.con>\n' + @@ -38,7 +48,7 @@ export abstract class PackageCreationModes { 'Template-Name:' + metaDataTab.name + '\n' + 'Template-Version:' + metaDataTab.version + '\n' + 'Template-Type: ' + metaDataTab.mode + '\n' + - 'Template-Tags:' + metaDataTab.tags; + 'Template-Tags:' + tags; } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.html index 6fb1dcfd8..a67d12bcf 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.html @@ -1,5 +1,5 @@ <ace-editor [(text)]="dslDefinition.content" [mode]="'javascript'" [autoUpdateContent]="true" - [durationBeforeCallback]="1000" [theme]="'tomorrow_night_bright'" #editor style="height:300px;"> + [durationBeforeCallback]="1000" (textChanged)="textChanged($event)" [theme]="'tomorrow_night_bright'" #editor style="height:300px;"> </ace-editor> -<!-- <app-source-editor [lang]="'javascript'" (textChanged)="textChanged($event)" [(text)]="dslDefinition.content"></app-source-editor> -->
\ No newline at end of file +<!-- <app-source-editor [lang]="'javascript'" (textChanged)="textChanged($event)" [(text)]="dslDefinition.content"></app-source-editor> --> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.ts index 7171e730e..1297bc14e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/dsl-definitions-tab/dsl-definitions-tab.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit } from '@angular/core'; -import { DslDefinition } from '../mapping-models/CBAPacakge.model'; -import { PackageCreationStore } from '../package-creation.store'; +import {Component, OnInit} from '@angular/core'; +import {DslDefinition} from '../mapping-models/CBAPacakge.model'; +import {PackageCreationStore} from '../package-creation.store'; @Component({ selector: 'app-dsl-definitions-tab', @@ -16,11 +16,15 @@ export class DslDefinitionsTabComponent implements OnInit { } ngOnInit() { - this.packageCreationStore.changeDslDefinition(this.dslDefinition); + this.packageCreationStore.state$.subscribe(cbaPackage => { + if (cbaPackage && cbaPackage.definitions && cbaPackage.definitions.dslDefinition) { + this.dslDefinition.content = cbaPackage.definitions.dslDefinition.content; + } + }); } textChanged(event) { - console.log('event changed'); + this.packageCreationStore.changeDslDefinition(this.dslDefinition); } } 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 344e7f599..d80ed16b2 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 @@ -5,7 +5,7 @@ <a class="enter-link" href="#"><i class="icon-enter"></i></a> </div> <span class="import-container-span">Or you can also <a href="#" data-toggle="modal" - data-target="#exampleModal">Import File</a></span> + data-target="#importModal">Import File</a></span> </div> @@ -47,7 +47,7 @@ <div [id]="'id-'+mapIndex" class="collapse" [attr.aria-labelledby]="'head-'+mapIndex" data-parent="#accordion"> <div class="card-body"> - <ace-editor [(text)]="file.value" [mode]="'json'" [autoUpdateContent]="true" + <ace-editor [(text)]="file.value" (textChange)="textChanges($event,file.key)" [mode]="'json'" [autoUpdateContent]="true" [durationBeforeCallback]="1000" [theme]="'tomorrow_night_bright'" #editor style="height:300px;"> </ace-editor> @@ -82,12 +82,12 @@ </div> -<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" +<div class="modal fade" id="importModal" tabindex="-1" role="dialog" aria-labelledby="importModalLabel" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> - <h5 class="modal-title" id="exampleModalLabel">Import File</h5> + <h5 class="modal-title" id="importModalLabel">Import File</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> @@ -130,4 +130,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/imports-tab/imports-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.ts index 106fe3090..dc0cf7f3b 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.ts @@ -18,6 +18,8 @@ export class ImportsTabComponent implements OnInit { public files: NgxFileDropEntry[] = []; constructor(private packageCreationStore: PackageCreationStore, private packageCreationUtils: PackageCreationUtils) { + } + ngOnInit(): void { this.packageCreationStore.state$.subscribe(cbaPackage => { if (cbaPackage.definitions && cbaPackage.definitions.imports && cbaPackage.definitions.imports.size > 0) { this.definitionFiles = cbaPackage.definitions.imports; @@ -25,10 +27,6 @@ export class ImportsTabComponent implements OnInit { }); } - ngOnInit(): void { - // TODO - } - public dropped(files: NgxFileDropEntry[]) { this.files = files; for (const droppedFile of files) { @@ -74,4 +72,8 @@ export class ImportsTabComponent implements OnInit { resetTheUploadedFiles() { this.uploadedFiles = []; } + + textChanges(code: any, key: string) { + this.packageCreationStore.addDefinition(key, code); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/CBAPacakge.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/CBAPacakge.model.ts index d94a64ca3..a37339d90 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/CBAPacakge.model.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/CBAPacakge.model.ts @@ -1,8 +1,10 @@ import {MetaDataTabModel} from './metadata/MetaDataTab.model'; + + export class Definition { - public metaDataTab: MetaDataTabModel; + // public metaDataTab: MetaDataTabModel; public imports: Map<string, string>; public dslDefinition: DslDefinition; @@ -10,7 +12,7 @@ export class Definition { constructor() { this.imports = new Map<string, string>(); - this.metaDataTab = new MetaDataTabModel(); + // this.metaDataTab = new MetaDataTabModel(); this.dslDefinition = new DslDefinition(); } @@ -19,10 +21,10 @@ export class Definition { return this; } - public setMetaData(metaDataTab: MetaDataTabModel) { - this.metaDataTab = metaDataTab; - return this; - } + // public setMetaData(metaDataTab: MetaDataTabModel) { + // this.metaDataTab = metaDataTab; + // return this; + // } public setDslDefinition(dslDefinition: DslDefinition): Definition { this.dslDefinition = dslDefinition; @@ -34,6 +36,23 @@ export class DslDefinition { content: string; } +export class Base { + public files: Map<string, string>; + + constructor() { + this.files = new Map<string, string>(); + } + + public setContent(key: string, value: string) { + this.files.set(key, value); + return this; + } + + public getValue(key: string): string { + return this.files.get(key); + } +} + export class Scripts { public files: Map<string, string>; @@ -59,6 +78,13 @@ export class Template { this.files.set(key, value); return this; } + + public getValue(key: string): string { + return this.files.get(key); + } +} + +export class Mapping extends Base { } export class CBAPackage { @@ -67,6 +93,7 @@ export class CBAPackage { public definitions: Definition; public scripts: Scripts; public templates: Template; + public mapping: Mapping; constructor() { @@ -74,6 +101,7 @@ export class CBAPackage { this.scripts = new Scripts(); this.metaData = new MetaDataTabModel(); this.templates = new Template(); + this.mapping = new Mapping(); } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/ResourceDictionary.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/ResourceDictionary.model.ts new file mode 100644 index 000000000..558d1c7d0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/ResourceDictionary.model.ts @@ -0,0 +1,23 @@ +import { JsonObject, JsonProperty } from 'json2typescript'; + +@JsonObject('ResourceDictionary') +export class ResourceDictionary { + @JsonProperty() + name: string; + @JsonProperty('creation_date') + creationDate: string; + @JsonProperty('data_type') + dataType: string; + @JsonObject('definition') + definition?: any | null; + @JsonProperty('description') + description: string; + @JsonProperty('entry_schema') + entrySchema: string; + @JsonProperty('esource_dictionary_group') + resourceDictionaryGroup: string; + @JsonProperty('tags') + tags: string; + @JsonProperty('upadted_by') + updatedBy: string; +} 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 c4f3ee8bd..630baa1ac 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,5 +1,9 @@ import { Any, JsonObject, JsonProperty } from 'json2typescript'; +@JsonObject('topology_template') +export class TemplateTopology { + public content: string; +} @JsonObject export class VlbDefinition { @@ -10,14 +14,15 @@ export class VlbDefinition { imports: Import[]; // tslint:disable-next-line: variable-name dsl_definitions: DslContent; - // topology_template: TopologyTemplate; + // tslint:disable-next-line: variable-name + topology_template: TemplateTopology; } @JsonObject('dsl_definitions') export class DslContent { } - +// Refactor varaibles name and use JsonConverteri @JsonObject('metadata') export class Metadata { @JsonProperty('template_author') @@ -38,6 +43,8 @@ export class Metadata { @JsonProperty('dictionary_group') // tslint:disable-next-line:variable-name dictionary_group: string; + @JsonProperty('template_tags') + templateTags: string; /* @JsonProperty('custom_keys', {String}, false) 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 new file mode 100644 index 000000000..b4de578b9 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts @@ -0,0 +1,45 @@ +import { ResourceDictionary } from './ResourceDictionary.model'; +import { JsonObject, JsonProperty, JsonConvert } from 'json2typescript'; + +// Convert ResourceDictionary object to store Mapping. +export class MappingAdapter { + + constructor( + private resourceDictionary: ResourceDictionary, + private dependancies: Map<string, Array<string>>, + private dependanciesSource: Map<string, string>) { } + + ToMapping(): Mapping { + const mapping = new Mapping(); + mapping.name = this.resourceDictionary.name; + mapping.dictionaryName = this.resourceDictionary.name; + mapping.property = this.resourceDictionary.definition.property; + mapping.inputParam = false; + mapping.dictionarySource = this.dependanciesSource.get(mapping.name); + if (this.dependancies.get(mapping.name)) { + mapping.dependencies = this.dependancies.get(mapping.name); + } else { + mapping.dependencies = []; + } + mapping.version = 0; + return mapping; + } +} + +@JsonObject('Mapping') +export class Mapping { + @JsonProperty('name') + name: string; + @JsonProperty() + property: any; + @JsonProperty('input-param', Boolean) + inputParam: boolean; + @JsonProperty('dictionary-name') + dictionaryName: string; + @JsonProperty('dictionary-source') + dictionarySource: string; + @JsonProperty() + dependencies: string[]; + @JsonProperty() + version: number; +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/metadata/MetaDataTab.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/metadata/MetaDataTab.model.ts index df723d58f..7200e1210 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/metadata/MetaDataTab.model.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/metadata/MetaDataTab.model.ts @@ -26,10 +26,15 @@ export class MetaDataTabModel { name: string; description: string; version: string; - tags: string; mapOfCustomKey: Map<string, string> = new Map<string, string>(); entryFileName: string; templateName: string; + templateTags: Set<string> = new Set<string>(); + + setCustomKey(mapOfCustomKey: Map<string, string>) { + this.mapOfCustomKey = mapOfCustomKey; + return this; + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.css index e69de29bb..856f458f0 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.css +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.css @@ -0,0 +1,4 @@ +.fa-times-circle:hover { + cursor: pointer; + color: #1f64c3 +}
\ No newline at end of file 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 09393c403..89724be79 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 @@ -2,13 +2,13 @@ <div class="single-line"> <label class="label-name">Mode</label> <label name="trst" *ngFor="let mode of modes; let i = index"> - <input class="form-check-input" [(ngModel)]="metaDataTab.mode" type="radio" - name="exampleRadios" id="exampleRadios1" value={{mode.name}}> + <input class="form-check-input" [(ngModel)]="modeType" type="radio" name="radioMode" id="radioMode" + [value]="mode.name"> <span> - <i [className]="mode.style" aria-hidden="true" [id]="mode.name"></i> + <i [className]="mode.style" aria-hidden="true" [id]="mode.name"></i> {{mode.name}} - </span> + </span> </label> </div> <div class="single-line"> @@ -20,53 +20,50 @@ <option>Library Instance 3</option> <option>Library Instance 4</option> <option>Library Instance 5</option> - </select> + </select> </div> </div> </div> <div class="card creat-card"> - <div class="single-line-model error"> + <div class="single-line-model"> <label class="label-name">Name <span>*</span></label> <div class="label-input"> - <input type="input" - [(ngModel)]="metaDataTab.name" placeholder="Topology name.vLB.CDS"> + <input type="input" [readOnly]="!packageNameAndVersionEnables" [(ngModel)]="metaDataTab.name" + placeholder="Topology name.vLB.CDS"> </div> - <div class="model-note-container error-message"> - Package name already exists with this version. Please enter a different name or enter different version number. - </div> + <!--<div class="model-note-container error-message"> + Package name already exists with this version. Please enter a different name or enter different version + number. + </div>--> </div> - + <div class="single-line-model"> <label class="label-name">Version <span>*</span></label> <div class="label-input"> - <input type="input" [(ngModel)]="metaDataTab.version" - (input)="validatePackageNameAndVersion()" - placeholder="Example: 1.0.0"> + <input type="input" [readOnly]="!packageNameAndVersionEnables" [(ngModel)]="metaDataTab.version" + (input)="validatePackageNameAndVersion()" placeholder="Example: 1.0.0"> </div> <div class="model-note-container error-message">{{errorMessage}}</div> </div> <div class="single-line-model"> <label class="label-name">Description</label> <div class="label-input"> - <input type="input" [(ngModel)]="metaDataTab.description" - placeholder="Descripe the package"> + <input type="input" [(ngModel)]="metaDataTab.description" placeholder="Descripe the package"> </div> </div> - + <div class="single-line-model"> <label class="label-name">tags</label> <div class="label-input"> - <input type="input" [(ngModel)]="metaDataTab.tags" - placeholder="Ex., vDNS-CDS"> - + <input type="input" (keyup.enter)="addTag($event)" [(ngModel)]="metaDataTab.tags" + placeholder="Ex., vDNS-CDS"> + </div> <div class="model-note-container tag-notes">Seprate tags with comma or space</div> <div class="model-note-container tages-container"> - <span class="single-tage">vDNS-CDS <a href="#"> <i class="fa fa-times-circle"></i></a></span> - <span class="single-tage">vDNS-CDS <a href="#"> <i class="fa fa-times-circle"></i></a></span> - <span class="single-tage">vDNS-CDS <a href="#"> <i class="fa fa-times-circle"></i></a></span> - <span class="single-tage">vDNS-CDS <a href="#"> <i class="fa fa-times-circle"></i></a></span> + <span *ngFor="let tag of tags" class="single-tage">{{tag}} <i (click)="removeTag(tag)" + class="fa fa-times-circle"></i></span> </div> </div> </div> @@ -75,59 +72,48 @@ <div class="card creat-card"> <div class="single-line"> <h5 class="label-name"> - Custom key + Custom key </h5> </div> - <div class="single-custom-key"> - <div class="single-line-custom-key"> - <label class="label-name"><span>1-</span> Name</label> - <div class="label-input"> - <input name="key" type="input" placeholder="Enter name"> + <div *ngFor="let map of customKeysMap | keyvalue; let i=index" class="single-custom-key"> + <div class="single-line-custom-key"> + <label class="label-name"><span>{{i + 1}}-</span> Name</label> + <div class="label-input"> + <input value="{{map.key}}" name="key" type="input" placeholder="Enter name"> + </div> </div> - </div> - <div class="single-line-custom-key"> - <label class="label-name">Value</label> - <div class="label-input"> - <input name="value" type="input" - placeholder="Enter value"> + <div class="single-line-custom-key"> + <label class="label-name">Value</label> + <div class="label-input"> + <input value="{{map.value}}" name="value" type="input" placeholder="Enter value"> + </div> </div> - </div> - <div class="single-line-custom-key-delete"><button class="custom-key-delete"><i aria-hidden="true" class="icon-delete"></i></button></div> - </div> - <div class="single-custom-key"> - <div class="single-line-custom-key"> - <label class="label-name"><span>2-</span> Name</label> - <div class="label-input"> - <input name="key" type="input" placeholder="Enter name"> - </div> - </div> - <div class="single-line-custom-key"> - <label class="label-name">Value</label> - <div class="label-input"> - <input name="value" type="input" - placeholder="Enter value"> + <div class="single-line-custom-key-delete"> + <button (click)="removeKey($event,map.key)" class="custom-key-delete"><i aria-hidden="true" + class="icon-delete"></i></button> </div> </div> - <div class="single-line-custom-key-delete"><button class="custom-key-delete"><i aria-hidden="true" class="icon-delete"></i></button></div> - </div> - <div class="single-custom-key"> - <div class="single-line-custom-key"> - <label class="label-name"><span>3-</span> Name</label> - <div class="label-input"> - <input name="key" type="input" placeholder="Enter name"> + <div class="single-custom-key"> + <div class="single-line-custom-key"> + <label class="label-name"><span>{{customKeysMap.size + 1}}.</span> Name</label> + <div class="label-input"> + <input (keyup.enter)="addCustomKey()" name="key" type="input" class="mapKey" + placeholder="Enter name"> + </div> </div> - </div> - <div class="single-line-custom-key"> - <label class="label-name">Value</label> - <div class="label-input"> - <input name="value" type="input" - placeholder="Enter value"> + <div class="single-line-custom-key"> + <label class="label-name">Value</label> + <div class="label-input"> + <input (keyup.enter)="addCustomKey()" class="mapValue" name="value" type="input" + placeholder="Enter value"> + </div> </div> + <!-- <div class="single-line-custom-key-delete"><button (click)="removeKey($event)" + class="custom-key-delete"><i aria-hidden="true" class="icon-delete"></i></button></div> --> </div> - </div> </div> </div> -</div> +</div>
\ No newline at end of file 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 97040ee90..3a9b7b880 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 @@ -1,7 +1,8 @@ -import {Component, OnInit} from '@angular/core'; -import {PackageCreationService} from '../package-creation.service'; -import {MetaDataTabModel} from '../mapping-models/metadata/MetaDataTab.model'; -import {PackageCreationStore} from '../package-creation.store'; +import { Component, OnInit } from '@angular/core'; +import { PackageCreationService } from '../package-creation.service'; +import { MetaDataTabModel } from '../mapping-models/metadata/MetaDataTab.model'; +import { PackageCreationStore } from '../package-creation.store'; +import { ActivatedRoute } from '@angular/router'; @Component({ @@ -10,21 +11,90 @@ import {PackageCreationStore} from '../package-creation.store'; styleUrls: ['./metadata-tab.component.css'] }) export class MetadataTabComponent implements OnInit { - + packageNameAndVersionEnables = true; counter = 0; - modes: object[] = [ - {name: 'Designer Mode', style: 'mode-icon icon-designer-mode'}, - {name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode'}, - {name: 'Generic Script Mode', style: 'mode-icon icon-generic-script-mode'}]; + tags = new Set<string>(); + customKeysMap = new Map(); + modes: any[] = [ + { name: 'Designer Mode', style: 'mode-icon icon-designer-mode' }]; + /* {name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode'}, + {name: 'Generic Script Mode', style: 'mode-icon icon-generic-script-mode'}];*/ + modeType = this.modes[0].name; private metaDataTab: MetaDataTabModel = new MetaDataTabModel(); private errorMessage: string; - constructor(private packageCreationService: PackageCreationService, private packageCreationStore: PackageCreationStore) { + constructor( + private route: ActivatedRoute, + private packageCreationService: PackageCreationService, + private packageCreationStore: PackageCreationStore + ) { } ngOnInit() { - this.packageCreationStore.changeMetaData(this.metaDataTab); + this.metaDataTab.templateTags = this.tags; + this.metaDataTab.mapOfCustomKey = this.customKeysMap; + this.metaDataTab.mode = this.modeType; + + const id = this.route.snapshot.paramMap.get('id'); + id ? this.packageNameAndVersionEnables = false : + this.packageNameAndVersionEnables = true; + this.packageCreationStore.state$.subscribe(element => { + + if (element && element.metaData) { + + this.metaDataTab.name = element.metaData.name; + this.metaDataTab.version = element.metaData.version; + this.metaDataTab.description = element.metaData.description; + this.tags = element.metaData.templateTags; + 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; + } + + this.customKeysMap = element.metaData.mapOfCustomKey; + // this.tags = element.metaData.templateTags; + + } + }); + } + + removeTag(value) { + // console.log(event); + this.tags.delete(value); + } + + addTag(event) { + const value = event.target.value; + console.log(value); + if (value && value.trim().length > 0) { + event.target.value = ''; + this.tags.add(value); + } + } + + removeKey(event, key) { + console.log(event); + this.customKeysMap.delete(key); + } + + addCustomKey() { + // tslint:disable-next-line: no-string-literal + const key = document.getElementsByClassName('mapKey')[0]; + // tslint:disable-next-line: no-string-literal + const value = document.getElementsByClassName('mapValue')[0]; + + // tslint:disable-next-line: no-string-literal + if (key['value'] && value['value']) { + // tslint:disable-next-line: no-string-literal + this.customKeysMap.set(key['value'], value['value']); + // tslint:disable-next-line: no-string-literal + key['value'] = ''; + // tslint:disable-next-line: no-string-literal + value['value'] = ''; + } } validatePackageNameAndVersion() { @@ -39,4 +109,8 @@ export class MetadataTabComponent implements OnInit { } } + + saveMetaDataToStore() { + this.packageCreationStore.changeMetaData(this.metaDataTab); + } } 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 906904855..67beca2a1 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 @@ -2,21 +2,21 @@ <div class="new-wrapper"> <div class="container-fluid main-container"> - <header class="page-title"> - <div class="row"> - <h2 class="col m-0"> - <ul class="breadcrumb-header"> - <li>CBA Packages</li> - <li>Package Name</li> - </ul> - </h2> - <div class="col d-flex justify-content-end header-button-save"> - <button class="float btn btn-sm btn-outline-secondary" disabled>Discard Changes</button> - <button class="float btn btn-sm btn-primary" (click)="saveBluePrint()">Save</button> + <header class="page-title"> + <div class="row"> + <h2 class="col m-0"> + <ul class="breadcrumb-header"> + <li><a routerLink="/packages">CBA Packages</a></li> + <li>Package Name</li> + </ul> + </h2> + <div class="col d-flex justify-content-end header-button-save"> + <button class="float btn btn-sm btn-outline-secondary" (click)="goBackToDashBorad()">Discard + Changes</button> + <button class="float btn btn-sm btn-primary" (click)="saveBluePrint()">Save</button> + </div> </div> - </div> - </header> - + </header> <div class="container-fluid body-container"> @@ -39,93 +39,23 @@ </a> </div> - <div class="card creat-card view-package-container"> - <div class="row"> - <div class="col-8"> - <div class="row"> - <div class="col d-flex"> - <i class="package-type-icon icon-designer-mode"></i> - <div class="package-name-container"> - <div class="row"> - <div class="col-12 package-name deployed"> - Package Name - <span>.vLB.CDS</span> - <i class="icon-deploy"></i> - </div> - <div class="col-12 package-description"> - Last modified Oct 4, 2019 03:48 PM By Ahmed Abbas - </div> - </div> - <!-- <div class="row"> - <div class="col-4"> - <div class="package-view-title">Author Name</div> - <p>Abdelmuhaimen Seaudi</p> - </div> - <div class="col-4"> - <div class="package-view-title">Author Email</div> - <p>abdelmuhaimen.seaudi@orange.com</p> - </div> - <div class="col-4"> - <div class="package-view-title">Contributions</div> - <ul class="package-contributers"> - <li> - <button type="button" class="border-fade" data-toggle="tooltip" - data-placement="bottom" - title="User name"> - <img src="/assets/img/img-user1.jpeg"> - </button> - </li> - <li> - <button type="button" data-toggle="tooltip" data-placement="bottom" - title="User name"> - <img src="/assets/img/img-user2.jpg"> - </button> - </li> - <li> - <button type="button" data-toggle="tooltip" data-placement="bottom" - title="User name"> - <img src="/assets/img/img-user3.jpg"> - </button> - </li> - <li> - <a href="">5 contributors</a> - </li> - </ul> - </div> - </div> --> - </div> - </div> - </div> - </div> - <div class="col-4 package-view-button"> - <button class="btn btn-sm btn-outline-secondary"><i class="fa fa-play-circle"></i> Deploy</button> - <button class="btn btn-sm btn-primary">Designer Mode</button> - </div> - </div> - - </div> <nav class="row"> <!--Nav Tabs--> <div class="col"> <div class="nav nav-tabs " id="nav-tab" role="tablist"> <a class="nav-item nav-link active" id="nav-metadata-tab" data-toggle="tab" - href="#nav-metadata" - role="tab" aria-controls="nav-metadata" - aria-selected="true">METADATA</a> + href="#nav-metadata" role="tab" aria-controls="nav-metadata" aria-selected="false" + autofocus #nameit (focusout)="test()">METADATA</a> <a 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 & MAPPING</a> + role="tab" aria-controls="nav-template" aria-selected="false">TEMPLATE & MAPPING</a> <a class="nav-item nav-link" id="nav-scripts-tab" data-toggle="tab" href="#nav-scripts" - role="tab" aria-controls="nav-scripts" - aria-selected="false">SCRIPTS</a> + role="tab" aria-controls="nav-scripts" aria-selected="false">SCRIPTS</a> <a class="nav-item nav-link" id="nav-imports-tab" data-toggle="tab" href="#nav-imports" - role="tab" aria-controls="nav-imports" - aria-selected="false">IMPORTS</a> + role="tab" aria-controls="nav-imports" aria-selected="false">IMPORTS</a> <a class="nav-item nav-link" id="nav-authentication-tab" data-toggle="tab" - href="#nav-authentication" - role="tab" aria-controls="nav-authentication" - aria-selected="false">EXTERNAL SYSTEM AUTHENTICATION PROPERTIES</a> + href="#nav-authentication" role="tab" aria-controls="nav-authentication" + aria-selected="false">EXTERNAL SYSTEM AUTHENTICATION PROPERTIES</a> </div> </div> @@ -134,24 +64,24 @@ <div class="col"> <div class="tab-content" id="nav-tabContent"> <div class="tab-pane fade show active" id="nav-metadata" role="tabpanel" - aria-labelledby="nav-metadata-tab"> + aria-labelledby="nav-metadata-tab"> <app-metadata-tab></app-metadata-tab> </div> <div class="tab-pane fade" id="nav-template" role="tabpanel" - aria-labelledby="nav-template-tab"> + aria-labelledby="nav-template-tab"> <app-template-mapping></app-template-mapping> </div> <div class="tab-pane fade" id="nav-scripts" role="tabpanel" - aria-labelledby="nav-scripts-tab"> + aria-labelledby="nav-scripts-tab"> <app-scripts-tab></app-scripts-tab> </div> <div class="tab-pane fade" id="nav-imports" role="tabpanel" - aria-labelledby="nav-imports-tab"> + aria-labelledby="nav-imports-tab"> <app-imports-tab></app-imports-tab> </div> <div class="tab-pane fade" id="nav-authentication" role="tabpanel" - aria-labelledby="nav-authentication-tab"> + aria-labelledby="nav-authentication-tab"> <div class="card creat-card"> <div class="editor-container"> <app-dsl-definitions-tab></app-dsl-definitions-tab> @@ -163,5 +93,5 @@ </div> </div> </div> -</div> -</div> + </div> +</div>
\ No newline at end of file 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 58c04e83e..42db2688e 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,15 +19,17 @@ limitations under the License. ============LICENSE_END============================================ */ -import { Component, OnInit } from '@angular/core'; -import { FilesContent, FolderNodeElement, MetaDataTabModel } from './mapping-models/metadata/MetaDataTab.model'; +import {Component, ElementRef, 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 {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'; @Component({ @@ -36,24 +38,33 @@ import { PackageCreationUtils } from './package-creation.utils'; styleUrls: ['./package-creation.component.css'] }) export class PackageCreationComponent implements OnInit { + + // adding initial referencing to designer mode + + + constructor(private packageCreationStore: PackageCreationStore, + private packageCreationUtils: PackageCreationUtils, + private router: Router) { + } + 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'}]; private metaDataTab: MetaDataTabModel = new MetaDataTabModel(); private folder: FolderNodeElement = new FolderNodeElement(); private zipFile: JSZip = new JSZip(); private filesData: any = []; private definition: Definition = new Definition(); - // adding initial referencing to designer mode + @ViewChild(MetadataTabComponent, {static: false}) + private metadataTabComponent: MetadataTabComponent; - - constructor(private packageCreationStore: PackageCreationStore, private packageCreationUtils: PackageCreationUtils) { - } + @ViewChild('nameit', {static: true}) + private elementRef: ElementRef; ngOnInit() { - + this.elementRef.nativeElement.focus(); } saveBluePrint() { @@ -76,9 +87,10 @@ export class PackageCreationComponent implements OnInit { saveBluePrintToDataBase() { this.create(); - this.zipFile.generateAsync({ type: 'blob' }) + this.zipFile.generateAsync({type: 'blob'}) .then(blob => { this.packageCreationStore.saveBluePrint(blob); + this.router.navigate(['/packages']); }); } @@ -88,23 +100,14 @@ export class PackageCreationComponent implements OnInit { this.zipFile.folder(key.split('/')[0]); this.zipFile.file(key, value); }); - /*this.folder.TREE_DATA.forEach((path) => { - const name = path.name; - if (path.children) { - this.zipFile.folder(name); - path.children.forEach(children => { - const name2 = children.name; - if (FilesContent.getMapOfFilesNamesAndContent().has(name2)) { - this.zipFile.file(name + '/' + name2, FilesContent.getMapOfFilesNamesAndContent().get(name2)); - } else { - // this.zipFile.file(name2, FilesContent.getMapOfFilesNamesAndContent().get(name2)); - } - - }); - - } - });*/ + } + test() { + this.metadataTabComponent.saveMetaDataToStore(); + } + goBackToDashBorad() { + this.router.navigate(['/packages']); + } } 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 36da6a42f..494c9e555 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 @@ -23,9 +23,10 @@ import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import {ApiService} from '../../../../common/core/services/api.service'; -import {BlueprintURLs} from '../../../../common/constants/app-constants'; +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'; @Injectable({ providedIn: 'root' @@ -62,4 +63,7 @@ export class PackageCreationService { }); } + getTemplateAndMapping(variables: string[]): Observable<ResourceDictionary[]> { + return this.api.post(ResourceDictionaryURLs.searchResourceDictionaryByNames, variables); + } } 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 3dae2e570..0808223cd 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 @@ -19,14 +19,15 @@ limitations under the License. ============LICENSE_END============================================ */ -import {Injectable} from '@angular/core'; +import { Injectable } from '@angular/core'; -import {Store} from '../../../../common/core/stores/Store'; +import { Store } from '../../../../common/core/stores/Store'; -import {CBAPackage, DslDefinition} from './mapping-models/CBAPacakge.model'; -import {PackageCreationService} from './package-creation.service'; -import {FolderNodeElement, MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; -import * as JSZip from 'jszip'; +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'; @Injectable({ @@ -34,8 +35,6 @@ import * as JSZip from 'jszip'; }) export class PackageCreationStore extends Store<CBAPackage> { - private folder: FolderNodeElement = new FolderNodeElement(); - private zipFile: JSZip = new JSZip(); constructor(private packageCreationService: PackageCreationService) { super(new CBAPackage()); @@ -49,6 +48,13 @@ export class PackageCreationStore extends Store<CBAPackage> { }); } + setCustomKeys(mapOfCustomKey: Map<string, string>) { + this.setState({ + ...this.state, + metaData: this.state.metaData.setCustomKey(mapOfCustomKey) + }); + } + changeDslDefinition(dslDefinition: DslDefinition) { this.setState({ @@ -67,7 +73,6 @@ export class PackageCreationStore extends Store<CBAPackage> { } addScripts(name: string, content: string) { - this.setState({ ...this.state, scripts: this.state.scripts.setScripts(name, content) @@ -93,4 +98,19 @@ export class PackageCreationStore extends Store<CBAPackage> { templates: this.state.templates.setTemplates(filePath, fileContent) }); } + + addMapping(filePath: string, fileContent: string) { + this.setState({ + ...this.state, + mapping: this.state.mapping.setContent(filePath, fileContent) + }); + } + + getTemplateAndMapping(variables: string[]): Observable<ResourceDictionary[]> { + return this.packageCreationService.getTemplateAndMapping(variables); + } + + clear() { + this.setState(new CBAPackage()); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.html index 824152035..5dd68ed72 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.html @@ -24,15 +24,16 @@ aria-expanded="false" class="btn btn-link collapsed" data-toggle="collapse"> <i class="icon-file-code"></i> {{file.key}} </button> - <a (click)="removeFile(mapIndex)" class="accordion-delete"><i class="icon-delete"></i></a> + <a (click)="removeFile(file.key,mapIndex)" class="accordion-delete"><i + class="icon-delete"></i></a> </h5> </div> <div [attr.aria-labelledby]="'head-script-'+mapIndex" [id]="'id-script-'+mapIndex" class="collapse" data-parent="#accordion-script"> <div class="card-body"> - <ace-editor [(text)]="file.value" [mode]="'kotlin'" [autoUpdateContent]="true" - [durationBeforeCallback]="1000" [theme]="'tomorrow_night_bright'" #editor - style="height:300px;"> + <ace-editor [(text)]="file.value" (textChange)="textChanges($event,file.key)" [mode]="'kotlin'" + [autoUpdateContent]="true" [durationBeforeCallback]="1000" [theme]="'tomorrow_night_bright'" + #editor style="height:300px;"> </ace-editor> </div> </div> @@ -54,7 +55,7 @@ </button> </div> <div class="modal-body"> - <ngx-file-drop accept=".kt" (onFileDrop)="dropped($event)" (onFileLeave)="fileLeave($event)" + <ngx-file-drop accept=".kt,.py" (onFileDrop)="dropped($event)" (onFileLeave)="fileLeave($event)" (onFileOver)="fileOver($event)" dropZoneLabel="Drop files here"> <ng-template let-openFileSelector="openFileSelector" ngx-file-drop-content-tmp> <div class="folder-upload"> @@ -68,7 +69,7 @@ Files </button> </div> - <div class="folder-upload-type">Allowed file type: Kotlin(Kt)</div> + <div class="folder-upload-type">Allowed file type: Kotlin(kt), Python(py)</div> </ng-template> </ngx-file-drop> <div *ngFor="let item of uploadedFiles; let i=index" class="upload-table"> 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 eee291bba..5387489a2 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 @@ -1,7 +1,6 @@ import { Component, OnInit } from '@angular/core'; import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop'; import { PackageCreationStore } from '../package-creation.store'; -import { PackageCreationUtils } from '../package-creation.utils'; import 'ace-builds/src-noconflict/ace'; import 'ace-builds/webpack-resolver'; @@ -17,7 +16,12 @@ export class ScriptsTabComponent implements OnInit { public files: NgxFileDropEntry[] = []; private fileNames: Set<string> = new Set(); - constructor(private packageCreationStore: PackageCreationStore, private packageCreationUtils: PackageCreationUtils) { + constructor( + private packageCreationStore: PackageCreationStore, + ) { } + + + ngOnInit() { this.packageCreationStore.state$.subscribe(cbaPackage => { if (cbaPackage.scripts && cbaPackage.scripts.files && cbaPackage.scripts.files.size > 0) { this.scriptsFiles = cbaPackage.scripts.files; @@ -25,10 +29,6 @@ export class ScriptsTabComponent implements OnInit { }); } - - ngOnInit() { - } - public dropped(files: NgxFileDropEntry[]) { this.files = files; for (const droppedFile of files) { @@ -43,11 +43,18 @@ export class ScriptsTabComponent implements OnInit { } } - removeFile(fileIndex: number) { - console.log(this.uploadedFiles[fileIndex]); - const filename = 'Scripts/' + this.uploadedFiles[fileIndex].name; - this.packageCreationStore.removeFileFromState(filename); - this.uploadedFiles.splice(fileIndex, 1); + removeFile(filePath: string, FileIndex: number) { + const filename = filePath.split('/')[2] || ''; + // const filename = 'Scripts/' + this.getFileType(this.uploadedFiles[fileIndex].name) + '/' + this.uploadedFiles[fileIndex].name; + this.packageCreationStore.removeFileFromState(filePath); + // remove from upload files array + // tslint:disable-next-line: prefer-for-of + for (let i = 0; i < this.uploadedFiles.length; i++) { + if (this.uploadedFiles[i].name === filename) { + this.uploadedFiles.splice(i, 1); + break; + } + } } public fileOver(event) { @@ -64,7 +71,7 @@ export class ScriptsTabComponent implements OnInit { droppedFile.file((file: File) => { const fileReader = new FileReader(); fileReader.onload = (e) => { - this.packageCreationStore.addScripts('Scripts/' + droppedFile.name, + this.packageCreationStore.addScripts('Scripts/' + this.getFileType(droppedFile.name) + '/' + droppedFile.name, fileReader.result.toString()); }; fileReader.readAsText(file); @@ -73,7 +80,22 @@ export class ScriptsTabComponent implements OnInit { } } + getFileType(filename: string): string { + let fileType = ''; + const fileExtension = filename.substring(filename.lastIndexOf('.') + 1); + if (fileExtension === 'py') { + fileType = 'python'; + } else if (fileExtension === 'kt') { + fileType = 'kotlin'; + } + return fileType; + } + resetTheUploadedFiles() { this.uploadedFiles = []; } + + textChanges(code: any, key: string) { + this.packageCreationStore.addScripts(key, code); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/TemplateAndMapping.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/TemplateAndMapping.ts new file mode 100644 index 000000000..abfe4982b --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/TemplateAndMapping.ts @@ -0,0 +1,7 @@ +export class TemplateAndMapping { + isTemplate = false; + isMapping = false; + + constructor() { + } +} 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 3c92bc7c7..8a43b010b 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 @@ -17,7 +17,7 @@ <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"> + aria-controls="collapseOne"> 1. Create Template </button> @@ -29,25 +29,24 @@ <div class="single-line"> <label class="label-name">Template Type</label> <div class="label-input"> - <label name="trst"> - <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" - value=Velcoity> - + <label name="trst" (click)="allowedExt=['.vtl']"> + <input class="form-check-input" [(ngModel)]="templateExt" type="radio" + name="exampleRadios" id="exampleRadios1" value=Velcoity> <span> Velcoity </span> </label> - <label name="trst"> - <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" - value=Velcoity> + <label name="trst" (click)="allowedExt=['.j2','.jinja2']"> + <input class="form-check-input" [(ngModel)]="templateExt" type="radio" + name="exampleRadios" id="exampleRadios1" value=Jinja> <span> Jinja </span> </label> - <label name="trst"> - <input class="form-check-input" type="radio" name="exampleRadios" id="exampleRadios1" - value=Velcoity> + <label name="trst" (click)="allowedExt=['.kt']"> + <input class="form-check-input" [(ngModel)]="templateExt" type="radio" + name="exampleRadios" id="exampleRadios1" value=Kotlin> <span> Kotlin @@ -55,12 +54,13 @@ </label> </div> </div> - <div class="create-template-import">Use the editor to add parameters or you can also <a href="#" - data-toggle="modal" - data-target="#exampleModal">Import - File</a></div> + <div class="create-template-import">Use the editor to add parameters or you can also + <a href="#" data-toggle="modal" (click)="allowedExt=[getFileExtension()]" + data-target="#templateModal">Import + File</a></div> <div class="editor-container"> - <app-dsl-definitions-tab></app-dsl-definitions-tab> + <app-source-editor (textChange)="textChanges($event,templateInfo.fileName)" + [(text)]="templateFileContent"></app-source-editor> </div> </div> </div> @@ -69,7 +69,7 @@ <div class="card-header" id="headingTwo"> <h5 class="mb-0"> <button class="btn btn-link collapsed" data-toggle="collapse" data-target="#collapseTwo" - aria-expanded="false" aria-controls="collapseTwo"> + aria-expanded="false" aria-controls="collapseTwo"> 2. Manage Mapping </button> </h5> @@ -78,14 +78,15 @@ <div class="card-body"> <h6 class="text-center">Select a source to load config parameters</h6> <div class="text-center"> - <a href="#" class="mapping-source-load"> + <a href="#" (click)="getMappingTableFromTemplate($event)" class="mapping-source-load"> <i class="icon-current-template"></i> - <br/> + <br /> <span>Use Current Template Instance</span> </a> - <a href="#" data-toggle="modal" data-target="#exampleModal" class="mapping-source-load"> + <a href="#" (click)="allowedExt=['.csv']" data-toggle="modal" data-target="#templateModal" + class="mapping-source-load"> <i class="icon-Upload-attribute"></i> - <br/> + <br /> <div>Upload attribute list</div> <div class="source-load-note">(Should be comma delimited file)</div> </a> @@ -101,37 +102,121 @@ </div> </div> + <div id="mapping-table" [hidden]="resourceDictionaryRes?.length == 0" class="mx-4 my-2"> + <table datatable [dtOptions]="dtOptions" [dtTrigger]="dtTrigger" class="row-border hover"> + <thead> + <tr> + <th>Required</th> + <th>Parameter Name</th> + <th>Dictionary Name</th> + <th>Dictionary Source</th> + <th>Dependancies</th> + <th>Default</th> + <th>Data Type</th> + <th>Entry Schema</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let dict of resourceDictionaryRes"> + <td> + <i *ngIf="dict.definition?.property?.required" class="fa fa-check-square mx-2"></i> + <i *ngIf="!dict.definition?.property?.required" class="fa fa-square mx-2"></i> + </td> + <td>{{ dict.name }}</td> + <td>{{ dict.name }}</td> + <td> + <select class="custom-select" (click)="selectSource(dict,$event)"> + <option *ngFor="let val of dict.definition.sources | keyvalue"> + {{initMap(dict.name,val)}} + </option> + + </select> + </td> + <td> + <!-- <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>{{ dict.definition?.property?.type }}</td> + <td>{{ dict.definition?.property['entry_schema'] }}</td> + </tr> + </tbody> + </table> + </div> + + <div id="mapping-table" [hidden]="mappingRes?.length == 0" class="mx-4 my-2"> + <table datatable [dtOptions]="dtOptions" [dtTrigger]="resTableDtTrigger" class="row-border hover"> + <thead> + <tr> + <th>Required</th> + <th>Parameter Name</th> + <th>Dictionary Name</th> + <th>Dictionary Source</th> + <th>Dependancies</th> + <th>Default</th> + <th>Data Type</th> + <th>Entry Schema</th> + </tr> + </thead> + <tbody> + <tr *ngFor="let dict of mappingRes"> + <td> + <i *ngIf="dict.definition?.property?.required" class="fa fa-check-square mx-2"></i> + <i *ngIf="!dict.definition?.property?.required" class="fa fa-square mx-2"></i> + </td> + <td>{{ dict['name'] }}</td> + <td>{{ dict['name'] }}</td> + <td> + <input type="text" class="form-control" [value]="dict['dictionary-source']" + disabled> + + </td> + <td> + <input type="text" class="form-control" [value]="dict['dependencies']" disabled> + <!-- {{ dict.definition.sources }} --> + </td> + <td>{{ dict['property']['default'] }}</td> + <td>{{ dict['property']['type'] }}</td> + <td>{{ dict['property']['entry_schema'] }}</td> + </tr> + </tbody> + </table> + </div> </div> </div> - <div class="template-mapping-action"> <button class="btn btn-sm btn-outline-secondary">Cancel</button> - <button class="btn btn-sm btn-primary">Finish</button> + <button (click)="saveToStore()" class="btn btn-sm btn-primary">Finish</button> </div> </div> </div> -<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" - aria-hidden="true"> +<div class="modal fade" id="templateModal" tabindex="-1" role="dialog" aria-labelledby="templateModalLabel" + aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> - <h5 class="modal-title" id="exampleModalLabel">Import File</h5> + <h5 class="modal-title" id="templateModalLabel">Import File</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> - <ngx-file-drop dropZoneLabel="Drop files here" (onFileDrop)="dropped($event)" - (onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)"> + <ngx-file-drop [accept]="allowedExt" dropZoneLabel="Drop files here" (onFileDrop)="dropped($event)" + (onFileOver)="fileOver($event)" (onFileLeave)="fileLeave($event)"> <ng-template ngx-file-drop-content-tmp let-openFileSelector="openFileSelector"> <div class="folder-upload"> - <img src="assets/img/folder-upload.svg"/> + <img src="assets/img/folder-upload.svg" /> </div> <div class="folder-upload-text"> Drag & Drop file @@ -141,15 +226,17 @@ Files </button> </div> - <div class="folder-upload-type">Allowed file type: json</div> + <div class="folder-upload-type">Allowed file type: + {{allowedExt}} + </div> </ng-template> </ngx-file-drop> <div class="upload-table" *ngFor="let item of uploadedFiles; let i=index"> <table class="table"> <thead> - <tr> - <th>Name : {{ item.name }}</th> - </tr> + <tr> + <th>Name : {{ item.name }}</th> + </tr> </thead> </table> </div> @@ -157,13 +244,13 @@ <div class="modal-footer"> <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal" - (click)="resetTheUploadedFiles()">Cancel + (click)="resetTheUploadedFiles()">Cancel </button> <button type="button" class="btn btn-sm btn-primary" data-dismiss="modal" - (click)="setFilesToStore()"> + (click)="uploadFile();openListView()"> Import </button> </div> </div> </div> -</div> +</div>
\ No newline at end of file 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 752bd510b..628d963ce 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 @@ -1,24 +1,121 @@ -import {Component, EventEmitter, OnInit, Output} from '@angular/core'; -import {FileSystemFileEntry, NgxFileDropEntry} from 'ngx-file-drop'; -import {PackageCreationStore} from '../../package-creation.store'; +import { Component, EventEmitter, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; +import { FileSystemFileEntry, NgxFileDropEntry } from 'ngx-file-drop'; +import { PackageCreationStore } from '../../package-creation.store'; +import { TemplateInfo, TemplateStore } from '../../template.store'; +import { Subject } from 'rxjs'; +import { ResourceDictionary } from '../../mapping-models/ResourceDictionary.model'; +import { DataTableDirective } from 'angular-datatables'; +import { Mapping, MappingAdapter } from '../../mapping-models/mappingAdapter.model'; +import { PackageCreationUtils } from '../../package-creation.utils'; +import { JsonConvert } from 'json2typescript'; @Component({ selector: 'app-templ-mapp-creation', templateUrl: './templ-mapp-creation.component.html', styleUrls: ['./templ-mapp-creation.component.css'] }) -export class TemplMappCreationComponent implements OnInit { +export class TemplMappCreationComponent implements OnInit, OnDestroy { + @Output() showListViewParent = new EventEmitter<any>(); public uploadedFiles: FileSystemFileEntry[] = []; private fileNames: Set<string> = new Set(); - + private jsonConvert = new JsonConvert(); public files: NgxFileDropEntry[] = []; fileName: any; + templateInfo = new TemplateInfo(); + private variables: string[] = []; + dtOptions: DataTables.Settings = {}; + // We use this trigger because fetching the list of persons can be quite long, + // thus we ensure the data is fetched before rendering + dtTrigger = new Subject(); + resTableDtTrigger = new Subject(); + resourceDictionaryRes: ResourceDictionary[] = []; + allowedExt = ['.vtl']; + @ViewChild(DataTableDirective, { static: false }) + dtElement: DataTableDirective; + MappingAdapter: MappingAdapter; + mapping = new Map(); + templateFileContent: string; + templateExt = 'Velcoity'; + dependancies = new Map<string, Array<string>>(); + dependanciesSource = new Map<string, string>(); + mappingRes = []; + + - constructor(private packageCreationStore: PackageCreationStore) { + constructor( + private packageCreationStore: PackageCreationStore, + private templateStore: TemplateStore, + private packageCreationUtils: PackageCreationUtils + ) { } ngOnInit() { + this.templateStore.state$.subscribe(templateInfo => { + console.log('----------'); + console.log(templateInfo); + this.templateInfo = templateInfo; + this.fileName = templateInfo.fileName.split('/')[1]; + if (templateInfo.type === 'mapping') { + this.mappingRes = templateInfo.mapping; + this.resourceDictionaryRes = []; + this.resTableDtTrigger.next(); + } else { + + this.templateFileContent = templateInfo.fileContent; + } + }); + + this.dtOptions = { + pagingType: 'full_numbers', + pageLength: 10, + destroy: true, + retrieve: true, + }; + } + + getFileExtension() { + switch (this.templateExt) { + case 'Velcoity': + return '.vtl'; + case 'Koltin': + return '.ktl'; + case 'Jinja': + return '.j2'; + default: + return '.vtl'; + } + } + + 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; } public dropped(files: NgxFileDropEntry[]) { @@ -34,24 +131,59 @@ export class TemplMappCreationComponent implements OnInit { } } - removeFile(fileIndex: number) { - /*const filename = 'Definitions/' + this.uploadedFiles[fileIndex].name; - this.packageCreationStore.removeFileFromDefinition(filename); - this.uploadedFiles.splice(fileIndex, 1);*/ + uploadFile() { + this.dependancies.clear(); + this.dependanciesSource.clear(); + if (this.allowedExt.includes('.csv')) { + this.fetchCSVkeys(); + } else { + this.setTemplateFilesToStore(); + } } - setFilesToStore() { + fetchCSVkeys() { for (const droppedFile of this.uploadedFiles) { droppedFile.file((file: File) => { const fileReader = new FileReader(); fileReader.onload = (e) => { - this.packageCreationStore.addTemplate('Templates/' + this.fileName, - fileReader.result.toString()); + this.variables = fileReader.result.toString().split(','); + console.log(this.variables); + this.getMappingTableFromTemplate(null); }; fileReader.readAsText(file); }); + } + this.uploadedFiles = []; + } + private convertDictionaryToMap(resourceDictionaries: ResourceDictionary[]): Mapping[] { + const mapArray: Mapping[] = []; + for (const resourceDictionary of resourceDictionaries) { + this.MappingAdapter = new MappingAdapter(resourceDictionary, this.dependancies, this.dependanciesSource); + mapArray.push(this.MappingAdapter.ToMapping()); } + console.log(mapArray); + return mapArray; + } + + setTemplateFilesToStore() { + for (const droppedFile of this.uploadedFiles) { + droppedFile.file((file: File) => { + const fileReader = new FileReader(); + fileReader.onload = (e) => { + this.templateFileContent = fileReader.result.toString(); + this.variables = this.getTemplateVariable(this.templateFileContent); + + }; + fileReader.readAsText(file); + }); + } + this.uploadedFiles = []; + } + + textChanges(code: any, fileName: string) { + // this.packageCreationStore.addTemplate(fileName, code); + this.templateFileContent = code; } public fileOver(event) { @@ -61,8 +193,114 @@ export class TemplMappCreationComponent implements OnInit { public fileLeave(event) { console.log(event); } - + // resetTheUploadedFiles() { this.uploadedFiles = []; } + + openListView() { + this.showListViewParent.emit('tell parent to open create views'); + } + + getMappingTableFromTemplate(e) { + this.resourceDictionaryRes = []; + if (e) { + e.preventDefault(); + } + if (this.variables && this.variables.length > 0) { + console.log('base'); + this.packageCreationStore.getTemplateAndMapping(this.variables).subscribe(res => { + this.mappingRes = []; + this.resourceDictionaryRes = res; + console.log(this.resourceDictionaryRes); + this.rerender(); + }); + } + } + + initMap(key, map) { + if (!this.dependanciesSource.has(key)) { + this.dependanciesSource.set(key, map.key); + } + return map.key; + } + saveToStore() { + console.log(this.dependancies); + console.log(this.dependanciesSource); + if (this.fileName) { + // Save Mapping to Store + if (this.resourceDictionaryRes && this.resourceDictionaryRes.length > 0) { + const mapArray = this.convertDictionaryToMap(this.resourceDictionaryRes); + this.packageCreationStore.addMapping('Templates/' + this.fileName + '-mapping.json', + this.packageCreationUtils.transformToJson(this.jsonConvert.serialize(mapArray))); + this.resourceDictionaryRes = []; + } + // Save Template to store + if (this.templateFileContent) { + this.packageCreationStore.addTemplate('Templates/' + this.fileName + '-template' + this.getFileExtension(), + this.templateFileContent); + this.templateFileContent = ''; + } + } else { + + } + } + + selectSource(dict, e) { + const source = e.target.value; + let keyDepend = null; + try { + keyDepend = dict.definition.sources[source].properties['key-dependencies'] || null; + } catch (e) { } + console.log(dict); + console.log(source); + if (keyDepend) { + this.dependancies.set(dict.name, keyDepend); + } else { + // this.dependancies.delete(dict.name); + // this.dependanciesSource.delete(dict.name); + } + this.dependanciesSource.set(dict.name, source); + console.log(this.dependancies); + console.log(this.dependanciesSource); + } + + getKeys(map: Map<string, any>) { + return Array.from(map.keys()); + } + + getValue(key) { + return this.dependancies.get(key); + } + + rerender(): void { + 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(); + } +} + +class DependancyVal { + source: string; + keyDepend: any; + constructor( + source: string, + keyDepend: any + ) { + this.source = source; + this.keyDepend = keyDepend; + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.css index e69de29bb..054b5686e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.css +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.css @@ -0,0 +1,3 @@ +.template-mapping-list { + cursor: pointer; +}
\ No newline at end of file diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.html index ddf06c824..ab97159b6 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.html @@ -1,8 +1,6 @@ - - - <a (click)="openCreationView()" class="create-template-mapping-button"> - <i class="fa fa-plus"></i> <span>Create</span> - </a> +<a *ngIf="isCreate" (click)="openCreationView()" class="create-template-mapping-button"> + <i class="fa fa-plus"></i> <span>Create</span> +</a> <div class="template-mapping-accordion"> @@ -10,8 +8,8 @@ <div class="card"> <div class="card-header" id="headingThree"> <h5 class="mb-0 d-flex justify-content-between"> - <button class="btn btn-link" data-toggle="collapse" data-target="#collapseThree" aria-expanded="true" - aria-controls="collapseThree"> + <button class="btn btn-link" data-toggle="collapse" data-target="#collapseThree" + aria-expanded="true" aria-controls="collapseThree"> Template and Mapping List </button> @@ -19,138 +17,19 @@ </div> <div id="collapseThree" class="collapse show" aria-labelledby="headingThree" data-parent="#accordion"> - <div class="card-body max-height-list" *ngFor="let file of templates.files | keyvalue; let mapIndex = index"> - <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list active">{{file.key}} - <span>Mapping</span> - <span>Template</span> - </a> - </div> - <!-- <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Mapping</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - </a> - </div>--> - </div> - <!-- <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - <span>Mapping</span> - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Mapping</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - </a> - </div> - </div> - <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - <span>Template</span> - </a> - </div> - </div> - <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Mapping</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - </a> - </div> - </div> - <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - <span>Mapping</span> - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Mapping</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - </a> - </div> - </div> + <div class="card-body max-height-list"> <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - <span>Mapping</span> - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Mapping</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> + <!-- <div class="col-4" style="color:white" *ngFor="let file of templates.files | keyvalue; let mapIndex = index">--> + <div class="col-4" style="color:white" *ngFor="let file of getKeys(templateAndMappingMap)"> + <a (click)="setSourceCodeEditor(file)" class="template-mapping-list active">{{file}} + <span *ngIf="getValue(file).isMapping">Mapping</span> + <span *ngIf="getValue(file).isTemplate">Template</span> </a> </div> </div> - <div class="row"> - <div class="col"> - <a href="#" class="template-mapping-list">hostname - - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-1 - <span>Template</span> - </a> - </div> - <div class="col"> - <a href="#" class="template-mapping-list">vf-module-2 - <span>Mapping</span> - <span>Template</span> - </a> - </div> - </div>--> </div> </div> </div> - + </div> -</div> +</div>
\ No newline at end of file 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 5cb41c35e..372fbca03 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,6 +1,10 @@ -import {Component, EventEmitter, OnInit, Output} from '@angular/core'; -import {PackageCreationStore} from '../../package-creation.store'; -import {Template} from '../../mapping-models/CBAPacakge.model'; +import { Component, EventEmitter, 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'; +import { TemplateAndMapping } from '../TemplateAndMapping'; +import { ActivatedRoute } from '@angular/router'; + @Component({ selector: 'app-templ-mapp-listing', @@ -9,21 +13,97 @@ import {Template} from '../../mapping-models/CBAPacakge.model'; }) export class TemplMappListingComponent implements OnInit { @Output() showCreationViewParentNotification = new EventEmitter<any>(); + private templateAndMappingMap = new Map<string, TemplateAndMapping>(); private templates: Template; + private mapping: Mapping; + isCreate = true; + + constructor( + private packageCreationStore: PackageCreationStore, + private templateStore: TemplateStore, + private route: ActivatedRoute + ) { + } - constructor(private packageCreationStore: PackageCreationStore) { + ngOnInit() { + if (this.route.snapshot.paramMap.has('id')) { + this.isCreate = false; + } this.packageCreationStore.state$.subscribe(cba => { if (cba.templates) { this.templates = cba.templates; + this.mapping = cba.mapping; + console.log(this.mapping); + let templateAndMapping; + this.templateAndMappingMap.clear(); + this.templates.files.forEach((value, key) => { + templateAndMapping = new TemplateAndMapping(); + templateAndMapping.isTemplate = true; + const isFromTemplate = true; + this.setIsMappingOrTemplate(key, templateAndMapping, isFromTemplate); + }); + this.mapping.files.forEach((value, key) => { + templateAndMapping = new TemplateAndMapping(); + templateAndMapping.isMapping = true; + const isFromTemplate = false; + this.setIsMappingOrTemplate(key, templateAndMapping, isFromTemplate); + }); + console.log('hello there '); + console.log(this.templateAndMappingMap); } }); } - ngOnInit() { + private setIsMappingOrTemplate(key: string, templateAndMapping: TemplateAndMapping, isFromTemplate: boolean) { + const nameOfFile = key.split('/')[1].split('.')[0].split('-')[0]; + // const fullName = nameOfFile + ',' + key.split('.'); + if (this.templateAndMappingMap.has(nameOfFile)) { + const templateAndMappingExisted = this.templateAndMappingMap.get(nameOfFile); + !isFromTemplate ? templateAndMappingExisted.isMapping = true : templateAndMappingExisted.isTemplate = true; + this.templateAndMappingMap.set(nameOfFile, templateAndMappingExisted); + } else { + this.templateAndMappingMap.set(nameOfFile, templateAndMapping); + } + } openCreationView() { this.showCreationViewParentNotification.emit('tell parent to open create views'); } + setSourceCodeEditor(key: string) { + const templateKey = 'Templates/' + key + '-template.vtl'; + this.packageCreationStore.state$.subscribe(cba => { + console.log('cba ------'); + console.log(cba); + console.log(key); + console.log(this.templateAndMappingMap); + if (cba.templates && cba.templates.files.has(templateKey)) { + const fileContent = cba.templates.getValue(templateKey.trim()); + console.log(fileContent); + const templateInfo = new TemplateInfo(); + templateInfo.fileContent = fileContent; + templateInfo.fileName = templateKey; + this.templateStore.changeTemplateInfo(templateInfo); + } + const mappingKey = 'Templates/' + key + '-mapping.json'; + if (cba.mapping && cba.mapping.files.has(mappingKey)) { + const obj = JSON.parse(cba.mapping.getValue(mappingKey)); + const templateInfo = new TemplateInfo(); + templateInfo.mapping = obj; + templateInfo.fileName = mappingKey; + templateInfo.type = 'mapping'; + this.templateStore.changeTemplateInfo(templateInfo); + } + }); + } + + getKeys(templateAndMappingMap: Map<string, TemplateAndMapping>) { + return Array.from(this.templateAndMappingMap.keys()); + } + + getValue(file: string) { + return this.templateAndMappingMap.get(file); + } + } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.html index 83f3c84c8..f8cfe7a6a 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.html @@ -1,9 +1,9 @@ -<div *ngIf="!creationView"> - <app-templ-mapp-listing - (showCreationViewParentNotification)="openCreationView($event)"> - </app-templ-mapp-listing> +<div *ngIf="!listView"> + <app-templ-mapp-listing + (showCreationViewParentNotification)="openCreationView($event)"> + </app-templ-mapp-listing> </div> -<div *ngIf="creationView"> - <app-templ-mapp-creation></app-templ-mapp-creation> +<div *ngIf="!creationView"> + <app-templ-mapp-creation (showListViewParent)="openListView($event)"></app-templ-mapp-creation> </div> 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 7e9ae1639..106765834 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,20 +1,37 @@ import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { PackageCreationStore } from '../package-creation.store'; @Component({ - selector: 'app-template-mapping', - templateUrl: './template-mapping.component.html', - styleUrls: ['./template-mapping.component.css'] + selector: 'app-template-mapping', + templateUrl: './template-mapping.component.html', + styleUrls: ['./template-mapping.component.css'] }) export class TemplateMappingComponent implements OnInit { - creationView = false; + creationView = true; + listView = false; - constructor() { } + constructor(private route: ActivatedRoute, private pakcageStore: PackageCreationStore) { + } - ngOnInit() { - } + ngOnInit() { + if (this.route.snapshot.paramMap.has('id')) { + console.log('Edit mode'); + this.creationView = false; + this.listView = false; + } else { + console.log('Create mode'); + this.pakcageStore.clear(); + } + } + openCreationView() { + this.creationView = false; + this.listView = true; + } - openCreationView() { - this.creationView = true; - } + openListView() { + this.listView = false; + this.creationView = false; + } } 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 new file mode 100644 index 000000000..9c8775514 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts @@ -0,0 +1,58 @@ +/* +============LICENSE_START========================================== +=================================================================== +Copyright (C) 2019 Orange. All rights reserved. +=================================================================== + +Unless otherwise specified, all software contained herein is licensed +under the Apache License, Version 2.0 (the License); +you may not use this software except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +============LICENSE_END============================================ +*/ + +import { Injectable } from '@angular/core'; + +import { Store } from '../../../../common/core/stores/Store'; + + +export class TemplateInfo { + fileName: string; + fileContent: string; + type: string; + mapping = []; + + + constructor() { + this.fileName = ''; + this.fileContent = ''; + this.type = ''; + } + + +} + +@Injectable({ + providedIn: 'root' +}) +export class TemplateStore extends Store<TemplateInfo> { + + + constructor() { + super(new TemplateInfo()); + } + + changeTemplateInfo(templateInfo: TemplateInfo) { + this.setState(templateInfo); + } + + +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.html index 7f6c0a6f4..9322ee783 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.html @@ -7,7 +7,8 @@ </div> <div class="card-footer row"> <div class="col"> - <a routerLink="/packages/createPackage" role="button" aria-pressed="true" class="btn-create-package float">Create + <a routerLink="/packages/createPackage" role="button" aria-pressed="true" + class="btn-create-package float">Create </a> </div> <div class="col"> @@ -25,10 +26,11 @@ <div class="card-body"> <div class="row"> <div class="col-9 pr-0"> - <h5 class="card-title" [routerLink]="['/packages/package', bluePrint.id]" (click)="testDispatch(bluePrint)"> + <a class="card-title" [routerLink]="['/packages/package', bluePrint.id]" + (click)="testDispatch(bluePrint)"> <img class="icon-deployed" src="/assets/img/icon-deploy.svg"> {{bluePrint.artifactName}} - </h5> + </a> </div> <div class="col-3"> @@ -56,25 +58,24 @@ <div class="row"> <div class="col"> <p class="mb-0">Last modified {{ bluePrint.createdDate | date:'short' }} - </p> - <p>By {{bluePrint.updatedBy}}</p> + </p> + <p>By {{bluePrint.updatedBy}}</p> <ul class="package-contributers"> <li> <button type="button" class="border-fade" data-toggle="tooltip" - data-placement="bottom" - title="User name"> + data-placement="bottom" title="User name"> <img src="/assets/img/img-user1.jpeg"> </button> </li> <li> <button type="button" data-toggle="tooltip" data-placement="bottom" - title="User name"> + title="User name"> <img src="/assets/img/img-user2.jpg"> </button> </li> <li> <button type="button" data-toggle="tooltip" data-placement="bottom" - title="User name"> + title="User name"> <img src="/assets/img/img-user3.jpg"> </button> </li> @@ -101,4 +102,4 @@ </div> </div> -</div> +</div>
\ No newline at end of file diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts index 7935e12a3..66c7b498a 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.module.ts @@ -1,33 +1,34 @@ -import {NgModule} from '@angular/core'; -import {CommonModule, JsonPipe} from '@angular/common'; -import {ApiService} from '../../../common/core/services/api.typed.service'; -import {PackagesRoutingModule} from './packages.routing.module'; -import {NgbPaginationModule} from '@ng-bootstrap/ng-bootstrap'; -import {SharedModulesModule} from '../../shared-modules/shared-modules.module'; -import {PackagesDashboardComponent} from './packages-dashboard/packages-dashboard.component'; -import {PackageListComponent} from './packages-dashboard/package-list/package-list.component'; -import {DesignerComponent} from './designer/designer.component'; -import {SidebarModule} from 'ng-sidebar'; -import {PackagePaginationComponent} from './packages-dashboard/package-pagination/package-pagination.component'; -import {SortPackagesComponent} from './packages-dashboard/sort-packages/sort-packages.component'; -import {PackagesHeaderComponent} from './packages-dashboard/packages-header/packages-header.component'; -import {PackagesSearchComponent} from './packages-dashboard/search-by-packages/search-by-packages.component'; -import {TagsFilteringComponent} from './packages-dashboard/filter-by-tags/filter-by-tags.component'; -import {ConfigurationDashboardComponent} from './configuration-dashboard/configuration-dashboard.component'; -import {FunctionsComponent} from './designer/functions/functions.component'; -import {ActionsComponent} from './designer/actions/actions.component'; -import {PackageCreationComponent} from './package-creation/package-creation.component'; -import {FormsModule} from '@angular/forms'; -import {ImportsTabComponent} from './package-creation/imports-tab/imports-tab.component'; -import {NgxFileDropModule} from 'ngx-file-drop'; -import {TemplateMappingComponent} from './package-creation/template-mapping/template-mapping.component'; -import {SourceEditorComponent} from './source-editor/source-editor.component'; -import {ScriptsTabComponent} from './package-creation/scripts-tab/scripts-tab.component'; -import {AceEditorModule} from 'ng2-ace-editor'; -import {MetadataTabComponent} from './package-creation/metadata-tab/metadata-tab.component'; -import {DslDefinitionsTabComponent} from './package-creation/dsl-definitions-tab/dsl-definitions-tab.component'; +import { NgModule } from '@angular/core'; +import { CommonModule, JsonPipe } from '@angular/common'; +import { ApiService } from '../../../common/core/services/api.typed.service'; +import { PackagesRoutingModule } from './packages.routing.module'; +import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; +import { SharedModulesModule } from '../../shared-modules/shared-modules.module'; +import { PackagesDashboardComponent } from './packages-dashboard/packages-dashboard.component'; +import { PackageListComponent } from './packages-dashboard/package-list/package-list.component'; +import { DesignerComponent } from './designer/designer.component'; +import { SidebarModule } from 'ng-sidebar'; +import { PackagePaginationComponent } from './packages-dashboard/package-pagination/package-pagination.component'; +import { SortPackagesComponent } from './packages-dashboard/sort-packages/sort-packages.component'; +import { PackagesHeaderComponent } from './packages-dashboard/packages-header/packages-header.component'; +import { PackagesSearchComponent } from './packages-dashboard/search-by-packages/search-by-packages.component'; +import { TagsFilteringComponent } from './packages-dashboard/filter-by-tags/filter-by-tags.component'; +import { ConfigurationDashboardComponent } from './configuration-dashboard/configuration-dashboard.component'; +import { ActionsComponent } from './designer/actions/actions.component'; +import { PackageCreationComponent } from './package-creation/package-creation.component'; +import { FormsModule } from '@angular/forms'; +import { ImportsTabComponent } from './package-creation/imports-tab/imports-tab.component'; +import { NgxFileDropModule } from 'ngx-file-drop'; +import { TemplateMappingComponent } from './package-creation/template-mapping/template-mapping.component'; +import { SourceEditorComponent } from './source-editor/source-editor.component'; +import { ScriptsTabComponent } from './package-creation/scripts-tab/scripts-tab.component'; +import { AceEditorModule } from 'ng2-ace-editor'; +import { MetadataTabComponent } from './package-creation/metadata-tab/metadata-tab.component'; +import { DslDefinitionsTabComponent } from './package-creation/dsl-definitions-tab/dsl-definitions-tab.component'; import { TemplMappCreationComponent } from './package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component'; import { TemplMappListingComponent } from './package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component'; +import { DataTablesModule } from 'angular-datatables'; +import { DesignerSourceViewComponent } from './designer/source-view/source-view.component'; @NgModule({ declarations: [PackagesDashboardComponent, @@ -39,7 +40,6 @@ import { TemplMappListingComponent } from './package-creation/template-mapping/t SortPackagesComponent, ConfigurationDashboardComponent, PackagesHeaderComponent, - FunctionsComponent, ActionsComponent, PackageCreationComponent, ImportsTabComponent, @@ -50,6 +50,7 @@ import { TemplMappListingComponent } from './package-creation/template-mapping/t ScriptsTabComponent, MetadataTabComponent, DslDefinitionsTabComponent, + DesignerSourceViewComponent, ], imports: [ CommonModule, @@ -59,7 +60,8 @@ import { TemplMappListingComponent } from './package-creation/template-mapping/t SidebarModule.forRoot(), FormsModule, NgxFileDropModule, - AceEditorModule + AceEditorModule, + DataTablesModule ], providers: [ApiService, JsonPipe], bootstrap: [] diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts index 913bb1081..ad06cf15f 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.routing.module.ts @@ -4,6 +4,7 @@ import {PackagesDashboardComponent} from './packages-dashboard/packages-dashboar import {DesignerComponent} from './designer/designer.component'; import {PackageCreationComponent} from './package-creation/package-creation.component'; import {ConfigurationDashboardComponent} from './configuration-dashboard/configuration-dashboard.component'; +import { DesignerSourceViewComponent } from './designer/source-view/source-view.component'; const routes: Routes = [ @@ -12,6 +13,7 @@ const routes: Routes = [ component: PackagesDashboardComponent }, {path: 'designer', component: DesignerComponent}, + { path: 'designer/source', component: DesignerSourceViewComponent }, {path: 'package/:id', component: ConfigurationDashboardComponent}, {path: 'createPackage', component: PackageCreationComponent}, ]; diff --git a/cds-ui/designer-client/src/app/modules/shared-modules/header/header.component.html b/cds-ui/designer-client/src/app/modules/shared-modules/header/header.component.html index f57ab100b..502e098d3 100644 --- a/cds-ui/designer-client/src/app/modules/shared-modules/header/header.component.html +++ b/cds-ui/designer-client/src/app/modules/shared-modules/header/header.component.html @@ -5,14 +5,14 @@ <div class="overflow-container"> <ul class="menu-dropdown"> <li class="active"> - <a routerLink="packages/list">Packages</a> + <a routerLink="/packages">Packages</a> <span class="icon"> <!-- <i class="fa fa-dashboard"></i> --> <i class="icon-package"></i> </span> </li> <li class="menu-hasdropdown"> - <a href="#">Data Dictionary</a> + <a >Data Dictionary</a> <span class="icon"> <i class="icon-dictionary"></i> </span> |