diff options
Diffstat (limited to 'cds-ui')
84 files changed, 3488 insertions, 1583 deletions
diff --git a/cds-ui/application/pom.xml b/cds-ui/application/pom.xml index 52eb555d4..4d8f8593d 100644 --- a/cds-ui/application/pom.xml +++ b/cds-ui/application/pom.xml @@ -24,24 +24,18 @@ limitations under the License. <parent> <groupId>org.onap.ccsdk.cds</groupId> - <artifactId>ui</artifactId> - <version>1.0.0-SNAPSHOT</version> + <artifactId>cds-ui</artifactId> + <version>1.1.0-SNAPSHOT</version> <relativePath>..</relativePath> </parent> - <artifactId>application</artifactId> - <version>1.0.0-SNAPSHOT</version> + <artifactId>cds-ui-application</artifactId> <packaging>pom</packaging> - <name>CDS UI Application</name> + <name>UI Application</name> <properties> <image.name>onap/ccsdk-cds-ui</image.name> - <ccsdk.project.version>${project.version}</ccsdk.project.version> - <ccsdk.distribution.version>${project.version}</ccsdk.distribution.version> - <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp> - <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format> - <docker.verbose>true</docker.verbose> </properties> <build> @@ -73,7 +67,7 @@ limitations under the License. <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> - <version>0.28.0</version> + <version>0.34.0</version> <inherited>false</inherited> <configuration> <images> @@ -89,19 +83,13 @@ limitations under the License. </build> </image> </images> + <verbose>${docker.verbose}</verbose> + <skipPush>${docker.skip.push}</skipPush> </configuration> <executions> <execution> - <id>generate-images</id> - <phase>package</phase> - <goals> - <goal>build</goal> - </goals> - </execution> - - <execution> - <id>push-images</id> - <phase>deploy</phase> + <id>build-push-images</id> + <phase>${docker.push.phase}</phase> <goals> <goal>build</goal> <goal>push</goal> diff --git a/cds-ui/client/pom.xml b/cds-ui/client/pom.xml index d2309f89d..386eeaf89 100644 --- a/cds-ui/client/pom.xml +++ b/cds-ui/client/pom.xml @@ -20,77 +20,70 @@ limitations under the License. ============LICENSE_END============================================ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onap.ccsdk.cds</groupId> - <artifactId>ui</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>..</relativePath> - </parent> - - <artifactId>ui-client</artifactId> - <version>1.0.0-SNAPSHOT</version> - <packaging>pom</packaging> - - <name>CDS UI Client</name> - - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <npm.executable>npm</npm.executable> - <onap.nexus.url>https://nexus.onap.org</onap.nexus.url> - </properties> - - <build> - <plugins> - <plugin> - <groupId>com.github.eirslett</groupId> - <artifactId>frontend-maven-plugin</artifactId> - <!-- Use the latest released version: https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ --> - <version>1.3</version> - <configuration> - <nodeVersion>v8.12.0</nodeVersion> - <npmVersion>6.4.1</npmVersion> - <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> - <installDirectory>./</installDirectory> - </configuration> - <executions> - <execution> - <id>install node and npm</id> - <goals> - <goal>install-node-and-npm</goal> - </goals> - <phase>generate-resources</phase> - </execution> - - <execution> - <id>npm install</id> - <goals> - <goal>npm</goal> - </goals> - - <phase>generate-resources</phase> - - <configuration> - <arguments>install</arguments> - </configuration> - </execution> - - <execution> - <id>npm build</id> - <goals> - <goal>npm</goal> - </goals> - - <phase>generate-resources</phase> - - <configuration> - <arguments>run build</arguments> - </configuration> - </execution> - - </executions> - </plugin> - </plugins> - </build> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.cds</groupId> + <artifactId>cds-ui</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>cds-ui-client</artifactId> + <packaging>pom</packaging> + + <name>UI Client</name> + + <build> + <plugins> + <plugin> + <groupId>com.github.eirslett</groupId> + <artifactId>frontend-maven-plugin</artifactId> + <!-- Use the latest released version: https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ --> + <version>1.3</version> + <configuration> + <nodeVersion>v8.12.0</nodeVersion> + <npmVersion>6.4.1</npmVersion> + <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> + <installDirectory>./</installDirectory> + </configuration> + <executions> + <execution> + <id>install node and npm</id> + <goals> + <goal>install-node-and-npm</goal> + </goals> + <phase>generate-resources</phase> + </execution> + + <execution> + <id>npm install</id> + <goals> + <goal>npm</goal> + </goals> + + <phase>generate-resources</phase> + + <configuration> + <arguments>install</arguments> + </configuration> + </execution> + + <execution> + <id>npm build</id> + <goals> + <goal>npm</goal> + </goals> + + <phase>generate-resources</phase> + + <configuration> + <arguments>run build</arguments> + </configuration> + </execution> + + </executions> + </plugin> + </plugins> + </build> </project> diff --git a/cds-ui/designer-client/package-lock.json b/cds-ui/designer-client/package-lock.json index 6ee937186..14feaad08 100644 --- a/cds-ui/designer-client/package-lock.json +++ b/cds-ui/designer-client/package-lock.json @@ -10941,6 +10941,12 @@ } } }, + "sonar-scanner": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/sonar-scanner/-/sonar-scanner-3.1.0.tgz", + "integrity": "sha1-UcHBEB9UuYq8XYVlIJsdkjKXk0M=", + "dev": true + }, "sort-keys": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz", diff --git a/cds-ui/designer-client/package.json b/cds-ui/designer-client/package.json index 517b2dab1..096e96eb9 100644 --- a/cds-ui/designer-client/package.json +++ b/cds-ui/designer-client/package.json @@ -3,11 +3,12 @@ "version": "0.0.0", "scripts": { "ng": "ng", - "start": "npm run lint && ng build --prod --aot && ng serve --proxy-config proxy.conf.json", + "start": "npm run lint && ng serve --proxy-config proxy.conf.json && ng build --prod --aot ", "build": "npm run lint && ng build --prod --aot ", "test": "ng test", "lint": "ng lint", - "e2e": "ng e2e" + "e2e": "ng e2e", + "sonar": "sonar-scanner" }, "private": true, "dependencies": { @@ -76,6 +77,7 @@ "karma-jasmine": "~2.0.1", "karma-jasmine-html-reporter": "^1.4.0", "protractor": "~5.4.0", + "sonar-scanner": "^3.1.0", "ts-node": "~7.0.0", "tslint": "~5.15.0", "typescript": "~3.5.3" diff --git a/cds-ui/designer-client/pom.xml b/cds-ui/designer-client/pom.xml index 0d3331d92..6cda0b155 100644 --- a/cds-ui/designer-client/pom.xml +++ b/cds-ui/designer-client/pom.xml @@ -20,77 +20,70 @@ limitations under the License. ============LICENSE_END============================================ --> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> - <modelVersion>4.0.0</modelVersion> - - <parent> - <groupId>org.onap.ccsdk.cds</groupId> - <artifactId>ui</artifactId> - <version>1.0.0-SNAPSHOT</version> - <relativePath>..</relativePath> - </parent> - - <artifactId>designer-client</artifactId> - <version>1.0.0-SNAPSHOT</version> - <packaging>pom</packaging> - - <name>CDS designer Client</name> - - <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <npm.executable>npm</npm.executable> - <onap.nexus.url>https://nexus.onap.org</onap.nexus.url> - </properties> - - <build> - <plugins> - <plugin> - <groupId>com.github.eirslett</groupId> - <artifactId>frontend-maven-plugin</artifactId> - <!-- Use the latest released version: https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ --> - <version>1.3</version> - <configuration> - <nodeVersion>v13.7.0</nodeVersion> - <npmVersion>6.13.6</npmVersion> - <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> - <installDirectory>./</installDirectory> - </configuration> - <executions> - <execution> - <id>install node and npm</id> - <goals> - <goal>install-node-and-npm</goal> - </goals> - <phase>generate-resources</phase> - </execution> - - <execution> - <id>npm install</id> - <goals> - <goal>npm</goal> - </goals> - - <phase>generate-resources</phase> - - <configuration> - <arguments>install</arguments> - </configuration> - </execution> - - <execution> - <id>npm build</id> - <goals> - <goal>npm</goal> - </goals> - - <phase>generate-resources</phase> - - <configuration> - <arguments>run build</arguments> - </configuration> - </execution> - - </executions> - </plugin> - </plugins> - </build> + <modelVersion>4.0.0</modelVersion> + + <parent> + <groupId>org.onap.ccsdk.cds</groupId> + <artifactId>cds-ui</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> + </parent> + + <artifactId>cds-ui-designer-client</artifactId> + <packaging>pom</packaging> + + <name>UI designer Client</name> + + <build> + <plugins> + <plugin> + <groupId>com.github.eirslett</groupId> + <artifactId>frontend-maven-plugin</artifactId> + <!-- Use the latest released version: https://repo1.maven.org/maven2/com/github/eirslett/frontend-maven-plugin/ --> + <version>1.3</version> + <configuration> + <nodeVersion>v13.7.0</nodeVersion> + <npmVersion>6.13.6</npmVersion> + <nodeDownloadRoot>https://nodejs.org/dist/</nodeDownloadRoot> + <installDirectory>./</installDirectory> + </configuration> + <executions> + <execution> + <id>install node and npm</id> + <goals> + <goal>install-node-and-npm</goal> + </goals> + <phase>generate-resources</phase> + </execution> + + <execution> + <id>npm install</id> + <goals> + <goal>npm</goal> + </goals> + + <phase>generate-resources</phase> + + <configuration> + <arguments>install</arguments> + </configuration> + </execution> + + <execution> + <id>npm build</id> + <goals> + <goal>npm</goal> + </goals> + + <phase>generate-resources</phase> + + <configuration> + <arguments>run build</arguments> + </configuration> + </execution> + + </executions> + </plugin> + </plugins> + </build> </project> diff --git a/cds-ui/designer-client/proxy.conf.json b/cds-ui/designer-client/proxy.conf.json index 17de0a74f..4e8ef0aab 100644 --- a/cds-ui/designer-client/proxy.conf.json +++ b/cds-ui/designer-client/proxy.conf.json @@ -1,12 +1,12 @@ { "/controllerblueprint/*": { - "target": "https://41.128.168.198:3000", + "target": "https://localhost:3000", "secure": false, "logLevel": "debug", "changeOrigin": true }, "/resourcedictionary/*": { - "target": "https://41.128.168.198:3000", + "target": "https://localhost:3000", "secure": false, "logLevel": "debug", "changeOrigin": true diff --git a/cds-ui/designer-client/sonar-project.properties b/cds-ui/designer-client/sonar-project.properties new file mode 100644 index 000000000..6b246e759 --- /dev/null +++ b/cds-ui/designer-client/sonar-project.properties @@ -0,0 +1,12 @@ +sonar.host.url=http://localhost:9000 +sonar.login=admin +sonar.password=admin +sonar.projectKey=designer-client-app +sonar.projectName=designer-client-app +sonar.projectVersion=1.0 +sonar.sourceEncoding=UTF-8 +sonar.sources=src +sonar.exclusions=**/node_modules/** +sonar.tests=src +sonar.test.inclusions=**/*.spec.ts +sonar.typescript.lcov.reportPaths=coverage/lcov.info diff --git a/cds-ui/designer-client/src/app/app-routing.module.ts b/cds-ui/designer-client/src/app/app-routing.module.ts index 2610dc59f..d0a8e2a28 100644 --- a/cds-ui/designer-client/src/app/app-routing.module.ts +++ b/cds-ui/designer-client/src/app/app-routing.module.ts @@ -20,13 +20,17 @@ limitations under the License. */ import {NgModule} from '@angular/core'; -import {Routes, RouterModule} from '@angular/router'; +import {RouterModule, Routes} from '@angular/router'; const routes: Routes = [ - {path: 'packages', - loadChildren: './modules/feature-modules/packages/packages.module#PackagesModule'}, - {path: 'resource-dictionary', - loadChildren: './modules/feature-modules/resource-dictionary/resource-dictionary.module#ResourceDictionaryModule'}, + { + path: 'packages', + loadChildren: './modules/feature-modules/packages/packages.module#PackagesModule' + }, + { + path: 'resource-dictionary', + loadChildren: './modules/feature-modules/resource-dictionary/resource-dictionary.module#ResourceDictionaryModule' + }, // { path: '', component: MainAppComponent }, { path: '', @@ -36,7 +40,7 @@ const routes: Routes = [ ]; @NgModule({ - imports: [RouterModule.forRoot(routes)], + imports: [RouterModule.forRoot(routes, {useHash: true})], exports: [RouterModule] }) export class AppRoutingModule { diff --git a/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivate.ts b/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivate.ts new file mode 100644 index 000000000..3435b10d3 --- /dev/null +++ b/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivate.ts @@ -0,0 +1,14 @@ +import {HostListener} from '@angular/core'; + +export abstract class ComponentCanDeactivate { + + abstract canDeactivate(): boolean; + + + @HostListener('window:beforeunload', ['$event']) + unloadNotification($event: any) { + if (this.canDeactivate()) { + $event.returnValue = true; + } + } +} diff --git a/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivateGuard.ts b/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivateGuard.ts new file mode 100644 index 000000000..b24784262 --- /dev/null +++ b/cds-ui/designer-client/src/app/common/core/canDactivate/ComponentCanDeactivateGuard.ts @@ -0,0 +1,19 @@ +import {Injectable} from '@angular/core'; + +import {CanDeactivate} from '@angular/router'; +import {ComponentCanDeactivate} from './ComponentCanDeactivate'; + +@Injectable() +export class ComponentCanDeactivateGuard implements CanDeactivate<ComponentCanDeactivate> { + canDeactivate(component: ComponentCanDeactivate): boolean { + + if (component.canDeactivate()) { + if (confirm('You have unsaved changes! If you leave, your changes will be lost.')) { + return true; + } else { + return false; + } + } + return true; + } +} diff --git a/cds-ui/designer-client/src/app/common/core/services/api.service.ts b/cds-ui/designer-client/src/app/common/core/services/api.service.ts index de8aab886..8e27befb0 100644 --- a/cds-ui/designer-client/src/app/common/core/services/api.service.ts +++ b/cds-ui/designer-client/src/app/common/core/services/api.service.ts @@ -48,4 +48,8 @@ export class ApiService { return this.httpClient.post(url, body, 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 0be804270..c6995787d 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 @@ -17,6 +17,7 @@ export class Store<T> { protected setState(nextState: T): void { console.log('setting state', this.subject); this.subject.next(nextState); + console.log('current state', this.subject); } public 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 0ffd9cb5e..a281aafae 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 @@ -13,60 +13,70 @@ </h2> <div class="col profile-help"> <nav class="navbar navbar-expand-lg navbar-light"> - <ul class="navbar-nav ml-auto"> - <!-- <li class="nav-item help-btn"> - <a class="nav-link mr-2" href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank" - [delay]="300" tooltip="Help" placement="bottom"><i class="icon-info" aria-hidden="true"></i></a> - </li> --> - <!--Help Menu--> - <div class="nav-item dropdown helpMenu"> - <input class="dropdown-toggle" type="text"> - <div class="dropdown-text"><i class="icon-info" aria-hidden="true"></i></div> - <ul class="dropdown-content"> - <!-- <li> - <i class="icon-get_started" aria-hidden="true"></i> - <p> - <input id="clicker3" [checked]="startTour" type="checkbox" /> - <label for="clicker"> - Getting Started - <span>Quick steps to help you get started</span> - </label> - </p> + <ul class="navbar-nav ml-auto"> + <!-- <li class="nav-item help-btn"> + <a class="nav-link mr-2" href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank" + [delay]="300" tooltip="Help" placement="bottom"><i class="icon-info" aria-hidden="true"></i></a> </li> --> - <li> - <a href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank"> - <i class="icon-user_guide" aria-hidden="true"></i> - <p> - Tutorials - <span>CDS Designer's User Guide</span> - </p> - </a> - </li> - </ul> - </div> - <!--User Menu--> - <div class="nav-item dropdown userMenu"> - <input class="dropdown-toggle" type="text"> - <div class="dropdown-text"><img src="../assets/img/img-user.jpeg" align="right"></div> - <ul class="dropdown-content"> - <li> - <a href="#">Username</a> - </li> - <li> - <a href="#">Settings</a> - </li> - <li> - <a href="#">Projects</a> - </li> - <li> - <a href="#">Log out</a> - </li> - </ul> - </div> + <!--Help Menu--> + <div class="nav-item dropdown helpMenu"> + <input class="dropdown-toggle" type="text"> + <div class="dropdown-text"><i class="icon-info" aria-hidden="true"></i></div> + <ul class="dropdown-content"> + <li> + <i class="icon-get_started" aria-hidden="true"></i> + <p> + <input id="clicker3" type="checkbox"/> + <label for="clicker"> + Getting Started + <span>Quick steps to help you get started</span> + </label> + </p> + </li> + <!-- <li> + <i class="icon-get_started" aria-hidden="true"></i> + <p> + <input id="clicker3" [checked]="startTour" type="checkbox" /> + <label for="clicker"> + Getting Started + <span>Quick steps to help you get started</span> + </label> + </p> + </li> --> + <li> + <a href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank"> + <i class="icon-user_guide" aria-hidden="true"></i> + <p> + Tutorials + <span>CDS Designer's User Guide</span> + </p> + </a> + </li> + </ul> + </div> + <!--User Menu--> + <div class="nav-item dropdown userMenu"> + <input class="dropdown-toggle" type="text"> + <div class="dropdown-text"><img src="../assets/img/img-user.jpeg" align="right"></div> + <ul class="dropdown-content"> + <li> + <a href="#">Username</a> + </li> + <li> + <a href="#">Settings</a> + </li> + <li> + <a href="#">Projects</a> + </li> + <li> + <a href="#">Log out</a> + </li> + </ul> + </div> - </ul> + </ul> </nav> - </div> + </div> </div> </header> @@ -103,7 +113,7 @@ <span>Download</span> </a> - <a data-target="#removePackageModal" data-toggle="modal" class="action-button"> + <a data-target="#removePackageModal" data-toggle="modal" class="action-button delete"> <i class="icon-delete-sm" aria-hidden="true"></i> <span>Delete</span> </a> @@ -127,7 +137,8 @@ <div class="row package-auth-info"> <div class="col-3"> <p><b>Author Name</b></p> - <span> {{viewedPackage.updatedBy ? viewedPackage.updatedBy.split('<')[0] : ""}}</span> + <span> + {{viewedPackage.updatedBy ? viewedPackage.updatedBy.split('<')[0] : ""}}</span> </div> <!--<div class="col-4"> <p><b>Author Email</b></p> @@ -167,8 +178,8 @@ </button> --> <!-- Button trigger modal - 1st Action --> - <button type="button" class="btn btn-sm btn-primary mb-2" data-toggle="modal" - data-target="#exampleModalLong"> + <button (click)="checkSkipTypesOfAction()" type="button" class="btn btn-sm btn-primary mb-2" + data-toggle="modal" [attr.data-target]="dataTarget"> <i class="icon-topologyView-active"></i> Designer Mode </button> <!-- Designer Modal --> @@ -270,7 +281,7 @@ </div> <div class="row"> <div class="col text-center"> - <button class="btn skip-btn" + <button class="btn skip-btn" data-dismiss="modal" (click)="goToDesignerMode(viewedPackage.id)"> Skip to Designer Canvas @@ -288,7 +299,7 @@ <input type="text" [(ngModel)]="customActionName" class="form-control customAction" placeholder="Type Action Name" autofocus> - <button type="button" + <button type="button" data-dismiss="modal" (click)="goToDesignerMode(viewedPackage.id)" class="btn submit">Start </button> @@ -460,7 +471,7 @@ <div class="row"> <div class="col text-center"> <p class="selectedActions">0 selected</p> - <button type="button" + <button type="button" data-dismiss="modal" (click)="goToDesignerMode(viewedPackage.id)" class="btn submit">Start </button> @@ -641,8 +652,7 @@ <div class="row"> <div class="col text-center"> <p class="selectedActions">0 selected</p> - <button type="button" - class="btn submit">Start + <button type="button" class="btn submit">Start </button> </div> </div> @@ -706,8 +716,7 @@ </div> <div class="row"> <div class="col text-center"> - <button type="button" - class="btn submit mt-4">Import + <button type="button" class="btn submit mt-4">Import </button> </div> </div> @@ -757,7 +766,7 @@ <div class="col"> <div class="tab-content" id="nav-tabContent" (change)="clickEvent()"> <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" @@ -806,11 +815,10 @@ <li>1. Copy and paste "workflows" and "node_templates"</li> <li>2. Press <b>Enrich</b> button</li> </ul> - <ace-editor [(text)]="vlbDefinition.topology_template.content" [mode]="'javascript'" - [autoUpdateContent]="true" - [durationBeforeCallback]="1000" (textChanged)="textChanged($event)" [theme]="'eclipse'" - #editor - style="height:300px;"> + <ace-editor [(text)]="this.vlbDefinition.topology_template.content" [mode]="'json'" + [autoUpdateContent]="true" [durationBeforeCallback]="1000" [theme]="'eclipse'" + (textChanged)="textChanged($event)" + #editor style="height:300px;"> </ace-editor> </div> <div class="modal-footer"> @@ -838,8 +846,7 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> - <button type="button" (click)="deletePackage()" data-dismiss="modal" - class="btn btn-primary">Delete + <button type="button" (click)="deletePackage()" data-dismiss="modal" class="btn btn-primary">Delete </button> </div> </div> @@ -861,8 +868,8 @@ </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> - <button type="button" (click)="discardChanges()" data-dismiss="modal" - class="btn btn-primary">Discard Changes + <button type="button" (click)="discardChanges()" data-dismiss="modal" class="btn btn-primary">Discard + Changes </button> </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 029601d67..dc5697f78 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,13 +1,13 @@ -import {Component, ElementRef, OnInit, ViewChild} from '@angular/core'; +import {Component, ElementRef, OnDestroy, 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 {FilesContent, FolderNodeElement} 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 {TemplateTopology, VlbDefinition} from '../package-creation/mapping-models/definitions/VlbDefinition'; -import {DslDefinition} from '../package-creation/mapping-models/CBAPacakge.model'; +import {CBAPackage} 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'; @@ -15,13 +15,18 @@ import {saveAs} from 'file-saver'; import {DesignerStore} from '../designer/designer.store'; import {ToastrService} from 'ngx-toastr'; import {NgxFileDropEntry} from 'ngx-file-drop'; +import {PackageCreationService} from '../package-creation/package-creation.service'; +import {ComponentCanDeactivate} from '../../../../common/core/canDactivate/ComponentCanDeactivate'; +import {PackageCreationExtractionService} from '../package-creation/package-creation-extraction.service'; +import {distinctUntilChanged, takeUntil} from 'rxjs/operators'; +import {Subject} from 'rxjs'; @Component({ selector: 'app-configuration-dashboard', templateUrl: './configuration-dashboard.component.html', styleUrls: ['./configuration-dashboard.component.css'], }) -export class ConfigurationDashboardComponent implements OnInit { +export class ConfigurationDashboardComponent extends ComponentCanDeactivate implements OnInit, OnDestroy { viewedPackage: BluePrintDetailModel = new BluePrintDetailModel(); @ViewChild(MetadataTabComponent, {static: false}) metadataTabComponent: MetadataTabComponent; @@ -42,43 +47,65 @@ export class ConfigurationDashboardComponent implements OnInit { isSaveEnabled = false; versionPattern = '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$'; metadataClasses = 'nav-item nav-link active'; + private cbaPackage: CBAPackage = new CBAPackage(); + dataTarget: any = ''; + ngUnsubscribe = new Subject(); + private designerState: any; constructor( private route: ActivatedRoute, private configurationDashboardService: ConfigurationDashboardService, private packageCreationStore: PackageCreationStore, + private packageCreationService: PackageCreationService, private packageCreationUtils: PackageCreationUtils, private router: Router, private designerStore: DesignerStore, - private toastService: ToastrService + private toastService: ToastrService, + private packageCreationExtractionService: PackageCreationExtractionService ) { + super(); + + } ngOnInit() { this.vlbDefinition.topology_template = new TemplateTopology(); - + this.packageCreationStore.state$ + .pipe(distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe( + cbaPackage => { + this.cbaPackage = cbaPackage; + }); + this.designerStore.state$.pipe( + distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe(state => { + this.designerState = state; + this.vlbDefinition.topology_template.content = this.packageCreationUtils.transformToJson(state.template); + }); this.elementRef.nativeElement.focus(); this.refreshCurrentPackage(); const regexp = RegExp(this.versionPattern); - this.packageCreationStore.state$.subscribe( - cbaPackage => { - if (cbaPackage && cbaPackage.metaData && cbaPackage.metaData.description - && cbaPackage.metaData.name && cbaPackage.metaData.version && - regexp.test(cbaPackage.metaData.version)) { - if (!this.metadataClasses.includes('complete')) { - this.metadataClasses += ' complete'; - } - } else { - this.metadataClasses = this.metadataClasses.replace('complete', ''); - this.isSaveEnabled = false; - } + if (this.cbaPackage && this.cbaPackage.metaData && this.cbaPackage.metaData.description + && this.cbaPackage.metaData.name && this.cbaPackage.metaData.version && + regexp.test(this.cbaPackage.metaData.version)) { + if (!this.metadataClasses.includes('complete')) { + this.metadataClasses += ' complete'; + } + } else { + this.metadataClasses = this.metadataClasses.replace('complete', ''); + this.isSaveEnabled = false; + } + - }); } - private refreshCurrentPackage() { + private refreshCurrentPackage(id?) { this.id = this.route.snapshot.paramMap.get('id'); - this.configurationDashboardService.getPagedPackages(this.id).subscribe( + console.log(this.id); + id = id ? id : this.id; + this.configurationDashboardService.getPagedPackages(id).subscribe( (bluePrintDetailModels) => { if (bluePrintDetailModels) { this.viewedPackage = bluePrintDetailModels[0]; @@ -90,122 +117,47 @@ export class ConfigurationDashboardComponent implements OnInit { private downloadCBAPackage(bluePrintDetailModels: BluePrintDetailModel) { this.configurationDashboardService.downloadResource( - bluePrintDetailModels[0].artifactName + '/' + bluePrintDetailModels[0].artifactVersion).subscribe(response => { + this.viewedPackage.artifactName + '/' + this.viewedPackage.artifactVersion).subscribe(response => { const blob = new Blob([response], {type: 'application/octet-stream'}); this.currentBlob = blob; - this.extractBlobToStore(blob, bluePrintDetailModels); - }); - } - - private extractBlobToStore(blob: Blob, bluePrintDetailModels: BluePrintDetailModel) { - this.zipFile.loadAsync(blob).then((zip) => { - Object.keys(zip.files).forEach((filename) => { - zip.files[filename].async('string').then((fileData) => { - console.log(filename); - if (fileData) { - if (filename.includes('Scripts/')) { - this.setScripts(filename, fileData); - } else if (filename.includes('Templates/')) { - if (filename.includes('-mapping.')) { - this.setMapping(filename, fileData); - } else if (filename.includes('-template.')) { - this.setTemplates(filename, fileData); - } - - } else if (filename.includes('Definitions/')) { - this.setImports(filename, fileData, bluePrintDetailModels); - } else if (filename.includes('TOSCA-Metadata/')) { - const metaDataTabInfo: MetaDataTabModel = this.getMetaDataTabInfo(fileData); - this.setMetaData(metaDataTabInfo, bluePrintDetailModels[0]); - } - } - }); - }); + this.packageCreationExtractionService.extractBlobToStore(blob); }); } - setScripts(filename: string, fileData: any) { - this.packageCreationStore.addScripts(filename, fileData); - } - - setImports(filename: string, fileData: any, bluePrintDetailModels: BluePrintDetailModel) { - if (filename.includes(bluePrintDetailModels[0].artifactName)) { - 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); - if (definition.topology_template && definition.topology_template.content) { - this.designerStore.saveSourceContent(definition.topology_template.content); - } - - } - this.packageCreationStore.addDefinition(filename, fileData); - - } - - setTemplates(filename: string, fileData: any) { - this.packageCreationStore.addTemplate(filename, fileData); - } - - setMapping(fileName: string, fileData: string) { - this.packageCreationStore.addMapping(fileName, fileData); - } - editBluePrint() { - this.packageCreationStore.state$.subscribe( - 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(); - }); - } + this.configurationDashboardService.deletePackage(this.viewedPackage.id).subscribe(res => { + this.formTreeData(); + this.saveBluePrintToDataBase(); - setMetaData(metaDataObject: MetaDataTabModel, bluePrintDetailModel: BluePrintDetailModel) { - metaDataObject.description = bluePrintDetailModel.artifactDescription; - this.packageCreationStore.changeMetaData(metaDataObject); + }); + } + private formTreeData() { + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); } 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(',')); - return metaDataTabModel; } saveBluePrintToDataBase() { this.create(); this.zipFile.generateAsync({type: 'blob'}) .then(blob => { - this.packageCreationStore.saveBluePrint(blob).subscribe( + this.packageCreationService.savePackage(blob).subscribe( bluePrintDetailModels => { if (bluePrintDetailModels) { const id = bluePrintDetailModels.toString().split('id')[1].split(':')[1].split('"')[1]; this.toastService.info('package updated successfully '); + this.isSaveEnabled = false; this.router.navigate(['/packages/package/' + id]); + this.refreshCurrentPackage(id); } }, error => { this.toastService.error('error happened when editing ' + error.message); @@ -218,6 +170,7 @@ export class ConfigurationDashboardComponent implements OnInit { this.configurationDashboardService.deletePackage(this.id).subscribe(res => { console.log('Deleted'); console.log(res); + this.isSaveEnabled = false; this.router.navigate(['/packages']); }, err => { console.log(err); @@ -245,13 +198,12 @@ export class ConfigurationDashboardComponent implements OnInit { } deployCurrentPackage() { - this.collectZipFileFromStore(); + this.formTreeData(); this.deployPackage(); } goToDesignerMode(id) { - // this.designerService.setActionName(this.customActionName); this.router.navigate(['/packages/designer', id, {actionName: this.customActionName}]); } @@ -268,52 +220,36 @@ export class ConfigurationDashboardComponent implements OnInit { } textChanged($event: {}) { - this.packageCreationStore.addTopologyTemplate(this.vlbDefinition.topology_template); + this.cbaPackage.templateTopology.node_templates = this.designerState.template.node_templates; + this.cbaPackage.templateTopology.workflows = this.designerState.template.workflows; + this.cbaPackage.templateTopology.content = this.vlbDefinition.topology_template.content; } enrichBluePrint() { - - this.collectZipFileFromStore(); + this.packageCreationStore.addTopologyTemplate(this.cbaPackage.templateTopology); + this.formTreeData(); this.enrichPackage(); + this.designerStore.clear(); + this.packageCreationStore.clear(); } - private collectZipFileFromStore() { - this.packageCreationStore.state$.subscribe( - cbaPackage => { - FilesContent.clear(); - console.log(cbaPackage); - 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); - }); - } private enrichPackage() { this.create(); this.zipFile.generateAsync({type: 'blob'}) .then(blob => { - this.packageCreationStore.enrichBluePrint(blob).subscribe(response => { + this.packageCreationService.enrichPackage(blob).subscribe(response => { console.log('success'); const blobInfo = new Blob([response], {type: 'application/octet-stream'}); - this.configurationDashboardService.getPagedPackages(this.id).subscribe( - (bluePrintDetailModels) => { - if (bluePrintDetailModels) { - this.packageCreationStore.clear(); - this.extractBlobToStore(blob, bluePrintDetailModels); - this.isSaveEnabled = true; - this.toastService.info('enriched successfully '); - } - }); - - // saveAs(blobInfo, 'test' + '-' + '1.0.0' + '-CBA.zip'); - + this.currentBlob = blobInfo; + this.packageCreationStore.clear(); + this.packageCreationExtractionService.extractBlobToStore(this.currentBlob); + this.isSaveEnabled = true; + this.toastService.info('enriched successfully '); }); }, error => { - this.toastService.error('error happened when editing ' + error.message); - console.log('Error -' + error.message); + this.toastService.error('error happened when enrich ' + error.message); + console.error('Error -' + error.message); }); } @@ -321,12 +257,11 @@ export class ConfigurationDashboardComponent implements OnInit { this.create(); this.zipFile.generateAsync({type: 'blob'}) .then(blob => { - this.packageCreationStore.deployBluePrint(blob).subscribe(response => { - console.log('success'); - console.log(response); - - // saveAs(blobInfo, 'test' + '-' + '1.0.0' + '-CBA.zip'); - + this.packageCreationService.deploy(blob).subscribe(response => { + this.toastService.info('deployed successfully '); + const id = response.toString().split('id')[1].split(':')[1].split('"')[1]; + this.isSaveEnabled = false; + this.router.navigate(['/packages/package/' + id]); }); }, error => { this.toastService.error('error happened when deploying ' + error.message); @@ -337,4 +272,24 @@ export class ConfigurationDashboardComponent implements OnInit { clickEvent() { this.isSaveEnabled = true; } + + canDeactivate(): boolean { + return this.isSaveEnabled; + } + + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + + checkSkipTypesOfAction() { + console.log(this.cbaPackage); + if (this.cbaPackage.templateTopology && this.cbaPackage.templateTopology.node_templates + && this.cbaPackage.templateTopology.workflows) { + this.goToDesignerMode(this.id); + } else { + this.dataTarget = '#exampleModalLong'; + } + } } + diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.css new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.css diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.html new file mode 100644 index 000000000..051ef1634 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.html @@ -0,0 +1,348 @@ +<div class="scrollWrapper"> + <div class="row m-0"> + <div class="col"> + <div class="form-group"> + <label for="exampleInputEmail1">Action Name</label> + <input type="text" class="form-control" placeholder="Action Name" + value="resource-assignment"> + </div> + </div> + </div> + <!--Add Attribute--> + <div class="row m-b add-attribute"> + <div class="col"> + <h5>Add Attribute</h5> + <div class="row"> + <div class="col pr-0 text-center"> + <button type="button" data-toggle="modal" data-target="#exampleModalScrollable" + class="btn btn-secondary"><i class="icon-custom-attribute" type="button" + aria-hidden="true"></i></button> + <span>Custom Attribute</span> + + + </div> + <div class="col text-center"> + <button type="button" class="btn btn-secondary"><i class="icon-function-attribute" + type="button" aria-hidden="true"></i></button> + <span>Function Attribute</span> + </div> + </div> + </div> + </div> + <!--INPUTS--> + <div class="accordion" id="accordionExample"> + <div class="card"> + <div class="card-header row" id="headingOne"> + <button class="btn btn-link" type="button" data-toggle="collapse" + data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> + Inputs + </button> + </div> + <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" + data-parent="#accordionExample"> + <div class="card-body action-attributes"> + <div class="row"> + <div class="col"> + <div class="form-group" *ngFor="let input of inputs"> + <label for="exampleFormControlTextarea1">{{input.name}} + <i [hidden]="!input.required" class="icon-required-star" + type="button" aria-hidden="true"></i> + <i [hidden]="input.required" type="button" aria-hidden="true"></i> + </label> + <div class="attributeOptions"> + <a data-toggle="modal" data-target="#exampleModalScrollable2" + class="accordion-delete editAttribute" + tooltip="Edit Attribute" placement="bottom"><i + class="icon-edit"></i></a> + <a class="accordion-delete deleteAttribute" + tooltip="Delete Attribute" placement="bottom"><i + class="icon-delete-sm"></i></a> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + </div> + <!--OUTPUTS--> + <div class="accordion" id="accordionExample1"> + <div class="card"> + <div class="card-header row" id="headingOne"> + <button class="btn btn-link" type="button" data-toggle="collapse" + data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo"> + Outputs + </button> + </div> + + <div id="collapseTwo" class="collapse show" aria-labelledby="headingOne" + data-parent="#accordionExample1"> + <div class="card-body"> + <div class="row"> + <div class="col"> + <div class="form-group" *ngFor="let output of outputs"> + <label for="exampleFormControlTextarea1">{{output.name}} + <i [hidden]="output.required" + class="icon-required-star optional-attribute" type="button" + aria-hidden="true"></i> + <i [hidden]="output.required" class="optional-attribute" + type="button" aria-hidden="true"></i> + </label> + </div> + </div> + </div> + </div> + </div> + </div> + </div> +</div> +<!--Action - Add Custom Attribute - Modal--> +<div class="modal fade" id="exampleModalScrollable" tabindex="-1" role="dialog" + aria-labelledby="exampleModalScrollableTitle" aria-hidden="true"> + <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalScrollableTitle"> + Add Custom Attributes</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <img src="assets/img/icon-close.svg"/> + </button> + </div> + <div class="modal-body createAttributeTabs"> + <!--Action - Inputs & Outputs Attribute--> + <ul class="nav nav-tabs" id="myTab" role="tablist"> + <li class="nav-item"> + <a class="nav-link active" id="home-tab" data-toggle="tab" href="#home" role="tab" + aria-controls="home" aria-selected="true">Inputs</a> + </li> + <li class="nav-item"> + <a class="nav-link" id="profile-tab" data-toggle="tab" href="#profile" role="tab" + aria-controls="profile" aria-selected="false">Outputs</a> + </li> + </ul> + <div class="tab-content" id="myTabContent"> + <!--INPUTS Tab--> + <div class="tab-pane fade show active create-form" id="home" role="tabpanel" + aria-labelledby="home-tab"> + <div class="form-group row"> + <label for="inputEmail3" class="col-sm-3 col-form-label">Name <span>*</span></label> + <div class="col-sm-9"> + <input [(ngModel)]="inputActionAttribute.name" type="email" class="form-control" + id="inputEmail3" placeholder="Attribute name"> + </div> + </div> + <div class="form-group row"> + <label for="inputPassword3" class="col-sm-3 col-form-label">Description</label> + <div class="col-sm-9"> + <input [(ngModel)]="inputActionAttribute.description" type="text" class="form-control" + id="inputPassword3" + placeholder="Add some description"> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Type <span>*</span></label> + <div class="col-sm-9"> + <div class="list-group list-group-horizontal"> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setInputType('String')"> + String + </button> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setInputType('Integer')">Integer + </button> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setInputType('Boolean')">Boolean + </button> + <button type="button" class="list-group-item list-group-item-action" + (click)="setInputType('List')">List + </button> + <button type="button" class="list-group-item list-group-item-action" + (click)="setInputType('Other')">Other + </button> + + </div> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Required <span>*</span></label> + <div class="col-sm-9"> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline1" name="customRadioInline1" + class="custom-control-input" (click)="setInputRequired(true)"> + <label class="custom-control-label" for="customRadioInline1">True</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline2" name="customRadioInline1" + class="custom-control-input" (click)="setInputRequired(false)"> + <label class="custom-control-label" for="customRadioInline2">False</label> + </div> + </div> + </div> + </div> + <!--OUTPUTS Tab--> + <div class="tab-pane fade create-form" id="profile" role="tabpanel" aria-labelledby="profile-tab"> + <div class="form-group row"> + <label for="inputEmail3" class="col-sm-3 col-form-label">Name <span>*</span></label> + <div class="col-sm-9"> + <input [(ngModel)]="outputActionAttribute.name" type="email" class="form-control" + id="inputEmail3" placeholder="Attribute name"> + </div> + </div> + <div class="form-group row"> + <label for="inputPassword3" class="col-sm-3 col-form-label">Description</label> + <div class="col-sm-9"> + <input [(ngModel)]="outputActionAttribute.description" + type="text" class="form-control" id="inputPassword3" + placeholder="Add some description"> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Type <span>*</span></label> + <div class="col-sm-9"> + <div class="list-group list-group-horizontal"> + <button type="button" class="list-group-item list-group-item-action">String</button> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setOutputType('Integer')"> + Integer + </button> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setOutputType('Boolean')"> + Boolean + </button> + <button type="button" class="list-group-item list-group-item-action" + (click)="setOutputType('List')"> + List + </button> + <button type="button" + class="list-group-item list-group-item-action" + (click)="setOutputType('Other')"> + Other + </button> + </div> + <input type="text" class="form-control mt-2 mb-2" id="inputPassword3" + placeholder="Add Other type name"> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Required <span>*</span></label> + <div class="col-sm-9"> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline1" name="customRadioInline1" + class="custom-control-input" (click)="setOutputRequired(true)"> + <label class="custom-control-label" for="customRadioInline1">True</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline2" name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" for="customRadioInline2" + (click)="setOutputRequired(false)">False</label> + </div> + </div> + </div> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary" (click)="submitAttributes()">Submit Attributes</button> + </div> + </div> + </div> +</div> +<!--Delete Action - Modal--> +<div class="modal fade" id="exampleModalScrollable1" tabindex="-1" role="dialog" + aria-labelledby="exampleModalScrollableTitle1" aria-hidden="true"> + <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalScrollableTitle1"> + Delete Action</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <img src="assets/img/icon-close.svg"/> + </button> + </div> + <div class="modal-body"> + Are you sure you want to delete <b>resource-assignment</b> action? + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary">Delete</button> + </div> + </div> + </div> +</div> +<!--Action - Edit Custom Attribute - Modal--> +<div class="modal fade" id="exampleModalScrollable2" tabindex="-1" role="dialog" + aria-labelledby="exampleModalScrollableTitle2" aria-hidden="true"> + <div class="modal-dialog modal-dialog-centered modal-dialog-scrollable" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <h5 class="modal-title" id="exampleModalScrollableTitle2"> + Edit Custom Attributes</h5> + <button type="button" class="close" data-dismiss="modal" aria-label="Close"> + <img src="assets/img/icon-close.svg"/> + </button> + </div> + <div class="modal-body createAttributeTabs"> + <div class="create-form"> + <div class="form-group row"> + <label for="inputEmail3" class="col-sm-3 col-form-label">Name <span>*</span></label> + <div class="col-sm-9"> + <input type="email" class="form-control" id="inputEmail3" placeholder="Attribute name" + value="resource-assignment-properties"> + </div> + </div> + <div class="form-group row"> + <label for="inputPassword3" class="col-sm-3 col-form-label">Description</label> + <div class="col-sm-9"> + <input type="text" class="form-control" id="inputPassword3" + placeholder="Add some description" + value="Dynamic PropertyDefinition for workflow(resource-assignment)."> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Type <span>*</span></label> + <div class="col-sm-9"> + <div class="list-group list-group-horizontal"> + <button type="button" + class="list-group-item list-group-item-action">String + </button> + <button type="button" class="list-group-item list-group-item-action">Integer</button> + <button type="button" class="list-group-item list-group-item-action">Boolean</button> + <button type="button" class="list-group-item list-group-item-action">List</button> + <button type="button" class="list-group-item list-group-item-action active">Other + </button> + </div> + <input type="text" class="form-control mt-2 mb-2" id="inputPassword3" + placeholder="Add Other type name" value="dt-resource-assignment-properties"> + </div> + </div> + <div class="form-group row"> + <label class="col-form-label col-sm-3 pt-0">Required <span>*</span></label> + <div class="col-sm-9"> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline1" name="customRadioInline1" + class="custom-control-input" checked> + <label class="custom-control-label" for="customRadioInline1">True</label> + </div> + <div class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline2" name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" for="customRadioInline2">False</label> + </div> + </div> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button> + <button type="button" class="btn btn-primary">Save</button> + </div> + </div> + </div> + </div> +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.spec.ts new file mode 100644 index 000000000..12078eb0d --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ActionAttributesComponent } from './action-attributes.component'; + +describe('ActionAttributesComponent', () => { + let component: ActionAttributesComponent; + let fixture: ComponentFixture<ActionAttributesComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ActionAttributesComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ActionAttributesComponent); + 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/action-attributes/action-attributes.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.ts new file mode 100644 index 000000000..f4f74a9fd --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/action-attributes.component.ts @@ -0,0 +1,58 @@ +import {Component, OnInit} from '@angular/core'; +import {InputActionAttribute, OutputActionAttribute} from './models/InputActionAttribute'; + +@Component({ + selector: 'app-action-attributes', + templateUrl: './action-attributes.component.html', + styleUrls: ['./action-attributes.component.css'] +}) +export class ActionAttributesComponent implements OnInit { + + inputs = []; + outputs = []; + actionAttributesSideBar: boolean; + inputActionAttribute = new InputActionAttribute(); + outputActionAttribute = new OutputActionAttribute(); + + constructor() { + + } + + ngOnInit() { + } + + _toggleSidebar2() { + this.actionAttributesSideBar = !this.actionAttributesSideBar; + } + + addInput(input: InputActionAttribute) { + this.inputs.push(input); + } + + addOutput(output: OutputActionAttribute) { + this.outputs.push(output); + } + + setInputType(type) { + this.inputActionAttribute.type = type; + } + + setInputRequired(isRequired) { + this.inputActionAttribute.required = isRequired; + } + + setOutputRequired(isRequired) { + this.outputActionAttribute.required = isRequired; + } + + setOutputType(type) { + this.outputActionAttribute.type = type; + } + + submitAttributes() { + console.log(this.inputActionAttribute); + console.log(this.outputActionAttribute); + this.inputs.push(this.inputActionAttribute); + this.outputs.push(this.outputActionAttribute); + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/models/InputActionAttribute.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/models/InputActionAttribute.ts new file mode 100644 index 000000000..3aa370360 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/action-attributes/models/InputActionAttribute.ts @@ -0,0 +1,17 @@ +export class InputActionAttribute { + name: string; + description: string; + type: string; + required: boolean; + + constructor() { + this.name = ''; + this.description = ''; + this.type = ''; + this.required = false; + } +} + +export class OutputActionAttribute extends InputActionAttribute { + +} 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 f7cff5072..43f3818a0 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 @@ -203,7 +203,9 @@ header{ font-size: 11px; line-height: 20px; } - +.save-blueprint li:hover{ + cursor: pointer; +} @@ -591,39 +593,69 @@ p.compType-4{ .componentContainer p{ font-size: 12px; } -.functionAttributeSidebar{ +.attributeSidebar{ width: 440px; padding: 0px; margin-top: 45px; } -.functionAttributeSidebar .attributesContainer{ +.attributesContainer{ + padding: 0; background: #fff; border: solid 1px #C1CDDD; box-shadow: 0 2px 6px rgba(47, 83, 151, .1); } /*ATTRIBUTES SIDE BAR*/ .attributesSideBar{ - width: 396px; + width: 358px; padding: 0px; - margin-top: 50px; + margin-top: 45px; } .attributesSideBar .attributesContainer{ + height: 85.9vh; + overflow-y: hidden; + padding-bottom: 20px; background: #fff; border: solid 1px #C1CDDD; box-shadow: 0 2px 6px rgba(47, 83, 151, .1); } .closeBar{ float: left; - width: 50%; - height: 42px; - background: url(/assets/img/icon-close.svg) center center #DCE8F4 no-repeat ; + padding: 0 !important; + width: 38px; + height: 35px; + background:#D9E3EE; border: 0; outline: 0; - margin-left: -30px; } .closeBar:focus{ outline: none; } +.attributesContainer .scrollWrapper{ + overflow-y: auto; + height: 79vh; +} +.attributesContainer .nav-link{ + padding-top: 7px !important; + padding-bottom: 7px !important; + color: #1B3E6F !important; + text-transform: capitalize !important; + border: solid 1px #ECEDF2 !important; + border-radius: 0 !important; +} +.attributesContainer .nav-item:first-child a{ + border-top-left-radius: 4px !important; + border-bottom-left-radius: 4px !important; + border-right-width: 0 !important; +} +.attributesContainer .nav-item:last-child a{ + border-top-right-radius: 4px !important; + border-bottom-right-radius: 4px !important; + border-left-width: 0 !important; +} +.nav-pills .nav-link.active{ + background-color: #1B3E6F; + color: #fff !important; +} .attributesContainer h1{ margin-bottom: 10px; padding: 12px 0 12px 15px; @@ -633,24 +665,91 @@ p.compType-4{ text-transform: uppercase; color: #1B3E6F; } +.attributesContainertTitle{ + height: 35px; + margin-bottom: 9px !important; + padding: 0; + background: #DEE8F3; + font-size: 12px; +} +.add-attribute{ + margin: 15px 0; + padding: 15px 9px; + background-color: #F4F9FE; +} +.add-attribute h5{ + padding: 0; + margin-bottom: 12px; + font-size: 12px; + font-weight: bold; + text-transform: uppercase; + color: #1B3E6F; +} +.add-attribute .btn{ + width: 100%; + background-color: #fff; + border: solid 1px #C1CDDD; + color: #1B3E6F; + line-height: 18px; + border-radius: 4px; +} +.add-attribute .btn:hover{ + background-color: #1B3E6F; +} +.add-attribute .btn:hover i::before{ + color: #fff; +} +.icon-function-attribute{ + font-size: 18px; +} +.add-attribute span{ + font-size: 11px; + line-height: 16px; +} +.attributesContainertTitle .btn-group{ + margin-top: 3px; +} +.attributesContainertTitle .btn{ + margin-left: 8px !important; + padding: 1px 9px !important; + border-radius: 4px !important; +} .attributesContainer h6{ - margin-bottom: 10px; - padding: 12px 0 12px 15px; + padding: 0; + margin-bottom: 0; background: #DEE8F3; + line-height: 35px !important; font-size: 12px; font-weight: bold; text-transform: uppercase; color: #1B3E6F; } -.actionName{ - margin-bottom: 21px; +.view-source, +.view-source:hover{ + background: #103D73; + border-color: #D0DFF1; + color: #fff; + font-size: 11px; +} +.trash-item, +.trash-item:hover{ + background: #fff; + border-color: #D0DFF1; + color: #103D73; +} +.trash-item{ + font-size: 14px; } .attributesContainer label{ color: #1B3E6F; - text-transform: uppercase; - font-size: 11px; + /* text-transform: uppercase; */ + font-size: 12px; font-weight: bold; } +.attributesContainer label.custom-control-label{ + text-transform: unset; + font-weight: normal; +} .attributesContainer .form-group{ margin-bottom: 9px; } @@ -668,23 +767,119 @@ p.compType-4{ .attributesContainer .form-control::placeholder{ color: #CFD7E5; } -.scrolll{ - max-height: 88.75vh; - overflow-y: auto; +.attributesContainer .attribute-value{ + text-transform: unset; + display: block; + width: 100%; + padding: 0 .75rem .375rem 0; + font-size: 12px; + font-weight: normal; +} +.attributesContainer textarea{ + height: 60px; +} +.icon-required-star{ + font-size: 10px; +} +.optional-attribute::before{ + color: #CAD3E0; +} +.attributeOptions{ + display: none; + border: 0; +} +.attributeOptions a:not(:first-child){ + margin-left: 18px; +} +.attributeOptions i{ + color: #103D73 !important; + font-size: 16px; +} +.editAttribute i{ + font-size: 14px; +} +.action-attributes .form-group{ + display: inline-block; + width: 100%; + padding-left: 12px; + /* line-height: 30px; */ +} +.action-attributes .form-group:hover{ + cursor: pointer !important; + background-color: #F5FAFF; +} +.action-attributes .form-group:hover label{ + cursor: pointer !important; + /* padding-left: 12px; */ +} +.action-attributes .form-group:hover .attributeOptions{ + display: inline-block; + position: relative; + left: 8%; + top: 3px; +} + +.btn-select-template{ + background-color: #C3CDDB; + border-radius: 2px; + color: #1B3E6F; + font-size: 12px; +} +.btn-select-template i{ + font-size: 16px; + vertical-align: text-bottom; +} +.attribute-wrap{ + padding-bottom: 15px; + margin-bottom: 9px; + border-bottom: solid 1px #F4F9FE; +} +.attribute-wrap .form-group{ + margin-bottom: 0; +} +.template-mapping-list{ + margin-bottom: 15px; + font-size: 13px; +} +.template-mapping-list p{ + width: 56%; +} +.deleteTemplate{ + right: 30px; + top: -8px; +} +.deleteTemplate i{ + color: #103D73 !important; +} +.icon-close::before{ + color: #103D73; + font-size: 10px !important; +} +.accordion{ + margin-top: 12px; } .accordion > .card{ margin-bottom: 0 !important; border: 0; + box-shadow: none; +} +.card-header .btn-link, +.accordion .card-header .btn-link[aria-expanded="true"], +.accordion .card-header .btn-link[aria-expanded="false"]{ + padding-left: 15px !important; + padding-right: 15px !important; } .accordion > .card .card-header{ margin: 0; - padding: 0; + padding: 0 !important; background-color: #F4F9FE; border: 0; border-radius: 0; } + .accordion > .card .card-body{ - padding-bottom: 10px !important; + padding-top: 20px !important; + padding-bottom: 0 !important; } .accordion .btn-link{ padding: 0; @@ -694,6 +889,9 @@ p.compType-4{ text-transform: uppercase; line-height: 15px; } +.btn-link::before{ + font-size: 15px !important; +} .accordion .btn-link:hover{ color: #103D73; text-decoration: unset; @@ -706,12 +904,12 @@ p.compType-4{ font-weight: normal; font-size: 12px; } -.accordion .card-header .btn-link[aria-expanded="true"]:after{ +/* .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; @@ -776,11 +974,7 @@ p.compType-4{ margin-left: 12px; font-weight: bold; } -.function-attribute{ - margin-right: -16px; -} .trash-span{ - margin-left: 150px; font-size:15px } @@ -854,3 +1048,10 @@ ul.editor{ .zoom-percent{ font-size: 12px; } +/*Modal*/ +.modal-backdrop{z-index: -1} +.modal-holder.modal-backdrop{z-index: 100} +.modal-holder + .modal-dialog {z-index: 1000} +.modal-dialog{ + max-width: 680px; +}
\ No newline at end of file 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 6a432fec8..537a0a8ca 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 @@ -10,9 +10,9 @@ </li> <i class="fa fa-angle-right ml-2 mr-2"></i> <li class="breadcrumb-item"> - <a href="/package/{{viewedPackage.id}}">{{viewedPackage.artifactName}}</a> + <a routerLink="/packages/package/{{viewedPackage.id}}">{{viewedPackage.artifactName}}</a> <button type="button" class="btn package-info-btn" data-toggle="modal" - data-target="#exampleModalLong"> + data-target="#exampleModalLong"> <i class="icon-info" aria-hidden="true"></i> </button> </li> @@ -22,13 +22,13 @@ </li> </ol> <div class="modal fade" id="exampleModalLong" tabindex="-1" role="dialog" - aria-labelledby="exampleModalLongTitle" aria-hidden="true"> + aria-labelledby="exampleModalLongTitle" aria-hidden="true"> <div class="modal-dialog" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="exampleModalLongTitle">Package Details</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> - <img src="assets/img/icon-close.svg" /> + <img src="assets/img/icon-close.svg"/> </button> </div> <div class="modal-body package-info"> @@ -70,15 +70,15 @@ <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"> + 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"> + 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"> + data-tooltip="Share"> <i class="fa fa-share-square"></i> </a> </div> @@ -87,12 +87,12 @@ <div class="dropdown"> <input class="dropdown-toggle" type="text"> <div class="dropdown-text">Save</div> - <ul class="dropdown-content"> + <ul class="dropdown-content save-blueprint"> <li> - <a href="">Save</a> + <a (click)="saveBluePrint()">Save</a> </li> <li> - <a href="">Save & Deploy</a> + <a (click)="publishBluePrint()">Save & Deploy</a> </li> </ul> </div> @@ -103,33 +103,36 @@ </div> </div> </header> - +<!--Editor Bar--> <nav class="editNavbar row source-button {{cl}} navbar navbar-expand-lg"> + <!--Actions/Functions Side Menu Toogole Button--> <button (click)="_toggleSidebar1()" class="toggoleBtn active btn tooltip-bottom" title="" aria-pressed="true" - data-tooltip="Collapse Side bar"> + data-tooltip="Collapse Side bar"> <i class="fa arr-size"></i> </button> + <!--Nav Tabs--> <div class="collapse navbar-collapse "> + <!--Action Tabs--> <ul class="navbar-nav"> <li class="nav-item active"> <nav class="row"> - <!--Nav Tabs--> <div class="col-12"> <div class="nav nav-tabs " id="nav-tab" role="tablist"> <a class="nav-item nav-link active col-6" id=" " data-toggle="tab" href="" role="tab" - aria-controls=" " aria-selected="false" autofocus #nameit>Workflow</a> + aria-controls=" " aria-selected="false" autofocus #nameit>Workflow</a> <a class="nav-item nav-link col-6" id=" " data-toggle="tab" href="" role="tab" - aria-controls=" " aria-selected="false">Template</a> + aria-controls=" " aria-selected="false">Template</a> </div> </div> </nav> </li> </ul> + <!--Requirement/Capability Legend--> <ul class="templateLegend ml-auto mr-auto p-0"> <li class="requirement"><i class="icon-rectangle" aria-hidden="true"></i> Requirement</li> <li class="capability"><i class="icon-rectangle" aria-hidden="true"></i> Capability</li> </ul> - + <!--Undo/Redo Buttons--> <ul class="editor navbar"> <li> <button type="button" class="btn tooltip-bottom" data-tooltip="Undo"> @@ -142,42 +145,43 @@ </button> </li> <li class="vertical_line"></li> - <li><button type="button" class="btn tooltip-bottom" data-tooltip="Zoom Out"> + <li> + <button type="button" class="btn tooltip-bottom" data-tooltip="Zoom Out"> <img src="/assets/img/icon-zoomOut.svg"> - </button></li> + </button> + </li> <li class="zoom-percent">100%</li> <li> <button type="button" class="btn tooltip-bottom" data-tooltip="Zoom In"> - <img src="/assets/img/icon-zoomIn.svg"> </button> + <img src="/assets/img/icon-zoomIn.svg"></button> </li> </ul> - + <!--Designer/Scripting View Tabs--> <ul class="navbar ml-2" style="list-style: none"> <li class="nav-item"> <div class="btn-group viewBtns" role="group"> <button type="button" class="btn btn-secondary topologySource active">Designer</button> <button [routerLink]="['/designer/source', viewedPackage.id]" type="button" - class="btn btn-secondary topologyView">Scripting</button> + class="btn btn-secondary topologyView">Scripting + </button> </div> </li> </ul> - </div> </nav> <ng-sidebar-container class="sidebar-container"> - <!-- Controller SideBar --> + <!--Left Side Menu--> <ng-sidebar [(opened)]="controllerSideBar" [sidebarClass]="'demo-sidebar controllerSidebar container-fluid'" - [mode]="'push'" #sidebarLeft> - + [mode]="'push'" #sidebarLeft> <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 col-6" id="nav-action-tab" data-toggle="tab" href="#nav-action" - role="tab" aria-controls="nav-action" aria-selected="false" autofocus #nameit>Actions</a> + role="tab" aria-controls="nav-action" aria-selected="false" autofocus #nameit>Actions</a> <a class="nav-item nav-link col-6" id="nav-function-tab" data-toggle="tab" href="#nav-function" - role="tab" aria-controls="nav-function" aria-selected="false">Functions</a> + role="tab" aria-controls="nav-function" aria-selected="false">Functions</a> </div> </div> </nav> @@ -185,10 +189,17 @@ <div class="col"> <div class="tab-content" id="nav-tabContent"> <div class="tab-pane fade show active" id="nav-action" role="tabpanel" - aria-labelledby="nav-action-tab"> + aria-labelledby="nav-action-tab"> <!--Action Search Box--> <input type="text" class="form-control input-search-controller" placeholder="Search Actions"> - + <button (click)="sidebarRight1.open()" type="button" class="btn btn-primary"> + Action Attributes + </button> + <br/><br/> + <button (click)="sidebarRight2.open()" type="button" class="btn btn-secondary"> + Function Attributes + </button> + <br/> <button (click)="insertCustomActionIntoBoard()" type="button" class="btn new-action"> + New Action </button> @@ -197,23 +208,31 @@ <label><i class="icon-file" aria-hidden="true"></i> {{customActionName}} </label> </div> + <div *ngIf="!showAction" class="custom-control"> + <ul> + <li *ngFor="let customActionName of actions"> + <label> + <i class="icon-file" aria-hidden="true" class="icon-file" + (click)="openFunctionAttributes(customActionName)"></i> + {{customActionName}} </label> + </li> + </ul> + </div> </div> </div> <div class="tab-pane fade" id="nav-function" role="tabpanel" aria-labelledby="nav-function-tab"> <!--Function Search Box--> <input type="text" class="form-control input-search-controller" placeholder="Search Functions"> - <div id="palette-paper" class="componentsList"> </div> + <div id="palette-paper" class="componentsList"></div> </div> - </div> </div> </div> - <div class="helpBox"><i class="icon-info" aria-hidden="true"></i><a - href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank">Help - Learn The Basics</a> + <div class="helpBox"><i class="icon-info" aria-hidden="true"></i> + <a href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank">Help - Learn The Basics</a> </div> </ng-sidebar> - <!-- Page content --> - + <!--Page content--> <div ng-sidebar-content id="board-paper"> <button class="rotate" (click)="_toggleSidebar1()"> <span> @@ -222,7 +241,9 @@ </span> </button> - <!-- Canvas --> + + <!-- CANVAS --> + <!--Editor Bar--> <div 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"> @@ -246,396 +267,64 @@ <button type="button" class="btn btn-secondary topologyView">Source</button> </div> </div> - <!-- <div class="card actionContainer"> - <div class="card-header"> - <span>Action 1</span> - </div> - <div class="card-body"> - <a (click)="sidebarRight.open()" class="componentContainer text-center"> - <img src="/assets/img/icon-comType1.svg" title=""> - <h2>config-assign</h2> - <p>component-resource-resolution</p> - </a> - <a (click)="sidebarRight.open()" class="componentContainer text-center"> - <img src="/assets/img/icon-comType2.svg" title=""> - <h2>execute</h2> - <p>component-netconf-executor</p> - </a> - <a (click)="sidebarRight.open()" class="componentContainer text-center"> - <img src="/assets/img/icon-comType3.svg" title=""> - <h2>function 1</h2> - <p>dg-generic</p> - </a> - <a (click)="sidebarRight.open()" class="componentContainer text-center"> - <img src="/assets/img/icon-comType2.svg" title=""> - <h2>execute</h2> - <p>component-netconf-executor</p> - </a> - </div> - </div> --> - <!-- <button (click)="_toggleSidebar2()" style="float:right;">Toggle sidebar right</button> --> + <!--<button (click)="_toggleSidebar2()" style="float:right;">Toggle sidebar right</button> --> </div> - <!-- Action Attribute SideBar --> - <ng-sidebar [(opened)]="attributesSideBar" [sidebarClass]="'demo-sidebar attributesSideBar '" [mode]="'push'" - [position]="'right'" #sidebarRight> + <ng-sidebar [(opened)]="actionAttributesSideBar" [sidebarClass]="'demo-sidebar attributesSideBar '" [mode]="'push'" + [position]="'right'" #sidebarRight1> <div class="container-fluid0"> <div class="row m-0"> - <div class="col-2 pr-0"> - <button (click)="sidebarRight.close()" class="closeBar"></button> - </div> - <div class="col-10 attributesContainer p-0"> - <h1>Action Attributes</h1> - <div class="scrolll"> - <div class="row m-0"> - <div class="col"> - <div class="form-group actionName"> - <label for="exampleInputEmail1">Action Name</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - </div> + <div class="col attributesContainer"> + <div class="row m-0 attributesContainertTitle"> + <div class="col-2 pl-0"> + <button (click)="sidebarRight1.close()" class="closeBar" tooltip="Close" placement="bottom"> + <i + class="icon-close" type="button" aria-hidden="true"></i></button> </div> - <div class="accordion" id="accordionExample"> - <div class="card"> - <div class="card-header row" id="headingOne"> - <h2 class="col-10 mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" - data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> - Steps - </button> - </h2> - <div class="col-2 p-0 text-center"> - <button class="btn btn-addAttribute" type="button"></button> - </div> - </div> - - <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" - data-parent="#accordionExample"> - <div class="card-body"> - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">Name</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Name</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - <div class="form-group"> - <label for="exampleFormControlTextarea1">Description</label> - <textarea class="form-control" id="exampleFormControlTextarea1" - rows="3"></textarea> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Target</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - - </div> - </div> - </div> - <div class="card"> - <div class="card-header row" id="headingTwo"> - <h2 class="col-10 mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" - data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo"> - Inputs - </button> - </h2> - <div class="col-2 p-0 text-center"> - <button class="btn btn-addAttribute" type="button"></button> - </div> - </div> - <div id="collapseTwo" class="collapse show" aria-labelledby="headingTwo" - data-parent="#accordionExample"> - <div class="card-body"> - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">Name</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Name</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - <div class="form-group"> - <label for="exampleFormControlTextarea1">Description</label> - <textarea class="form-control" id="exampleFormControlTextarea1" - rows="3"></textarea> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Target</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - - </div> - </div> - </div> - <div class="card"> - <div class="card-header row" id="headingThree"> - <h2 class="col-10 mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" - data-target="#collapseThree" aria-expanded="true" - aria-controls="collapseThree"> - Outputs - </button> - </h2> - <div class="col-2 p-0 text-center"> - <button class="btn btn-addAttribute" type="button"></button> - </div> - </div> - <div id="collapseThree" class="collapse show" aria-labelledby="headingThree" - data-parent="#accordionExample"> - <div class="card-body"> - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">Name</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Name</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - <div class="form-group"> - <label for="exampleFormControlTextarea1">Description</label> - <textarea class="form-control" id="exampleFormControlTextarea1" - rows="3"></textarea> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Target</label> - <input type="text" class="form-control" placeholder="Action 1"> - </div> - - </div> - </div> + <h6 class="col pl-0">Action Attributes</h6> + <div class="col-3 pl-0"> + <div class="btn-group" role="group" aria-label="Basic example"> + <button type="button" class="btn view-source" tooltip="View Action Source" + placement="bottom"><i class="icon-source"></i></button> + <button type="button" data-toggle="modal" data-target="#exampleModalScrollable1" + class="btn trash-item" tooltip="Delete Action" placement="bottom"><i + class="icon-delete-sm" aria-hidden="true"></i></button> </div> </div> </div> + <app-action-attributes></app-action-attributes> </div> </div> </div> </ng-sidebar> - - <!-- Function Attribute SideBar --> - <ng-sidebar [(opened)]="functionAttributeSidebar" [sidebarClass]="'demo-sidebar functionAttributeSidebar '" - [mode]="'push'" [position]="'right'" #sidebarRight> + <!--Right Side Menu - Function Attribute--> + <ng-sidebar [(opened)]="functionAttributeSidebar" [sidebarClass]="'demo-sidebar attributesSideBar'" [mode]="'push'" + [position]="'right'" #sidebarRight2> <div class="container-fluid0"> <div class="row m-0"> - <div class="col-2 pr-0"> - <!-- <button (click)="sidebarRight.close()" class="closeBar"></button> --> - </div> - <div class="col-10 attributesContainer p-0"> - <div class="row m-0"> - <div class="col"> - <div class="col-3"> - <button (click)="sidebarRight.close()" class="closeBar"></button> - </div> - - <div class="function-attribute"> - <h6>Function Attributes - <span class="trash-span"> - <i class="fa fa-trash" type="button" aria-hidden="true"></i> - </span> - </h6> - </div> - - - </div> - </div> - - <div> - <div class="row m-0"> - <div class="col"> - <div class="form-group actionName"> - <label for="exampleInputEmail1">Function Name</label> - <input type="text" class="form-control" placeholder="Function Name"> - </div> - </div> - </div> - <div class="row m-0"> - <div class="col"> - <div class=" actionName"> - <label>Function Type</label> - <div class="dropdown w-100"> - <input class="dropdown-toggle" type="text"> - <div class="dropdown-text">component-resource-resolution <i - class="fa fa-caret-down"></i></div> - <ul class="dropdown-content w-100"> - <li> - <div class="form-group "> - <li>other component</li> - </div> - </li> - </ul> - </div> - </div> + <div class="col attributesContainer"> + <div class="row m-0 attributesContainertTitle"> + <div class="col-2 pl-0"> + <button (click)="sidebarRight2.close()" class="closeBar" tooltip="Close" + placement="bottom"><i class="icon-close" type="button" aria-hidden="true"></i> + </button> </div> - </div> - <div class="accordion" id="accordionExample"> - <div class="card"> - <div class="card-header row" id="headingOne"> - <h2 class="col-10 mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" - data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> - Interface - </button> - </h2> - <div class="col-2 p-0 text-center"> - <button class="btn btn-addAttribute" type="button"></button> - </div> - </div> - - <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" - data-parent="#accordionExample"> - <div class="card-body"> - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">ResourceResolutionComponent</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Resoluton-key</label> - <input type="text" class="form-control"> - </div> - <div class="form-group"> - <label for="exampleFormControlTextarea1">Store result</label> - </div> - <div class="form-group"> - <label> - <input class="with-gap radio-btn" name="group1" type="radio" /> - <span class="radio-btn">True</span> - </label> - <label class="radio-btn"> - <input class="with-gap radio-btn" name="group1" type="radio" /> - <span class="radio-btn">False</span> - </label> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Target</label> - <input type="text" class="form-control" placeholder=""> - </div> - <div class="form-group"> - <label for="exampleFormControlTextarea1">Artifact Prefix Name</label> - <input type="text" class="form-control" placeholder=""> - - </div> - - </div> - </div> - </div> - - </div> - - <div class="accordion" id="accordionExample"> - <div class="card"> - <div class="card-header row" id="headingOne"> - <h2 class="col-10 mb-0"> - <button class="btn btn-link" type="button" data-toggle="collapse" - data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> - Artifact - </button> - </h2> - <div class="col-2 p-0 text-center"> - <button class="btn btn-addAttribute" type="button"></button> - </div> - </div> - - <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" - data-parent="#accordionExample"> - <div class="card-body"> - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">base config-template</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Type</label> - <div class="dropdown w-100"> - <input class="dropdown-toggle" type="text"> - <div class="dropdown-text">artifact-template-velocity <i - class="fa fa-caret-down"></i></div> - <ul class="dropdown-content w-100"> - <li> - <div class="form-group "> - <li>ddwd</li> - </div> - </li> - </ul> - </div> - </div> - - <div style="height: 30px; margin-top: 30px;"> - <hr> - </div> - - <div class="row"> - <div class="col-9"> - <label for="exampleInputEmail1">base config-mapping</label> - <button type="button" class="btn p-0"> - <img src="/assets/img/icon-edit.svg"> - </button> - </div> - <div class="col-3"> - <button type="button" class="btn btn-deleteAttribute">Delete</button> - </div> - </div> - <div class="form-group"> - <label for="exampleInputEmail1">Type</label> - <div class="dropdown w-100"> - <input class="dropdown-toggle" type="text"> - <div class="dropdown-text">artifact-mapping resource <i - class="fa fa-caret-down"></i></div> - <ul class="dropdown-content w-100"> - <li> - <div class="form-group "> - <li>ddwd</li> - </div> - </li> - </ul> - </div> - </div> - - <div style="height: 30px; margin-top: 30px;"> - <hr> + <h6 class="col pl-0">Function Attributes</h6> + <div class="col-3 pl-0"> + <div class="btn-group" role="group" aria-label="Basic example"> + <button type="button" class="btn view-source" tooltip="View Function Source" + placement="bottom"><i class="icon-source"></i></button> + <button type="button" class="btn trash-item" tooltip="Delete Function" + placement="bottom"><i class="icon-delete-sm" type="button" + aria-hidden="true"></i></button> </div> </div> </div> + <app-functions-attribute></app-functions-attribute> </div> - </div> </div> - </div> - </div> - </div> </ng-sidebar> -</ng-sidebar-container>
\ No newline at end of file + +</ng-sidebar-container> + 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 9462caf68..1475f1ac3 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 @@ -5,6 +5,8 @@ Copyright (C) 2019 Orange. All rights reserved. =================================================================== Modification Copyright (c) 2020 IBM =================================================================== +Modification Copyright (c) 2020 Orange +=================================================================== Unless otherwise specified, all software contained herein is licensed under the Apache License, Version 2.0 (the License); @@ -23,348 +25,454 @@ limitations under the License. import dagre from 'dagre'; import graphlib from 'graphlib'; -import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core'; +import {Component, OnDestroy, OnInit, ViewEncapsulation} 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, empty } from 'rxjs'; -import { takeUntil } from 'rxjs/operators'; -import { distinctUntilChanged } from 'rxjs/operators'; -import { BluePrintDetailModel } from '../model/BluePrint.detail.model'; -import { ActivatedRoute } from '@angular/router'; -import { DesignerService } from './designer.service'; -import { isDefined } from '@angular/compiler/src/util'; +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 {distinctUntilChanged, takeUntil} from 'rxjs/operators'; +import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; +import {ActivatedRoute, Router} from '@angular/router'; +import {DesignerService} from './designer.service'; +import {FilesContent, FolderNodeElement} from '../package-creation/mapping-models/metadata/MetaDataTab.model'; +import {PackageCreationModes} from '../package-creation/creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from '../package-creation/creationModes/PackageCreationBuilder'; +import {PackageCreationStore} from '../package-creation/package-creation.store'; +import {PackageCreationService} from '../package-creation/package-creation.service'; +import {PackageCreationUtils} from '../package-creation/package-creation.utils'; +import * as JSZip from 'jszip'; +import {PackageCreationExtractionService} from '../package-creation/package-creation-extraction.service'; +import {CBAPackage} from '../package-creation/mapping-models/CBAPacakge.model'; +import {TopologyTemplate} from './model/designer.topologyTemplate.model'; +import {ToastrService} from 'ngx-toastr'; @Component({ - selector: 'app-designer', - templateUrl: './designer.component.html', - styleUrls: ['./designer.component.css'], - encapsulation: ViewEncapsulation.None + selector: 'app-designer', + templateUrl: './designer.component.html', + styleUrls: ['./designer.component.css'], + encapsulation: ViewEncapsulation.None }) export class DesignerComponent implements OnInit, OnDestroy { - controllerSideBar: boolean; - attributesSideBar: boolean; - functionAttributeSidebar: boolean; - viewedPackage: BluePrintDetailModel = new BluePrintDetailModel(); - customActionName: string; - showAction: boolean; - cl = 'editBar'; - - boardGraph: joint.dia.Graph; - boardPaper: joint.dia.Paper; - - paletteGraph: joint.dia.Graph; - palettePaper: joint.dia.Paper; - ngUnsubscribe = new Subject(); - opt = { tx: 100, ty: 100 }; - - constructor( - private designerStore: DesignerStore, - private functionStore: FunctionsStore, - private graphUtil: GraphUtil, - private graphGenerator: GraphGenerator, - private route: ActivatedRoute, - private designerService: DesignerService) { - this.controllerSideBar = true; - this.attributesSideBar = false; - this.showAction = false; - this.functionAttributeSidebar = false; - - } - _toggleSidebar1() { - this.controllerSideBar = !this.controllerSideBar; - if (this.controllerSideBar === false) { - this.cl = 'editBar2'; + controllerSideBar: boolean; + actionAttributesSideBar: boolean; + functionAttributeSidebar: boolean; + viewedPackage: BluePrintDetailModel = new BluePrintDetailModel(); + customActionName: string; + showAction: boolean; + cl = 'editBar'; + + boardGraph: joint.dia.Graph; + boardPaper: joint.dia.Paper; + + paletteGraph: joint.dia.Graph; + palettePaper: joint.dia.Paper; + ngUnsubscribe = new Subject(); + opt = {tx: 100, ty: 100}; + filesData: any = []; + folder: FolderNodeElement = new FolderNodeElement(); + zipFile: JSZip = new JSZip(); + cbaPackage: CBAPackage; + actions: string[] = []; + dataTarget: string; + + constructor( + private designerStore: DesignerStore, + private functionStore: FunctionsStore, + private packageCreationStore: PackageCreationStore, + private packageCreationUtils: PackageCreationUtils, + private graphUtil: GraphUtil, + private graphGenerator: GraphGenerator, + private route: ActivatedRoute, + private router: Router, + private designerService: DesignerService, + private packageCreationService: PackageCreationService, + private packageCreationExtractionService: PackageCreationExtractionService, + private toastService: ToastrService) { + this.controllerSideBar = true; + this.actionAttributesSideBar = false; + this.showAction = false; + this.functionAttributeSidebar = false; + + } + + _toggleSidebar1() { + this.controllerSideBar = !this.controllerSideBar; + if (this.controllerSideBar === false) { + this.cl = 'editBar2'; + } + if (this.controllerSideBar === true) { + this.cl = 'editBar'; + } } - if (this.controllerSideBar === true) { - this.cl = 'editBar'; + + _toggleSidebar2() { + this.actionAttributesSideBar = !this.actionAttributesSideBar; } - } - _toggleSidebar2() { - this.attributesSideBar = !this.attributesSideBar; - } - // private _toggleSidebar3() { - // this.functionAttributeSidebar = !this.functionAttributeSidebar; - // } - - - /** - * - There is a board (main paper) that will the action and function selected from the palette - * itmes in this board will be used to create tosca workflow and node templates - * - There is also palette , whis contains all the possible functions and actions - * that can be dragged into the board - * - There is also a fly paper , which is temporarliy paper created on the fly - * when items is dragged from the palette- and it's deleted when the item is dropped over - * the board. - * for more info about the drag and drop algorithem used please visit the following link: - * https://stackoverflow.com/a/36932973/1340034 - */ - - ngOnInit() { - this.customActionName = this.route.snapshot.paramMap.get('actionName'); - if (this.customActionName !== '') { - this.showAction = true; + + publishBluePrint() { + this.create(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + const formData = new FormData(); + formData.append('file', blob); + this.designerService.publishBlueprint(formData).subscribe(res => { + console.log('Package Deployed...'); + }, error => { + console.log(error); + }, () => { + // this.deployBluePrint = false; + }); + }); } - this.initializeBoard(); - this.initializePalette(); - this.stencilPaperEventListeners(); - const id = this.route.snapshot.paramMap.get('id'); - this.designerService.getPagedPackages(id).subscribe( - (bluePrintDetailModels) => { - if (bluePrintDetailModels) { - this.viewedPackage = bluePrintDetailModels[0]; - } - }); + + // private _toggleSidebar3() { + // this.functionAttributeSidebar = !this.functionAttributeSidebar; + // } + + /** - * the code to retrieve from server is commented + * - There is a board (main paper) that will the action and function selected from the palette + * itmes in this board will be used to create tosca workflow and node templates + * - There is also palette , whis contains all the possible functions and actions + * that can be dragged into the board + * - There is also a fly paper , which is temporarliy paper created on the fly + * when items is dragged from the palette- and it's deleted when the item is dropped over + * the board. + * for more info about the drag and drop algorithem used please visit the following link: + * https://stackoverflow.com/a/36932973/1340034 */ - 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++); - }); - } - }); - - 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(); - - } - - initializePalette() { - if (!this.paletteGraph) { - this.paletteGraph = new joint.dia.Graph(); - this.palettePaper = new joint.dia.Paper({ - el: $('#palette-paper'), - model: this.paletteGraph, - width: 318, - 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: 1100, - gridSize: 10, - drawGrid: true, - // background: { - // color: 'rgba(0, 255, 0, 0.3)' - // }, - cellViewNamespace: joint.shapes - }); - - this.boardPaper.on('all', element => { - // console.log(element); - }); - - this.boardPaper.on('link:pointerdown', link => { - console.log(link); - }); - - this.boardPaper.on('element:pointerdown', element => { - // this.modelSelected.emit(element.model.get('model')); - }); - - this.boardPaper.on('blank:pointerclick', () => { - // this.selectedModel = undefined; - }); - - this.boardGraph.on('change:position', (cell) => { - - const parentId = cell.get('parent'); - if (!parentId) { - // this is action - return; + + ngOnInit() { + this.customActionName = this.route.snapshot.paramMap.get('actionName'); + if (this.customActionName !== '') { + this.showAction = true; } + this.initializeBoard(); + this.initializePalette(); + this.stencilPaperEventListeners(); + const id = this.route.snapshot.paramMap.get('id'); + this.designerService.getPagedPackages(id).subscribe( + (bluePrintDetailModels) => { + if (bluePrintDetailModels) { + this.viewedPackage = bluePrintDetailModels[0]; + this.packageCreationService.downloadPackage(this.viewedPackage.artifactName + '/' + + this.viewedPackage.artifactVersion) + .subscribe(response => { + const blob = new Blob([response], {type: 'application/octet-stream'}); + this.packageCreationExtractionService.extractBlobToStore(blob); + }); + } + }); + this.packageCreationStore.state$.subscribe(cba => { + this.cbaPackage = cba; + console.log(cba.templateTopology.content); + this.designerStore.saveSourceContent(cba.templateTopology.content); - const parent = this.boardGraph.getCell(parentId); + }); - 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())) { + /** + * 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++); + }); + } + }); + + 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: TopologyTemplate = JSON.parse(state.sourceContent); + console.log(topologtTemplate); + delete state.sourceContent; + this.graphGenerator.clear(this.boardGraph); + 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' + }); + this.actions = []; + for (const workflowsKey in topologtTemplate.workflows) { + if (workflowsKey && !this.actions.includes(workflowsKey)) { + this.actions.push(workflowsKey); + } + } + } + }); + + // action triggering + this.functionStore.retrieveFuntions(); - // All the four corners of the child are inside - // the parent area. - return; + } + + initializePalette() { + if (!this.paletteGraph) { + this.paletteGraph = new joint.dia.Graph(); + this.palettePaper = new joint.dia.Paper({ + el: $('#palette-paper'), + model: this.paletteGraph, + width: 318, + 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 + }); } + } - // Revert the child position. - cell.set('position', cell.previous('position')); - }); + 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: 1100, + gridSize: 10, + drawGrid: true, + // background: { + // color: 'rgba(0, 255, 0, 0.3)' + // }, + cellViewNamespace: joint.shapes + }); + + this.boardPaper.on('all', element => { + // console.log(element); + }); + + this.boardPaper.on('link:pointerdown', link => { + console.log(link); + }); + + this.boardPaper.on('element:pointerdown', element => { + // this.modelSelected.emit(element.model.get('model')); + }); + + this.boardPaper.on('blank:pointerclick', () => { + // this.selectedModel = undefined; + }); + + this.boardGraph.on('change:position', (cell) => { + + const parentId = cell.get('parent'); + if (!parentId) { + // this is action + return; + } + + const parent = this.boardGraph.getCell(parentId); + + 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; + } + + // Revert the child position. + cell.set('position', cell.previous('position')); + }); + } + console.log('done initializing Board...'); } - console.log('done initializing Board...'); - } - insertCustomActionIntoBoard() { - console.log('saving action to store action workflow....'); - const actionName = this.graphUtil.generateNewActionName(); - this.graphUtil.createCustomActionWithName(actionName, this.boardGraph); - this.designerStore.addDeclarativeWorkFlow(actionName); - } + insertCustomActionIntoBoard() { + 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) => { + stencilPaperEventListeners() { + this.palettePaper.on('cell:pointerdown', (draggedCell, pointerDownEvent, x, y) => { - $('body').append(` + $('body').append(` <div id="flyPaper" style="position:fixed;z-index:100;opacity:.7;pointer-event:none;background-color: transparent !important;"></div>` - ); - const flyGraph = new joint.dia.Graph(); - const flyPaper = new joint.dia.Paper({ - el: $('#flyPaper'), - model: flyGraph, - interactive: true - }); - const flyShape = draggedCell.model.clone(); - const pos = draggedCell.model.position(); - const offset = { - x: x - pos.x, - y: y - pos.y - }; - - flyShape.position(0, 0); - flyGraph.addCell(flyShape); - $('#flyPaper').offset({ - left: pointerDownEvent.pageX - offset.x, - top: pointerDownEvent.pageY - offset.y - }); - $('body').on('mousemove.fly', mouseMoveEvent => { - $('#flyPaper').offset({ - left: mouseMoveEvent.pageX - offset.x, - top: mouseMoveEvent.pageY - offset.y + ); + const flyGraph = new joint.dia.Graph(); + const flyPaper = new joint.dia.Paper({ + el: $('#flyPaper'), + model: flyGraph, + interactive: true + }); + const flyShape = draggedCell.model.clone(); + const pos = draggedCell.model.position(); + const offset = { + x: x - pos.x, + y: y - pos.y + }; + + flyShape.position(0, 0); + flyGraph.addCell(flyShape); + $('#flyPaper').offset({ + left: pointerDownEvent.pageX - offset.x, + top: pointerDownEvent.pageY - offset.y + }); + $('body').on('mousemove.fly', mouseMoveEvent => { + $('#flyPaper').offset({ + left: mouseMoveEvent.pageX - offset.x, + top: mouseMoveEvent.pageY - offset.y + }); + }); + + $('body').on('mouseup.fly', mouseupEvent => { + const mouseupX = mouseupEvent.pageX; + const mouseupY = mouseupEvent.pageY; + const target = this.boardPaper.$el.offset(); + // Dropped over paper ? + if (mouseupX > target.left && + mouseupX < target.left + this.boardPaper.$el.width() && + mouseupY > target.top && y < target.top + this.boardPaper.$el.height()) { + 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 (parentCell && + parentCell.model.get('parent') !== functionElementForBoard.id) { + parentCell.model.embed(functionElementForBoard); + } + } 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(); + }); }); - }); - - $('body').on('mouseup.fly', mouseupEvent => { - const mouseupX = mouseupEvent.pageX; - const mouseupY = mouseupEvent.pageY; - const target = this.boardPaper.$el.offset(); - // Dropped over paper ? - if (mouseupX > target.left && - mouseupX < target.left + this.boardPaper.$el.width() && - mouseupY > target.top && y < target.top + this.boardPaper.$el.height()) { - 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 (parentCell && - parentCell.model.get('parent') !== functionElementForBoard.id) { - parentCell.model.embed(functionElementForBoard); - } - } 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()...'); - } - - ngOnDestroy() { - this.ngUnsubscribe.next(); - this.ngUnsubscribe.complete(); - } + console.log('done stencilPaperEventListeners()...'); + } + + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } + + saveBluePrint() { + + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + this.designerStore.state$.subscribe(state => { + this.cbaPackage.templateTopology.content = this.packageCreationUtils.transformToJson(state.template); + }); + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); + this.saveBluePrintToDataBase(); + + } + + create() { + this.zipFile = new JSZip(); + FilesContent.getMapOfFilesNamesAndContent().forEach((value, key) => { + this.zipFile.folder(key.split('/')[0]); + this.zipFile.file(key, value); + }); + + } + + saveBluePrintToDataBase() { + this.create(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.packageCreationService.savePackage(blob).subscribe( + bluePrintDetailModels => { + this.toastService.info('success updating the package'); + const id = bluePrintDetailModels.toString().split('id')[1].split(':')[1].split('"')[1]; + this.router.navigate(['/packages/designer/' + id]); + console.log('success'); + }, error => { + this.toastService.error('error happened when editing ' + error.message); + console.log('Error -' + error.message); + }); + }); + } + + openFunctionAttributes(customActionName: string) { + console.log('opening here function attributes'); + } } 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 771c44ba8..c0d79cae1 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 @@ -21,11 +21,11 @@ limitations under the License. ============LICENSE_END============================================ */ -import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; -import {ApiService} from '../../../../common/core/services/api.typed.service'; -import {ResourceDictionaryURLs, BlueprintURLs} from '../../../../common/constants/app-constants'; -import {ModelType} from './model/ModelType.model'; +import { Injectable } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ApiService } from '../../../../common/core/services/api.typed.service'; +import { ResourceDictionaryURLs, BlueprintURLs } from '../../../../common/constants/app-constants'; +import { ModelType } from './model/ModelType.model'; import { BluePrintDetailModel } from '../model/BluePrint.detail.model'; @@ -34,8 +34,10 @@ import { BluePrintDetailModel } from '../model/BluePrint.detail.model'; }) export class DesignerService { - constructor(private api: ApiService<ModelType>, - private api2: ApiService<BluePrintDetailModel>) { + constructor( + private api: ApiService<ModelType>, + private api2: ApiService<BluePrintDetailModel> + ) { } getFunctions(modelDefinitionType: string): Observable<ModelType[]> { @@ -50,4 +52,9 @@ export class DesignerService { return this.getBluePrintModel(id); } + publishBlueprint(body: any | null, options?: any): Observable<any> { + + return this.api.post(BlueprintURLs.publish, body, { responseType: 'text' }); + } + } 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 ba8b2f0f1..e07fbb94d 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 @@ -23,8 +23,8 @@ import {Injectable} from '@angular/core'; import {Store} from '../../../../common/core/stores/Store'; import {DesignerService} from './designer.service'; import {DesignerDashboardState} from './model/designer.dashboard.state'; -import { DeclarativeWorkflow } from './model/designer.workflow'; -import { NodeTemplate } from './model/desinger.nodeTemplate.model'; +import {DeclarativeWorkflow} from './model/designer.workflow'; +import {NodeTemplate} from './model/desinger.nodeTemplate.model'; @Injectable({ @@ -54,7 +54,7 @@ export class DesignerStore extends Store<DesignerDashboardState> { }); } - addStepToDeclarativeWorkFlow(workflowName: string, stepName: string, stepType: string) { + addStepToDeclarativeWorkFlow(workflowName: string, stepName: string, stepType: string) { this.setState({ ...this.state, template: { @@ -76,12 +76,15 @@ export class DesignerStore extends Store<DesignerDashboardState> { } saveSourceContent(code: string) { - const topologyTemplate = JSON.parse(code); - this.setState({ - ...this.state, - sourceContent: code, - template: topologyTemplate - }); + console.log(code); + if (code) { + const topologyTemplate = JSON.parse(code); + this.setState({ + ...this.state, + sourceContent: code, + template: topologyTemplate + }); + } } @@ -141,4 +144,9 @@ export class DesignerStore extends Store<DesignerDashboardState> { } }); } + + clear() { + this.setState(new DesignerDashboardState()); + } + } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.css new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.css diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.html new file mode 100644 index 000000000..c89a96de0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.html @@ -0,0 +1,178 @@ +<div class="scrollWrapper"> + <div class="row m-0"> + <div class="col"> + <div class="form-group"> + <label for="exampleInputEmail1">Function Instance Name</label> + <input type="text" class="form-control" placeholder="Function Instance Name"> + </div> + <div class="form-group"> + <label>Function Type</label> + <label class="attribute-value">component-resource-resolution</label> + </div> + <div class="form-group"> + <label for="exampleFormControlTextarea1">Description</label> + <textarea class="form-control" id="exampleFormControlTextarea1" rows="3"></textarea> + </div> + </div> + </div> + <!--INTERFACES--> + <div class="accordion" id="accordionExample"> + <div class="card"> + <div class="card-header row" id="headingOne"> + <button class="btn btn-link" type="button" data-toggle="collapse" + data-target="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> + Interfaces + </button> + </div> + + <div id="collapseOne" class="collapse show" aria-labelledby="headingOne" + data-parent="#accordionExample"> + <div class="card-body"> + <!--Inputs & Outputs Tabs--> + <ul class="nav nav-pills nav-fill mb-3" id="pills-tab" role="tablist"> + <li class="nav-item" role="presentation"> + <a class="nav-link active" id="pills-home-tab" data-toggle="pill" + href="#pills-home" role="tab" aria-controls="pills-home" + aria-selected="true">Inputs</a> + </li> + <li class="nav-item" role="presentation"> + <a class="nav-link" id="pills-profile-tab" data-toggle="pill" + href="#pills-profile" role="tab" aria-controls="pills-profile" + aria-selected="false">Outputs</a> + </li> + </ul> + <div class="tab-content" id="pills-tabContent"> + <div class="tab-pane fade show active" id="pills-home" role="tabpanel" + aria-labelledby="pills-home-tab"> + <div class="row"> + <div class="col"> + <!--list--> + <div class="attribute-wrap"> + <div class="form-group"> + <label + for="exampleFormControlTextarea1">artifact-prefix-names + <i class="icon-required-star" type="button" + aria-hidden="true"></i></label> + </div> + <div + class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline1" + name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" + for="customRadioInline1">Pre-defined + Template</label> + </div> + <div + class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline2" + name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" + for="customRadioInline2">Input Drivin + Template</label> + </div> + <br /> + <button type="button" class="btn btn-select-template"><i + class="icon-add-circle" type="button" + aria-hidden="true"></i> Select Template</button> + </div> + <!--string--> + <div class="attribute-wrap"> + <div class="form-group"> + <label for="exampleInputEmail1">resoluton-key <i + class="icon-required-star" type="button" + aria-hidden="true"></i></label> + <input type="text" class="form-control"> + </div> + </div> + <!--integer--> + <div class="attribute-wrap"> + <div class="form-group"> + <label for="exampleInputEmail1">request-id <i + class="icon-required-star" type="button" + aria-hidden="true"></i></label> + <input type="number" class="form-control" placeholder="" + value="356"> + </div> + </div> + <!--boolean--> + <div class="attribute-wrap"> + <div class="form-group"> + <label + for="exampleFormControlTextarea1">resolution-summary + <i class="icon-required-star optional-attribute" + type="button" aria-hidden="true"></i></label> + </div> + <div + class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline1" + name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" + for="customRadioInline1">True</label> + </div> + <div + class="custom-control custom-radio custom-control-inline"> + <input type="radio" id="customRadioInline2" + name="customRadioInline1" + class="custom-control-input"> + <label class="custom-control-label" + for="customRadioInline2">False</label> + </div> + </div> + <!-- Add Optional Attributes button --> + </div> + </div> + </div> + <div class="tab-pane fade" id="pills-profile" role="tabpanel" + aria-labelledby="pills-profile-tab">2</div> + </div> + </div> + </div> + </div> + </div> + <!--ARTIFACTS--> + <div class="accordion" id="accordionExample1"> + <div class="card"> + <div class="card-header row" id="headingOne"> + <button class="btn btn-link" type="button" data-toggle="collapse" + data-target="#collapseTwo" aria-expanded="true" aria-controls="collapseTwo"> + Artifacts + </button> + </div> + + <div id="collapseTwo" class="collapse show" aria-labelledby="headingOne" + data-parent="#accordionExample1"> + <div class="card-body"> + <div class="row"> + <div class="col-12"> + <a class="template-mapping-list"> + <p>baseconfig</p> + <span>Mapping</span> + <span>Template</span> + + <a data-toggle="modal" + data-target="#templateDeletionModal" + class="accordion-delete deleteTemplate" + title="Delete Template"><i class="icon-delete-sm"></i></a> + </a> + + </div> + <div class="col-12"> + <a class="template-mapping-list"> + <p>vpkg</p> + <span>Mapping</span> + <span>Template</span> + <a data-toggle="modal" + data-target="#templateDeletionModal" + class="accordion-delete deleteTemplate" + title="Delete Template"><i class="icon-delete-sm"></i></a> + </a> + </div> + </div> + </div> + </div> + </div> + </div> +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.spec.ts new file mode 100644 index 000000000..2b41c192a --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FunctionsAttributeComponent } from './functions-attribute.component'; + +describe('FunctionsAttributeComponent', () => { + let component: FunctionsAttributeComponent; + let fixture: ComponentFixture<FunctionsAttributeComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ FunctionsAttributeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(FunctionsAttributeComponent); + 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-attribute/functions-attribute.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.ts new file mode 100644 index 000000000..88bd76eb6 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/designer/functions-attribute/functions-attribute.component.ts @@ -0,0 +1,46 @@ +import {Component, OnDestroy, OnInit} from '@angular/core'; +import {DesignerStore} from '../designer.store'; +import {PackageCreationStore} from '../../package-creation/package-creation.store'; +import {Subject} from 'rxjs'; +import {distinctUntilChanged, takeUntil} from 'rxjs/operators'; +import {CBAPackage} from '../../package-creation/mapping-models/CBAPacakge.model'; + +@Component({ + selector: 'app-functions-attribute', + templateUrl: './functions-attribute.component.html', + styleUrls: ['./functions-attribute.component.css'] +}) +export class FunctionsAttributeComponent implements OnInit, OnDestroy { + + ngUnsubscribe = new Subject(); + private designerDashboardState: DecodeSuccessCallback; + private cbaPackage: CBAPackage; + + constructor(private designerStore: DesignerStore, + private packageCreationStore: PackageCreationStore) { + } + + ngOnInit() { + this.designerStore.state$ + .pipe( + distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe(designerDashboardState => { + this.designerDashboardState = designerDashboardState; + }); + + this.packageCreationStore.state$ + .pipe( + distinctUntilChanged((a: any, b: any) => JSON.stringify(a) === JSON.stringify(b)), + takeUntil(this.ngUnsubscribe)) + .subscribe(cbaPackage => { + this.cbaPackage = cbaPackage; + }); + + } + + ngOnDestroy() { + this.ngUnsubscribe.next(); + this.ngUnsubscribe.complete(); + } +} 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 index 8e1d88907..226f54399 100644 --- 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 @@ -18,10 +18,9 @@ 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'; +import {TopologyTemplate} from './model/designer.topologyTemplate.model'; +import {Injectable} from '@angular/core'; +import {GraphUtil} from './graph.util'; @Injectable({ providedIn: 'root' @@ -31,6 +30,10 @@ export class GraphGenerator { constructor(private graphUtil: GraphUtil) { } + clear(boardGraph: joint.dia.Graph) { + boardGraph.clear(); + } + /** * loops over workflows * create action element @@ -79,7 +82,7 @@ export class GraphGenerator { // create action element const actionElement = - this.graphUtil.createCustomActionWithName(workFlowName, boardGraph); + this.graphUtil.createCustomActionWithName(workFlowName, boardGraph); // create board function elements const workflow = topologyTempalte.workflows[workFlowName].steps; @@ -91,7 +94,7 @@ export class GraphGenerator { this.graphUtil.dropFunctionOverActionRelativeToParent( actionElement, - stepName , functionType, boardGraph); + stepName, functionType, boardGraph); // TODO handle dg-generic case (multi-step in the same action) if (functionType === 'dg-generic') { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts index f739ceb2e..adae66244 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/DesignerCreationMode.ts @@ -37,9 +37,11 @@ export class DesignerCreationMode extends PackageCreationModes { } private createDefinitionsFolder(cbaPackage: CBAPackage, packageCreationUtils: PackageCreationUtils) { - cbaPackage.definitions.imports.forEach((valueOfFile, key) => { - FilesContent.putData(key, valueOfFile); - }); + if (cbaPackage.definitions.imports && cbaPackage.definitions.imports.size > 0) { + cbaPackage.definitions.imports.forEach((valueOfFile, key) => { + FilesContent.putData(key, valueOfFile); + }); + } const filenameEntry = 'Definitions/' + cbaPackage.metaData.name + '.json'; const vlbDefinition: VlbDefinition = new VlbDefinition(); @@ -51,42 +53,52 @@ export class DesignerCreationMode extends PackageCreationModes { metadata['author-email'] = 'shaaban.eltanany.ext@orange.com'; metadata['user-groups'] = 'test'; metadata.template_description = cbaPackage.metaData.description; - cbaPackage.metaData.mapOfCustomKey.forEach((customKeyValue, key) => { - metadata[key] = customKeyValue; - }); + if (cbaPackage.metaData.mapOfCustomKey && cbaPackage.metaData.mapOfCustomKey.size > 0) { + cbaPackage.metaData.mapOfCustomKey.forEach((customKeyValue, key) => { + metadata[key] = customKeyValue; + }); + } // create Tags let fullTags = ''; let setCount = 0; - cbaPackage.metaData.templateTags.forEach(val => { - setCount++; - if (setCount === cbaPackage.metaData.templateTags.size) { - fullTags += val; - } else { - fullTags += val + ', '; - } - }); + if (cbaPackage.metaData.templateTags && cbaPackage.metaData.templateTags.size > 0) { + cbaPackage.metaData.templateTags.forEach(val => { + setCount++; + if (setCount === cbaPackage.metaData.templateTags.size) { + fullTags += val; + } else { + fullTags += val + ', '; + } + }); + } metadata.template_tags = fullTags; vlbDefinition.metadata = metadata; const files: Import[] = []; - cbaPackage.definitions.imports.forEach((valueOfFile, key) => { - if (!key.includes(cbaPackage.metaData.name)) { - files.push({file: key}); - } - }); - console.log(vlbDefinition); - vlbDefinition.imports = files; - console.log(cbaPackage.definitions.dslDefinition.content); - if (cbaPackage.definitions.dslDefinition.content) { + let insideVlbDefinition: VlbDefinition = null; + if (cbaPackage.definitions.imports && cbaPackage.definitions.imports.size > 0) { + cbaPackage.definitions.imports.forEach((valueOfFile, key) => { + if (!key.includes(cbaPackage.metaData.name)) { + files.push({file: key}); + } else { + insideVlbDefinition = JSON.parse(valueOfFile); + } + }); + } + + if (cbaPackage.definitions && cbaPackage.definitions.dslDefinition && + cbaPackage.definitions.dslDefinition.content) { vlbDefinition.dsl_definitions = JSON.parse(cbaPackage.definitions.dslDefinition.content); } - if (cbaPackage.templateTopology.content) { + + vlbDefinition.imports = files; + if (cbaPackage.templateTopology && cbaPackage.templateTopology.content) { vlbDefinition.topology_template = JSON.parse(cbaPackage.templateTopology.content); + } else if (insideVlbDefinition && insideVlbDefinition.topology_template) { + vlbDefinition.topology_template = insideVlbDefinition.topology_template; } - console.log(vlbDefinition); + const value = packageCreationUtils.transformToJson(vlbDefinition); FilesContent.putData(filenameEntry, value); - console.log('hello there'); console.log(FilesContent.getMapOfFilesNamesAndContent()); - } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts index 6b80358fd..8b82cc0eb 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/creationModes/PackageCreationModes.ts @@ -1,7 +1,7 @@ -import { CBAPackage } from '../mapping-models/CBAPacakge.model'; -import { ModeType } from '../mapping-models/ModeType'; -import { FilesContent, MetaDataTabModel } from '../mapping-models/metadata/MetaDataTab.model'; -import { PackageCreationUtils } from '../package-creation.utils'; +import {CBAPackage} from '../mapping-models/CBAPacakge.model'; +import {ModeType} from '../mapping-models/ModeType'; +import {FilesContent, MetaDataTabModel} from '../mapping-models/metadata/MetaDataTab.model'; +import {PackageCreationUtils} from '../package-creation.utils'; export abstract class PackageCreationModes { @@ -21,25 +21,28 @@ export abstract class PackageCreationModes { public static mapModeType(cbaPackage: CBAPackage) { console.log(cbaPackage.metaData.mode); - if (cbaPackage.metaData.mode.includes('Scripting')) { - cbaPackage.metaData.mode = ModeType.Scripting; - } else if (cbaPackage.metaData.mode.includes('Designer') || cbaPackage.metaData.mode.includes('DEFAULT') ) { - cbaPackage.metaData.mode = ModeType.Designer; - } else { - cbaPackage.metaData.mode = ModeType.Generic; - } + /* if (cbaPackage.metaData.mode.includes('Scripting')) { + cbaPackage.metaData.mode = ModeType.Scripting; + } else if (cbaPackage.metaData.mode.includes('Designer') || cbaPackage.metaData.mode.includes('DEFAULT') ) { + cbaPackage.metaData.mode = ModeType.Designer; + } else { + cbaPackage.metaData.mode = ModeType.Generic; + }*/ + cbaPackage.metaData.mode = ModeType.Designer; return cbaPackage; } getValueOfMetaData(metaDataTab: MetaDataTabModel): string { let tags = ''; let count = 0; - for (const tag of metaDataTab.templateTags) { - count++; - if (count === metaDataTab.templateTags.size) { - tags += tag; - } else { - tags += tag + ', '; + if (metaDataTab.templateTags && metaDataTab.templateTags.size > 0) { + for (const tag of metaDataTab.templateTags) { + count++; + if (count === metaDataTab.templateTags.size) { + tags += tag; + } else { + tags += tag + ', '; + } } } return 'TOSCA-Meta-File-Version: 1.0.0\n' + diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html index 8f2b554d9..641caf2ad 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/imports-tab/imports-tab.component.html @@ -74,7 +74,7 @@ <div [id]="'id-'+mapIndex" class="collapse" [attr.aria-labelledby]="'head-'+mapIndex" data-parent="#accordion"> <div class="card-body"> - <ace-editor [(text)]="file.value" (textChange)="textChanges($event,file.key)" [mode]="'json'" + <ace-editor [(text)]="file.value" readOnly="true" (textChange)="textChanges($event,file.key)" [mode]="'json'" [autoUpdateContent]="true" [durationBeforeCallback]="1000" [theme]="'eclipse'" #editor style="height:300px;"> </ace-editor> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts index f82310872..7a029fb3f 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/definitions/VlbDefinition.ts @@ -1,8 +1,11 @@ -import { Any, JsonObject, JsonProperty } from 'json2typescript'; +import {JsonObject, JsonProperty} from 'json2typescript'; @JsonObject('topology_template') export class TemplateTopology { - public content: string; + // tslint:disable-next-line:variable-name + public node_templates: object; + public workflows: object; + public content: string ; } @JsonObject @@ -22,26 +25,27 @@ export class VlbDefinition { export class DslContent { } + // Refactor varaibles name and use JsonConverteri @JsonObject('metadata') export class Metadata { @JsonProperty('template_author') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_author: string; 'author-email': string; 'user-groups': string; @JsonProperty('template_name') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_name: string; @JsonProperty('template_version') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_version: string; @JsonProperty('template_tag') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name template_tags: string; @JsonProperty('dictionary_group') - // tslint:disable-next-line:variable-name + // tslint:disable-next-line:variable-name dictionary_group: string; @JsonProperty('template_tags') templateTags: string; diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts index b4de578b9..e63b17fa2 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/mapping-models/mappingAdapter.model.ts @@ -10,11 +10,14 @@ export class MappingAdapter { private dependanciesSource: Map<string, string>) { } ToMapping(): Mapping { + // console.log(this.resourceDictionary.definition.property); const mapping = new Mapping(); mapping.name = this.resourceDictionary.name; mapping.dictionaryName = this.resourceDictionary.name; - mapping.property = this.resourceDictionary.definition.property; - mapping.inputParam = false; + mapping.property = Object.assign({}, this.resourceDictionary.definition.property); + mapping.inputParam = this.resourceDictionary['input-param'] || false; + // tslint:disable-next-line: no-string-literal + mapping.property['required'] = this.resourceDictionary['required'] || false; mapping.dictionarySource = this.dependanciesSource.get(mapping.name); if (this.dependancies.get(mapping.name)) { mapping.dependencies = this.dependancies.get(mapping.name); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html index f2e5eedf1..16bf7fccd 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.html @@ -33,7 +33,7 @@ <div class="single-line-model"> <label class="label-name">Name <span>*</span></label> <div class="label-input"> - <input tourAnchor="mt-packageName" type="input" (change)="checkRequiredElements()" + <input tourAnchor="mt-packageName" type="input" [readOnly]="!isNameEditable" (change)="checkRequiredElements()" [(ngModel)]="metaDataTab.name" placeholder="Package name"> </div> <!--<div class="model-note-container error-message"> @@ -49,6 +49,7 @@ [(ngModel)]="metaDataTab.version" (input)="validatePackageNameAndVersion()" pattern="(\d+)\.(\d+)\.(\d+)" placeholder="Example: 1.0.0"> </div> + <div class="model-note-container tag-notes">Must follow this format (1.0.0)</div> <div class="model-note-container error-message">{{errorMessage}}</div> </div> <div class="single-line-model"> @@ -123,4 +124,4 @@ </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts index af5b875f7..a46d2a3ec 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/metadata-tab/metadata-tab.component.ts @@ -23,6 +23,7 @@ export class MetadataTabComponent implements OnInit { metaDataTab: MetaDataTabModel = new MetaDataTabModel(); errorMessage: string; versionPattern = '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$'; + isNameEditable = false; constructor( private route: ActivatedRoute, @@ -36,7 +37,7 @@ export class MetadataTabComponent implements OnInit { this.metaDataTab.templateTags = this.tags; this.metaDataTab.mapOfCustomKey = this.customKeysMap; this.metaDataTab.mode = this.modeType; - + this.isNameEditable = this.route.snapshot.paramMap.get('id') == null; this.packageCreationStore.state$.subscribe(element => { if (element && element.metaData) { @@ -47,7 +48,6 @@ export class MetadataTabComponent implements OnInit { this.tags = element.metaData.templateTags; this.tags.delete(''); this.metaDataTab.templateTags = this.tags; - console.log(element); if (element.metaData.mode && element.metaData.mode.includes('DEFAULT')) { this.metaDataTab.mode = 'Designer Mode'; this.modeType = this.metaDataTab.mode; @@ -55,8 +55,12 @@ export class MetadataTabComponent implements OnInit { this.customKeysMap = element.metaData.mapOfCustomKey; this.metaDataTab.mapOfCustomKey = this.customKeysMap; + /* if (this.isNameEditable) { + this.validatePackageNameAndVersion(); + }*/ // this.tags = element.metaData.templateTags; + } }); } @@ -98,6 +102,8 @@ export class MetadataTabComponent implements OnInit { } validatePackageNameAndVersion() { + console.log('in validate'); + console.log('in this.metaDataTab.name' + this.metaDataTab.name); if (this.metaDataTab.name && this.metaDataTab.version) { this.packageCreationService.checkBluePrintNameAndVersion(this.metaDataTab.name, this.metaDataTab.version).then(element => { if (element) { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts new file mode 100644 index 000000000..232590c62 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation-extraction.service.ts @@ -0,0 +1,163 @@ +import {Injectable, ViewChild} from '@angular/core'; +import {MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; +import {TemplateTopology, VlbDefinition} from './mapping-models/definitions/VlbDefinition'; +import {DslDefinition} from './mapping-models/CBAPacakge.model'; +import {PackageCreationStore} from './package-creation.store'; +import * as JSZip from 'jszip'; +import {PackageCreationUtils} from './package-creation.utils'; +import {MetadataTabComponent} from './metadata-tab/metadata-tab.component'; +import {DesignerStore} from '../designer/designer.store'; +import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; + +@Injectable({ + providedIn: 'root' +}) +export class PackageCreationExtractionService { + + private zipFile: JSZip; + private entryDefinitionKeys: string[] = ['template_tags', 'user-groups', + 'author-email', 'template_version', 'template_name', 'template_author', 'template_description']; + + private toscaMetaDataKeys: string[] = ['TOSCA-Meta-File-Version', 'CSAR-Version', + 'Created-By', 'Entry-Definitions', 'Template-Name', 'Template-Version', 'Template-Type', 'Template-Tags']; + @ViewChild(MetadataTabComponent, {static: false}) + private metadataTabComponent: MetadataTabComponent; + + constructor( + private packageCreationStore: PackageCreationStore, + private packageCreationUtils: PackageCreationUtils, + private designerStore: DesignerStore + ) { + + } + + public extractBlobToStore(blob) { + this.zipFile = new JSZip(); + let packageName = null; + this.zipFile.loadAsync(blob).then((zip) => { + Object.keys(zip.files).filter(fileName => fileName.includes('TOSCA-Metadata/')) + .forEach((filename) => { + zip.files[filename].async('string').then((fileData) => { + if (fileData) { + if (filename.includes('TOSCA-Metadata/')) { + + const metaDataTabInfo: MetaDataTabModel = this.getMetaDataTabInfo(fileData); + packageName = metaDataTabInfo.name; + this.setMetaData(metaDataTabInfo); + console.log('found file ' + packageName); + } + } + }); + }); + }); + + this.zipFile.loadAsync(blob).then((zip) => { + Object.keys(zip.files).forEach((filename) => { + zip.files[filename].async('string').then((fileData) => { + console.log(filename); + if (fileData) { + if (filename.includes('Scripts/')) { + this.setScripts(filename, fileData); + } else if (filename.includes('Templates/')) { + if (filename.includes('-mapping.')) { + this.setMapping(filename, fileData); + } else if (filename.includes('-template.')) { + this.setTemplates(filename, fileData); + } + + } else if (filename.includes('Definitions/')) { + this.setImports(filename, fileData, packageName); + } + } + }); + }); + }); + } + + public setScripts(filename: string, fileData: any) { + this.packageCreationStore.addScripts(filename, fileData); + } + + public setImports(filename: string, fileData: any, packageName: string) { + console.log(filename); + if (filename.includes('Definitions/' + packageName.trim() + '.json')) { + let definition = new VlbDefinition(); + definition = fileData as VlbDefinition; + definition = JSON.parse(fileData); + const dslDefinition = new DslDefinition(); + dslDefinition.content = this.packageCreationUtils.transformToJson(definition.dsl_definitions); + const mapOfCustomKeys = new Map<string, string>(); + for (const metadataKey in definition.metadata) { + if (!this.entryDefinitionKeys.includes(metadataKey + '')) { + mapOfCustomKeys.set(metadataKey + '', definition.metadata[metadataKey + '']); + } + } + + this.packageCreationStore.changeDslDefinition(dslDefinition); + this.packageCreationStore.setCustomKeys(mapOfCustomKeys); + this.setPackageDescription(definition.metadata.template_description); + console.log(definition); + console.log(definition.topology_template); + const content = {}; + const workflow = 'workflows'; + content[workflow] = definition.topology_template ? definition.topology_template.workflows : {}; + const nodeTemplates = 'node_templates'; + content[nodeTemplates] = definition.topology_template ? definition.topology_template.node_templates : {}; + this.designerStore.saveSourceContent(JSON.stringify(content)); + if (definition.topology_template) { + this.packageCreationStore.addTopologyTemplate(definition.topology_template); + } else { + this.packageCreationStore.addTopologyTemplate(new TemplateTopology()); + } + + + } + this.packageCreationStore.addDefinition(filename, fileData); + + } + + public setTemplates(filename: string, fileData: any) { + this.packageCreationStore.addTemplate(filename, fileData); + } + + public setMapping(fileName: string, fileData: string) { + this.packageCreationStore.addMapping(fileName, fileData); + } + + private setMetaData(metaDataObject: MetaDataTabModel) { + this.packageCreationStore.changeMetaData(metaDataObject); + } + + public setMetaDataWithObject(metaDataObject: MetaDataTabModel, bluePrintDetailModel: BluePrintDetailModel) { + metaDataObject.description = bluePrintDetailModel.artifactDescription; + this.packageCreationStore.changeMetaData(metaDataObject); + + } + + public getMetaDataTabInfo(fileData: string) { + const metaDataTabModel = new MetaDataTabModel(); + + const arrayOfLines = fileData.split('\n'); + const map = new Map<string, string>(); + for (const currentLine of arrayOfLines) { + const currentKey = currentLine.split(':')[0]; + const currentValue = currentLine.split(':')[1]; + map.set(currentKey, currentValue); + } + metaDataTabModel.entryFileName = map.get(this.toscaMetaDataKeys[3]); + metaDataTabModel.name = map.get(this.toscaMetaDataKeys[4]); + metaDataTabModel.version = map.get(this.toscaMetaDataKeys[5]).trim(); + metaDataTabModel.mode = map.get(this.toscaMetaDataKeys[6]); + if (map.get(this.toscaMetaDataKeys[7])) { + metaDataTabModel.templateTags = new Set<string>(map.get(this.toscaMetaDataKeys[7]).split(',')); + } + return metaDataTabModel; + } + + private setPackageDescription(templateDescription: string) { + const metaData = this.packageCreationStore.getMetaData(); + metaData.description = templateDescription; + this.setMetaData(metaData); + + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html index a09951cd2..e42304ad6 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.html @@ -19,6 +19,16 @@ <input class="dropdown-toggle" type="text"> <div class="dropdown-text"><i class="icon-info" aria-hidden="true"></i></div> <ul class="dropdown-content"> + <li> + <i class="icon-get_started" aria-hidden="true"></i> + <p> + <input id="clicker3" type="checkbox" /> + <label for="clicker"> + Getting Started + <span>Quick steps to help you get started</span> + </label> + </p> + </li> <!-- <li> <i class="icon-get_started" aria-hidden="true"></i> <p> @@ -83,8 +93,9 @@ <div class="nav nav-tabs " id="nav-tab" role="tablist"> <a (click)="openTourGuide('metadataTab')" tourAnchor="metadataTab" class="nav-item nav-link active" id="nav-metadata-tab" data-toggle="tab" href="#nav-metadata" role="tab" aria-controls="nav-metadata" - aria-selected="false" autofocus #nameit (focusout)="saveMetaData()" - [classList]="metadataClasses">METADATA</a> + aria-selected="false" autofocus #nameit (focusout)="saveMetaData()" [classList]="metadataClasses">METADATA</a> + + <a (click)="openTourGuide('tm-templateTab')" tourAnchor="tm-templateTab" class="nav-item nav-link" id="nav-template-tab" data-toggle="tab" href="#nav-template" role="tab" aria-controls="nav-template" aria-selected="false">TEMPLATE & @@ -134,4 +145,4 @@ </div> </div> </div> -</div>
\ No newline at end of file +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts index 4145e0f8e..c7285774e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.component.ts @@ -19,19 +19,22 @@ limitations under the License. ============LICENSE_END============================================ */ -import { Component, ElementRef, OnInit, ViewChild } from '@angular/core'; -import { FilesContent, FolderNodeElement, MetaDataTabModel } from './mapping-models/metadata/MetaDataTab.model'; +import {Component, ElementRef, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {FilesContent, FolderNodeElement, MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; import * as JSZip from 'jszip'; -import { PackageCreationStore } from './package-creation.store'; -import { Definition } from './mapping-models/CBAPacakge.model'; -import { PackageCreationModes } from './creationModes/PackageCreationModes'; -import { PackageCreationBuilder } from './creationModes/PackageCreationBuilder'; -import { PackageCreationUtils } from './package-creation.utils'; -import { MetadataTabComponent } from './metadata-tab/metadata-tab.component'; -import { Router } from '@angular/router'; -import { ToastrService } from 'ngx-toastr'; -import { TourService } from 'ngx-tour-md-menu'; +import {PackageCreationStore} from './package-creation.store'; +import {CBAPackage, Definition} from './mapping-models/CBAPacakge.model'; +import {PackageCreationModes} from './creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from './creationModes/PackageCreationBuilder'; +import {PackageCreationUtils} from './package-creation.utils'; +import {MetadataTabComponent} from './metadata-tab/metadata-tab.component'; +import {Router} from '@angular/router'; +import {ToastrService} from 'ngx-toastr'; +import {TourService} from 'ngx-tour-md-menu'; +import {PackageCreationService} from './package-creation.service'; +import {ComponentCanDeactivate} from '../../../../common/core/canDactivate/ComponentCanDeactivate'; +import {DesignerStore} from '../designer/designer.store'; @Component({ @@ -39,23 +42,28 @@ import { TourService } from 'ngx-tour-md-menu'; templateUrl: './package-creation.component.html', styleUrls: ['./package-creation.component.css'] }) -export class PackageCreationComponent implements OnInit { +export class PackageCreationComponent extends ComponentCanDeactivate implements OnInit, OnDestroy { + // adding initial referencing to designer mode constructor( private packageCreationStore: PackageCreationStore, + private packageCreationService: PackageCreationService, private packageCreationUtils: PackageCreationUtils, private router: Router, private tourService: TourService, - private toastService: ToastrService) { + private toastService: ToastrService, + private designerStore: DesignerStore) { + + super(); } counter = 0; modes: object[] = [ - { name: 'Designer Mode', style: 'mode-icon icon-designer-mode' }, - { name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode' }]; + {name: 'Designer Mode', style: 'mode-icon icon-designer-mode'}, + {name: 'Scripting Mode', style: 'mode-icon icon-scripting-mode'}]; metaDataTab: MetaDataTabModel = new MetaDataTabModel(); folder: FolderNodeElement = new FolderNodeElement(); zipFile: JSZip = new JSZip(); @@ -63,18 +71,22 @@ export class PackageCreationComponent implements OnInit { definition: Definition = new Definition(); isSaveEnabled = false; - @ViewChild(MetadataTabComponent, { static: false }) + @ViewChild(MetadataTabComponent, {static: false}) metadataTabComponent: MetadataTabComponent; - @ViewChild('nameit', { static: true }) + @ViewChild('nameit', {static: true}) elementRef: ElementRef; versionPattern = '^(\\d+\\.)?(\\d+\\.)?(\\*|\\d+)$'; metadataClasses = 'nav-item nav-link active complete'; + private cbaPackage: CBAPackage; ngOnInit() { this.elementRef.nativeElement.focus(); const regexp = RegExp(this.versionPattern); this.packageCreationStore.state$.subscribe(cbaPackage => { + console.log(cbaPackage); + console.log('abbaaaas' + cbaPackage.metaData.name); + this.cbaPackage = cbaPackage; if (cbaPackage && cbaPackage.metaData && cbaPackage.metaData.description && cbaPackage.metaData.name && cbaPackage.metaData.version && regexp.test(cbaPackage.metaData.version)) { @@ -96,18 +108,17 @@ export class PackageCreationComponent implements OnInit { } saveBluePrint() { - this.packageCreationStore.state$.subscribe( - cbaPackage => { - console.log(cbaPackage); - FilesContent.clear(); - let packageCreationModes: PackageCreationModes; - cbaPackage = PackageCreationModes.mapModeType(cbaPackage); - cbaPackage.metaData = PackageCreationModes.setEntryPoint(cbaPackage.metaData); - packageCreationModes = PackageCreationBuilder.getCreationMode(cbaPackage); - packageCreationModes.execute(cbaPackage, this.packageCreationUtils); - this.filesData.push(this.folder.TREE_DATA); - this.saveBluePrintToDataBase(); - }); + console.log(this.cbaPackage); + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + + // this.cbaPackage.templateTopology.content = this.designerStore.state.sourceContent; + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); + this.saveBluePrintToDataBase(); } @@ -115,13 +126,14 @@ export class PackageCreationComponent implements OnInit { saveBluePrintToDataBase() { this.create(); - this.zipFile.generateAsync({ type: 'blob' }) + this.zipFile.generateAsync({type: 'blob'}) .then(blob => { - this.packageCreationStore.saveBluePrint(blob).subscribe( + this.packageCreationService.savePackage(blob).subscribe( bluePrintDetailModels => { if (bluePrintDetailModels) { const id = bluePrintDetailModels.toString().split('id')[1].split(':')[1].split('"')[1]; this.toastService.info('package updated successfully '); + this.isSaveEnabled = false; this.router.navigate(['/packages/package/' + id]); } }, error => { @@ -150,4 +162,12 @@ export class PackageCreationComponent implements OnInit { this.metadataTabComponent.saveMetaDataToStore(); } + + canDeactivate(): boolean { + return this.isSaveEnabled; + } + + ngOnDestroy(): void { + + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts index e7ccbb39a..ed3db4286 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.service.ts @@ -21,28 +21,46 @@ limitations under the License. import {Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; +import {Observable, Subject} from 'rxjs'; import {ApiService} from '../../../../common/core/services/api.service'; import {BlueprintURLs, ResourceDictionaryURLs} from '../../../../common/constants/app-constants'; import {PackagesApiService} from '../packages-api.service'; import {PackagesStore} from '../packages.store'; import {ResourceDictionary} from './mapping-models/ResourceDictionary.model'; +import {FilesContent, FolderNodeElement} from './mapping-models/metadata/MetaDataTab.model'; +import {PackageCreationModes} from './creationModes/PackageCreationModes'; +import {PackageCreationBuilder} from './creationModes/PackageCreationBuilder'; +import {PackageCreationStore} from './package-creation.store'; +import {CBAPackage} from './mapping-models/CBAPacakge.model'; +import {PackageCreationUtils} from './package-creation.utils'; +import * as JSZip from 'jszip'; +import {DesignerStore} from '../designer/designer.store'; @Injectable({ providedIn: 'root' }) export class PackageCreationService { - - - constructor(private api: ApiService, private packagesListService: PackagesApiService, private packagesStore: PackagesStore) { + private cbaPackage: CBAPackage; + folder: FolderNodeElement = new FolderNodeElement(); + filesData: any = []; + zipFile: JSZip = new JSZip(); + + constructor(private api: ApiService, private packagesListService: PackagesApiService, + private packagesStore: PackagesStore, private designerStore: DesignerStore, + private packageCreationStore: PackageCreationStore, private packageCreationUtils: PackageCreationUtils + ) { + this.packageCreationStore.state$.subscribe( + cbaPackage => { + this.cbaPackage = cbaPackage; + }); } - private saveBlueprint(body: any | null, options?: any): Observable<any> { + private saveBlueprint(body: any | null, options?: any): Observable<string> { return this.api.post(BlueprintURLs.save, body, {responseType: 'text'}); } private enrichBlueprint(body: any | null, options?: any): Observable<any> { - return this.api.post(BlueprintURLs.enrich, body, {responseType: 'text'}); + return this.api.post(BlueprintURLs.enrich, body, {responseType: 'blob'}); } private deployBluePrint(body: any | null, options?: any): Observable<any> { @@ -58,7 +76,7 @@ export class PackageCreationService { this.packagesStore.getAll(); } - savePackage(blob) { + public savePackage(blob): Observable<string> { const formData = this.getFormData(blob); return this.saveBlueprint(formData); } @@ -83,5 +101,69 @@ export class PackageCreationService { return this.api.post(ResourceDictionaryURLs.searchResourceDictionaryByNames, variables); } + downloadPackage(id) { + return this.api.getCustomized(BlueprintURLs.download + id, {responseType: 'blob'}); + } + + public saveBluePrintToDataBase(): Observable<string> { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.savePackage(blob).subscribe(bluePrintModel => { + subject.next(bluePrintModel); + }); + }); + return subject.asObservable(); + } + + public deployCurrentPackage() { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + this.deploy(blob).subscribe(bluePrintModel => { + subject.next(bluePrintModel); + }); + }); + return subject.asObservable(); + } + + public enrichCurrentPackage() { + this.formTreeData(); + this.create(); + const subject = new Subject<any>(); + return this.zipFile.generateAsync({type: 'blob'}) + .then(blob => { + return this.enrichPackage(blob).pipe(); + }); + // return subject.asObservable(); + + } + + private create() { + this.zipFile = new JSZip(); + FilesContent.getMapOfFilesNamesAndContent().forEach((value, key) => { + this.zipFile.folder(key.split('/')[0]); + this.zipFile.file(key, value); + }); + + } + + private formTreeData() { + + FilesContent.clear(); + let packageCreationModes: PackageCreationModes; + this.cbaPackage = PackageCreationModes.mapModeType(this.cbaPackage); + this.cbaPackage.metaData = PackageCreationModes.setEntryPoint(this.cbaPackage.metaData); + packageCreationModes = PackageCreationBuilder.getCreationMode(this.cbaPackage); + this.designerStore.state$.subscribe(state => { + this.cbaPackage.templateTopology.content = this.packageCreationUtils.transformToJson(state.template); + }); + packageCreationModes.execute(this.cbaPackage, this.packageCreationUtils); + this.filesData.push(this.folder.TREE_DATA); + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts index b60831238..77867e55e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/package-creation.store.ts @@ -24,11 +24,7 @@ import {Injectable} from '@angular/core'; import {Store} from '../../../../common/core/stores/Store'; import {CBAPackage, DslDefinition} from './mapping-models/CBAPacakge.model'; -import {PackageCreationService} from './package-creation.service'; import {MetaDataTabModel} from './mapping-models/metadata/MetaDataTab.model'; -import {Observable} from 'rxjs'; -import {ResourceDictionary} from './mapping-models/ResourceDictionary.model'; -import {BluePrintDetailModel} from '../model/BluePrint.detail.model'; import {TemplateTopology} from './mapping-models/definitions/VlbDefinition'; @@ -38,7 +34,7 @@ import {TemplateTopology} from './mapping-models/definitions/VlbDefinition'; export class PackageCreationStore extends Store<CBAPackage> { - constructor(private packageCreationService: PackageCreationService) { + constructor() { super(new CBAPackage()); } @@ -98,17 +94,6 @@ export class PackageCreationStore extends Store<CBAPackage> { this.state.definitions.imports.delete(filename); } - saveBluePrint(blob): Observable<BluePrintDetailModel> { - return this.packageCreationService.savePackage(blob); - } - - enrichBluePrint(blob): Observable<any> { - return this.packageCreationService.enrichPackage(blob); - } - - deployBluePrint(blob): Observable<BluePrintDetailModel> { - return this.packageCreationService.deploy(blob); - } addTemplate(filePath: string, fileContent: string) { this.setState({ @@ -124,12 +109,10 @@ export class PackageCreationStore extends Store<CBAPackage> { }); } - getTemplateAndMapping(variables: string[]): Observable<ResourceDictionary[]> { - return this.packageCreationService.getTemplateAndMapping(variables); - } - clear() { + console.log('clearing the store'); this.setState(new CBAPackage()); + console.log('it should be empty'); } setEntryDefinition(data: string) { @@ -142,4 +125,8 @@ export class PackageCreationStore extends Store<CBAPackage> { templateTopology }); } + + getMetaData() { + return this.state.metaData; + } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts index c3704365c..2653d739c 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/scripts-tab/scripts-tab.component.ts @@ -24,6 +24,7 @@ export class ScriptsTabComponent implements OnInit { ngOnInit() { + this.packageCreationStore.state$.subscribe(cbaPackage => { if (cbaPackage.scripts && cbaPackage.scripts.files && cbaPackage.scripts.files.size > 0) { this.scriptsFiles = cbaPackage.scripts.files; diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts index 57c2bcbfa..47128130c 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/shared-service.ts @@ -10,11 +10,17 @@ export class SharedService { // based on edit Mode, edit=false mode = new BehaviorSubject(false); list = new BehaviorSubject(''); + modeState: Observable<boolean>; + listState: Observable<string>; constructor() { + this.mode = new BehaviorSubject(false); + this.list = new BehaviorSubject(''); + this.modeState = this.mode.asObservable(); + this.listState = this.list.asObservable(); } isEdit(): Observable<boolean> { - return this.mode.asObservable(); + return this.modeState; } enableEdit() { this.mode.next(true); @@ -28,7 +34,7 @@ export class SharedService { this.list.next(filename); } listAction(): Observable<string> { - return this.list.asObservable(); + return this.listState; } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts deleted file mode 100644 index 17a4bfae6..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/TemplateType.ts +++ /dev/null @@ -1,5 +0,0 @@ -export enum TemplateType { - Velocity = 'vtl', - Koltin = 'kt', - Jinja = 'Unknown' -} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html index 4b0ef8b49..de97a4679 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.html @@ -5,12 +5,14 @@ class="fa fa-chevron-left mr-2"></i>Template List</button> </div> <div class="col text-right"> + <button (click)="cancel()" [hidden]="!templatesExist || edit" class="btn btn-outline-danger" + title="Delete Template">Cancel</button> <button data-toggle="modal" [hidden]="!edit" data-target="#templateDeletionModal2" class="btn btn-outline-danger" title="Delete Template">Delete</button> - <button (click)="cancel()" [hidden]="fileName?.length <=0 || edit" + <button (click)="clear()" [hidden]="fileName?.length <=0 || edit" class="btn btn-outline-secondary">Clear</button> - <button tourAnchor="tm-templateFinish" (click)="saveToStore()" [disabled]="fileName?.length <=0" title="Submit template and close" - class="btn btn-primary">Finish</button> + <button tourAnchor="tm-templateFinish" (click)="saveToStore()" [disabled]="fileName?.length <=0" + title="Submit template and close" class="btn btn-primary">Finish</button> </div> </div> <div class="card creat-card"> @@ -31,8 +33,8 @@ <div class="card"> <div class="card-header" id="headingOne"> <h5 class="mb-0 d-flex justify-content-between"> - <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" aria-expanded="true" - aria-controls="collapseOne"> + <button class="btn btn-link" data-toggle="collapse" data-target="#collapseOne" id="templateTab" + aria-expanded="true" aria-controls="collapseOne"> 1. Template <span class="accordian-title">{{currentTemplate?.fileName?.split('/')[1]}}</span> </button> @@ -44,24 +46,25 @@ <div tourAnchor="tm-templateType" class="single-line"> <label class="label-name">Template Type</label> <div class="label-input"> - <label name="trst" (click)="allowedExt=['.vtl']"> + <label name="trst" (click)="allowedExt=['.vtl'];templateExt='vtl'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Velcoity> + name="exampleRadios" id="exampleRadios1" value=vtl> <span> - Velcoity + Velocity </span> </label> - <label name="trst" (click)="allowedExt=['.j2','.jinja2']"> + <label name="trst" (click)="allowedExt=['.j2','.jinja2'];templateExt='j2'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Jinja> + name="exampleRadios" id="exampleRadios1" value=j2> <span> Jinja </span> </label> - <label tourAnchor="tm-templateContent" name="trst" (click)="allowedExt=['.kt']"> + <label tourAnchor="tm-templateContent" name="trst" + (click)="allowedExt=['.kt'];templateExt='kt'"> <input class="form-check-input" [(ngModel)]="templateExt" type="radio" - name="exampleRadios" id="exampleRadios1" value=Kotlin> + name="exampleRadios" id="exampleRadios1" value=kt> <span> Kotlin @@ -70,7 +73,7 @@ </div> </div> <div class="create-template-import">Use the editor to add parameters or you can also - <a href="#" data-toggle="modal" (click)="allowedExt=[getFileExtension()]" + <a href="#" data-toggle="modal" (click)="allowedExt=['.'+templateExt]" data-target="#templateModal"><b>Import File</b></a>. <br /> <span class="templateNote"><i class="icon-info" aria-hidden="true"></i> When you import new file, the new attributes will replace @@ -86,8 +89,9 @@ <div class="card"> <div class="card-header" id="headingTwo"> <h5 class="mb-0"> - <button tourAnchor="tm-mappingContent" class="btn btn-link collapsed" id="mappingTab" data-toggle="collapse" - data-target="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo"> + <button tourAnchor="tm-mappingContent" class="btn btn-link collapsed" id="mappingTab" + data-toggle="collapse" data-target="#collapseTwo" aria-expanded="false" + aria-controls="collapseTwo"> 2. Manage Mapping <span class="accordian-title">{{currentMapping?.fileName?.split('/')[1]}}</span> </button> @@ -97,8 +101,8 @@ <div class="card-body"> <p class="text-center"><b>Select a source to load config parameters</b></p> <div class="text-center"> - <button [disabled]="!(variables?.length>0 && templateFileContent?.trim()?.length > 0)" - (click)="getMappingTableFromTemplate($event)" class="mapping-source-load" [ngClass]="variables?.length>0 && templateFileContent?.trim()?.length > 0 + <button [disabled]="!(templateFileContent?.trim()?.length > 0)" + (click)="getMappingTableFromTemplate($event)" class="mapping-source-load" [ngClass]="templateFileContent?.trim()?.length > 0 ?'hover-enable':'hover-disable'"> <i class="icon-use-attributes"></i> <br /> @@ -122,28 +126,68 @@ </div> + </div> + <div id="mapping-table" [hidden]="resourceDictionaryRes?.length == 0" class="mapping-table mx-4 my-2"> + <div class="btn-group mapping-editBar" role="group"> + <div class="custom-control custom-checkbox" tooltip="Select All" placement="bottom"> + <input type="checkbox" (click)="selectAllProps()" class="custom-control-input" + id="customCheck1" + [checked]="resourceDictionaryRes.length>0&&resourceDictionaryRes.length === this.selectedProps.size"> + <label class="custom-control-label" for="customCheck1"></label> + </div> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="reMap()" + tooltip="Re-mapping" placement="bottom"><i class="icon-autoMap"></i></button> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="removeProps()" + tooltip="Remove" placement="bottom"><i class="icon-delete-sm"></i></button> + <div style="line-height: 35px;font-size: 10px;"> + <span>{{selectedProps.size}} selected </span> + <span>({{resourceDictionaryRes.length}} attributes in total)</span> + </div> + </div> <table datatable [dtOptions]="initDtOptions" [dtTrigger]="dtTrigger" class="row-border hover"> <thead> <tr> + <th></th> <th>Required</th> + <th>Template Input</th> <th>Parameter Name</th> <th>Dictionary Name</th> <th>Dictionary Source</th> <th>Dependancies</th> <th>Default</th> + <th>Velocity</th> <th>Data Type</th> <th>Entry Schema</th> </tr> </thead> <tbody> - <tr *ngFor="let dict of resourceDictionaryRes"> + <tr *ngFor="let dict of resourceDictionaryRes;let i=index;trackBy: identify"> + <td> + <div class="custom-control custom-checkbox" tooltip="Select" placement="bottom"> + <input type="checkbox" class="custom-control-input" + id="customCheck-{{dict.name}}" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"> + <label class="custom-control-label" for="customCheck-{{dict.name}}"></label> + </div> + <!-- <input type="checkbox" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"></td> --> + </td> <td> - <img *ngIf="dict.definition?.property?.required" - src="/assets/img/icon-required-yes.svg"> - <img *ngIf="!dict.definition?.property?.required" - src="/assets/img/icon-required-no.svg"> + <div class="custom-control custom-checkbox reuiredInput"> + <input type="checkbox" class="custom-control-input" #requiredInput + (click)="setProp(requiredInput,'required',i)" + id="requiredCheck-{{dict.name}}"> + <label class="custom-control-label" for="requiredCheck-{{dict.name}}"></label> + </div> + </td> + <td> + <div class="custom-control custom-checkbox reuiredInput"> + <input type="checkbox" class="custom-control-input" #tempInput + (click)="setProp(tempInput,'input-param',i)" id="inputCheck-{{dict.name}}"> + <label class="custom-control-label" for="inputCheck-{{dict.name}}"></label> + </div> </td> <td>{{ dict.name }}</td> <td>{{ dict.name }}</td> @@ -159,12 +203,13 @@ <!-- <select class="custom-select"> <option *ngFor="let val of getKeys(dependancies)"> {{ getValue(dict.name)}}</option> - </select> --> <input type="text" class="form-control" [ngModel]="getValue(dict.name)"> <!-- {{ dict.definition.sources }} --> </td> <td>{{ dict.definition?.property?.default }}</td> + <td><input type="text" class="form-control" #velocity + (input)="setVelocity(i,velocity.value)"></td> <td>{{ dict.definition?.property?.type }}</td> <td>{{ dict.definition?.property['entry_schema'] }}</td> </tr> @@ -173,26 +218,51 @@ </div> <div id="mapping-table-res" [hidden]="mappingRes?.length == 0" class="mapping-table mx-4 my-2"> + <!-- <div class="btn-group mapping-editBar" role="group"> + <div class="custom-control custom-checkbox" tooltip="Select All" placement="bottom"> + <input type="checkbox" (click)="selectAllProps()" class="custom-control-input" + id="customCheck2" + [checked]="resourceDictionaryRes.length>0&&resourceDictionaryRes.length === this.selectedProps.size"> + <label class="custom-control-label" for="customCheck2"></label> + </div> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="reMap()" + tooltip="Re-mapping" placement="bottom"><i class="icon-autoMap"></i></button> + <button [disabled]="selectedProps.size <=0" type="button" class="btn" (click)="removeProps()" + tooltip="Remove" placement="bottom"><i class="icon-delete-sm"></i></button> + </div> --> <table datatable [dtOptions]="dtOptions" [dtTrigger]="resTableDtTrigger" class="row-border hover"> <thead> <tr> + <!-- <th></th> --> <th>Required</th> + <th>Template Input</th> <th>Parameter Name</th> <th>Dictionary Name</th> <th>Dictionary Source</th> <th>Dependancies</th> <th>Default</th> + <th>Velocity</th> <th>Data Type</th> <th>Entry Schema</th> </tr> </thead> <tbody> <tr *ngFor="let dict of mappingRes"> + <!-- <td> + <div class="custom-control custom-checkbox" tooltip="Select" placement="bottom"> + <input type="checkbox" class="custom-control-input" + id="customCheck2-{{dict.name}}" [checked]="selectedProps.has(dict.name)" + (click)="selectProp(dict.name)"> + <label class="custom-control-label" for="customCheck2-{{dict.name}}"></label> + </div> + </td> --> <td> - <img *ngIf="dict.definition?.property?.required" - src="/assets/img/icon-required-yes.svg"> - <img *ngIf="!dict.definition?.property?.required" - src="/assets/img/icon-required-no.svg"> + <img *ngIf="dict?.property?.required" src="/assets/img/icon-required-yes.svg"> + <img *ngIf="!dict?.property?.required" src="/assets/img/icon-required-no.svg"> + </td> + <td> + <img *ngIf="dict['input-param']" src="/assets/img/icon-required-yes.svg"> + <img *ngIf="!dict['input-param']" src="/assets/img/icon-required-no.svg"> </td> <td>{{ dict['name'] }}</td> <td>{{ dict['name'] }}</td> @@ -206,6 +276,10 @@ <!-- {{ dict.definition.sources }} --> </td> <td>{{ dict['property']['default'] }}</td> + <td *ngIf="dict?.property?.metadata"> + {{dict?.property?.metadata['transform-template']}} + </td> + <td *ngIf="!dict?.property?.metadata"></td> <td>{{ dict['property']['type'] }}</td> <td>{{ dict['property']['entry_schema'] }}</td> </tr> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts index 3e7cfea7b..56ed0422a 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-creation/templ-mapp-creation.component.ts @@ -10,8 +10,11 @@ import { PackageCreationUtils } from '../../package-creation.utils'; import { JsonConvert, Any } from 'json2typescript'; import { ToastrService } from 'ngx-toastr'; import { SharedService } from '../shared-service'; -import { XmlParser } from '../utils/XmlParser'; +import { XmlParser } from '../utils/ParserFactory/XmlParser'; import { TourService } from 'ngx-tour-md-menu'; +import { PackageCreationService } from '../../package-creation.service'; +import { ParserFactory } from '../utils/ParserFactory/ParserFactory'; +import { TemplateType, FileExtension } from '../utils/TemplateType'; declare var $: any; @Component({ @@ -42,14 +45,17 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { MappingAdapter: MappingAdapter; mapping = new Map(); templateFileContent: string; - templateExt = 'Velcoity'; + templateExt = 'vtl'; dependancies = new Map<string, Array<string>>(); dependanciesSource = new Map<string, string>(); mappingRes = []; currentTemplate: any; currentMapping: any; edit = false; + templatesExist = false; fileToDelete: any = {}; + parserFactory: ParserFactory; + selectedProps: Set<string>; constructor( private packageCreationStore: PackageCreationStore, @@ -57,11 +63,14 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { private packageCreationUtils: PackageCreationUtils, private toastr: ToastrService, private sharedService: SharedService, + private packageCreationService: PackageCreationService, private tourService: TourService, ) { } ngOnInit() { + this.selectedProps = new Set<string>(); + this.parserFactory = new ParserFactory(); this.templateStore.state$.subscribe(templateInfo => { // init Template&mapping vars console.log('Oninit'); @@ -70,7 +79,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.fileToDelete = templateInfo.fileName; this.fileName = templateInfo.fileName.split('/')[1]; if (this.fileName) { - this.fileName = this.fileName.split('-')[0]; + this.fileName = this.fileName.substr(0, this.fileName.lastIndexOf('-')); } if (templateInfo.type === 'mapping' || templateInfo.type.includes('mapping')) { this.mappingRes = templateInfo.mapping; @@ -80,20 +89,27 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } else { this.mappingRes = []; this.currentMapping = Any; + this.resourceDictionaryRes = []; } this.templateFileContent = templateInfo.fileContent; + this.templateExt = this.templateInfo.ext || this.templateExt; this.currentTemplate = Object.assign({}, templateInfo); if (templateInfo.type === 'template' || templateInfo.type.includes('template')) { - this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.vtl'; + console.log('template extension ' + this.templateExt); + this.currentTemplate.fileName = 'Templates/' + this.fileName + '-template.' + this.templateExt; + console.log(this.currentTemplate.fileName); } else { this.currentTemplate = Any; } }); + this.sharedService.isEdit().subscribe(res => { - console.log('------------------------'); + console.log('------------------------....'); + this.templatesExist = this.packageCreationStore.state.templates.files.size > 0 + || this.packageCreationStore.state.mapping.files.size > 0; console.log(res); this.edit = res; @@ -113,6 +129,14 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { pageLength: 25, destroy: true, retrieve: true, + columnDefs: [ + { + targets: [0, 1, 2], // column or columns numbers + orderable: false, // set orderable for selected columns + searchable: false, + }, + + ], }; this.dtOptions = { pagingType: 'full_numbers', @@ -122,13 +146,79 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { }; } + setProp(e, propName, index) { + this.resourceDictionaryRes[index][propName] = e.checked; + console.log(this.resourceDictionaryRes[index]); + } + selectProp(value) { + console.log(value); + if (this.selectedProps.has(value)) { + this.selectedProps.delete(value); + } else { + this.selectedProps.add(value); + } + } + + removeProps() { + console.log(this.selectedProps); + this.selectedProps.forEach(prop => { + this.resourceDictionaryRes.forEach((res, index) => { + if (res.name === prop) { + console.log('delete...'); + this.resourceDictionaryRes.splice(index, 1); + this.selectedProps.delete(prop); + } + }); + }); + } + selectAllProps() { + if (this.resourceDictionaryRes.length === this.selectedProps.size) { + this.selectedProps = new Set<string>(); + } else { + this.resourceDictionaryRes.forEach(prop => { + console.log(prop); + this.selectedProps.add(prop.name); + }); + } + + } + reMap() { + let currentResDictionary = []; + if (this.selectedProps && this.selectedProps.size > 0) { + console.log('base'); + this.packageCreationService.getTemplateAndMapping([...this.selectedProps]).subscribe(res => { + let message = 'Re-Auto mapping'; + this.mappingRes = []; + currentResDictionary = res; + console.log(currentResDictionary); + if (currentResDictionary && currentResDictionary.length <= 0) { + message = 'No values for those attributes'; + } + + // Replcae new values with the old ones + currentResDictionary.forEach(curr => { + for (let i = 0; i < this.resourceDictionaryRes.length; i++) { + if (this.resourceDictionaryRes[i].name === curr.name) { + this.resourceDictionaryRes[i] = curr; + } + } + }); + this.rerender(); + this.toastr.success(message, 'Success'); + }, err => { + this.toastr.error('Error'); + }); + } + + } + getFileExtension() { switch (this.templateExt) { - case 'Velcoity': + case 'vtl': return '.vtl'; - case 'Koltin': + case 'kt': return '.ktl'; - case 'Jinja': + case 'j2': return '.j2'; default: return '.vtl'; @@ -141,34 +231,10 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } public getTemplateVariable(fileContent: string) { - const variables: string[] = []; - const stringsSlittedByBraces = fileContent.split('${'); - const stringsDefaultByDollarSignOnly = fileContent.split('"$'); - - for (let i = 1; i < stringsSlittedByBraces.length; i++) { - const element = stringsSlittedByBraces[i]; - if (element) { - const firstElement = element.split('}')[0]; - if (!variables.includes(firstElement)) { - variables.push(firstElement); - } else { - console.log(firstElement); - } - } - } - - for (let i = 1; i < stringsDefaultByDollarSignOnly.length; i++) { - const element = stringsDefaultByDollarSignOnly[i]; - if (element && !element.includes('$')) { - const firstElement = element.split('"')[0] - .replace('{', '') - .replace('}', '').trim(); - if (!variables.includes(firstElement)) { - variables.push(firstElement); - } - } - } - return variables; + // TODO: implement factory Pattern for parser + console.log('start parsing........ ' + this.templateExt); + const parser = this.parserFactory.getParser(fileContent, this.templateExt); + return parser.getVariables(fileContent); } public dropped(files: NgxFileDropEntry[]) { @@ -224,7 +290,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { const parser = new XmlParser(); this.variables = parser.getVariables(fileReader.result.toString()); } - console.log(this.variables); + console.log('variables = ' + this.variables); this.getMappingTableFromTemplate(null); }; @@ -250,7 +316,8 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { const fileReader = new FileReader(); fileReader.onload = (e) => { this.templateFileContent = fileReader.result.toString(); - this.variables = this.getTemplateVariable(this.templateFileContent); + // this.variables = this.getTemplateVariable(this.templateFileContent); + // console.log(this.variables); }; fileReader.readAsText(file); @@ -286,15 +353,30 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.showCreationView.emit('close create form and open list'); } + identify(index, item) { + return item.name; + } + setVelocity(index, value) { + // console.log('velocity value = ' + value); + // console.log(this.resourceDictionaryRes[index]); + // tslint:disable-next-line: no-string-literal + this.resourceDictionaryRes[index].definition.property['metadata'] = { + 'transform-template': value + }; + console.log(this.resourceDictionaryRes[index]); + } + getMappingTableFromTemplate(e) { console.log('-' + this.templateFileContent + '-'); this.resourceDictionaryRes = []; if (e) { e.preventDefault(); } + this.variables = this.getTemplateVariable(this.templateFileContent); + console.log('variables = ' + this.variables); if (this.variables && this.variables.length > 0) { console.log('base'); - this.packageCreationStore.getTemplateAndMapping(this.variables).subscribe(res => { + this.packageCreationService.getTemplateAndMapping(this.variables).subscribe(res => { let message = 'Attributes are Fetched'; this.mappingRes = []; this.resourceDictionaryRes = res; @@ -307,6 +389,8 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { }, err => { this.toastr.error('Error'); }); + } else { + this.toastr.error('Empty or Invalid file format. Validate your file first'); } } @@ -316,7 +400,7 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { } return map.key; } - cancel() { + clear() { this.fileName = ''; this.templateFileContent = ''; this.resourceDictionaryRes = []; @@ -325,6 +409,9 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.currentTemplate = {}; // this.closeCreationForm(); } + cancel() { + this.openListView(); + } saveToStore() { if (this.fileName) { // check file duplication @@ -350,8 +437,9 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { this.fileName = ''; this.toastr.success('File is created', 'success'); this.openListView(); - console.log(this.tourService.getStatus()); - this.tourService.goto('tm-templateEdit'); + if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') { + this.tourService.goto('tm-templateEdit'); + } } else { console.log('this file already exist'); this.toastr.error('File name already exist', 'Error'); @@ -392,24 +480,13 @@ export class TemplMappCreationComponent implements OnInit, OnDestroy { rerender(): void { this.dtTrigger.next(); - - // if (this.dtElement.dtInstance) { - // console.log('rerender'); - // this.dtElement.dtInstance.then((dtInstance: DataTables.Api) => { - // dtInstance.destroy(); - // this.dtElement.dtOptions = this.dtOptions; - // this.dtElement.dtTrigger.next(); - // dtInstance.draw(); - // }); - // } else { - // this.dtTrigger.next(); - // } } ngOnDestroy(): void { // Do not forget to unsubscribe the event this.dtTrigger.unsubscribe(); this.resTableDtTrigger.unsubscribe(); + // this.templateStore.unsubscribe(); } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts index 70e35939b..3a05bcfc5 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/templ-mapp-listing/templ-mapp-listing.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core'; import { PackageCreationStore } from '../../package-creation.store'; import { Mapping, Template } from '../../mapping-models/CBAPacakge.model'; import { TemplateInfo, TemplateStore } from '../../template.store'; @@ -6,6 +6,7 @@ import { TemplateAndMapping } from '../TemplateAndMapping'; import { ActivatedRoute } from '@angular/router'; import { SharedService } from '../shared-service'; import { TourService } from 'ngx-tour-md-menu'; +import { TemplateType } from '../utils/TemplateType'; @Component({ @@ -13,7 +14,7 @@ import { TourService } from 'ngx-tour-md-menu'; templateUrl: './templ-mapp-listing.component.html', styleUrls: ['./templ-mapp-listing.component.css'] }) -export class TemplMappListingComponent implements OnInit { +export class TemplMappListingComponent implements OnInit, OnDestroy { @Output() showCreationView = new EventEmitter<any>(); @Output() showListView = new EventEmitter<any>(); templateAndMappingMap = new Map<string, TemplateAndMapping>(); @@ -22,7 +23,7 @@ export class TemplMappListingComponent implements OnInit { isCreate = true; currentFile: string; edit = false; - fileToDelete: any = {}; + fileToDelete = ''; constructor( private packageCreationStore: PackageCreationStore, @@ -30,11 +31,17 @@ export class TemplMappListingComponent implements OnInit { private route: ActivatedRoute, private sharedService: SharedService, private tourService: TourService, - ) { } + ngOnDestroy(): void { + // this.templateStore.unsubscribe(); + // this.packageCreationStore.unsubscribe(); + } + ngOnInit() { + this.templateAndMappingMap = new Map<string, TemplateAndMapping>(); + this.edit = false; if (this.route.snapshot.paramMap.has('id')) { this.isCreate = false; this.sharedService.isEdit().subscribe(res => { @@ -73,7 +80,9 @@ export class TemplMappListingComponent implements OnInit { } private setIsMappingOrTemplate(key: string, templateAndMapping: TemplateAndMapping, isFromTemplate: boolean) { - const nameOfFile = key.split('/')[1].split('.')[0].split('-')[0]; + const nameOfFile = isFromTemplate ? + key.split('/')[1].split('.')[0].split('-template')[0] + : key.split('/')[1].split('.')[0].split('-mapping')[0]; // const fullName = nameOfFile + ',' + key.split('.'); if (this.templateAndMappingMap.has(nameOfFile)) { const templateAndMappingExisted = this.templateAndMappingMap.get(nameOfFile); @@ -102,12 +111,16 @@ export class TemplMappListingComponent implements OnInit { createNewTemplate() { this.openCreationView(); this.sharedService.disableEdit(); - this.tourService.goto('tm-templateName'); + if (localStorage.getItem('tour-guide') !== 'end' && localStorage.getItem('tour-guide') !== 'false') { + this.tourService.goto('tm-templateName'); + } } + openCreationView() { this.showCreationView.emit('tell parent to open create views'); console.log('disable edit mode'); } + openListView() { console.log('open list view'); this.showListView.emit('show full view'); @@ -115,19 +128,25 @@ export class TemplMappListingComponent implements OnInit { setSourceCodeEditor(key: string) { this.currentFile = key; - const templateKey = 'Templates/' + key + '-template.vtl'; + const templateKey = 'Templates/' + key + '-template'; this.packageCreationStore.state$.subscribe(cba => { console.log('cba ------'); console.log(cba); console.log(key); console.log(this.templateAndMappingMap); const templateInfo = new TemplateInfo(); - if (cba.templates && cba.templates.files.has(templateKey)) { - const fileContent = cba.templates.getValue(templateKey.trim()); - console.log(fileContent); - templateInfo.fileContent = fileContent; - templateInfo.fileName = templateKey; - templateInfo.type = 'template'; + // tslint:disable-next-line: forin + for (const templateType in TemplateType) { + const fileName = templateKey + '.' + TemplateType[templateType]; + if (cba.templates && cba.templates.files.has(fileName)) { + const fileContent = cba.templates.getValue(fileName.trim()); + console.log(templateType + '......ccccccc.... ' + fileName); + templateInfo.fileContent = fileContent; + templateInfo.fileName = fileName; + templateInfo.ext = TemplateType[templateType]; + templateInfo.type = 'template'; + break; + } } const mappingKey = 'Templates/' + key + '-mapping.json'; if (cba.mapping && cba.mapping.files.has(mappingKey)) { @@ -138,7 +157,9 @@ export class TemplMappListingComponent implements OnInit { } this.templateStore.changeTemplateInfo(templateInfo); this.openCreationView(); - this.sharedService.enableEdit(); + if (templateInfo.fileName && templateInfo.fileName.length > 0) { + this.sharedService.enableEdit(); + } }); } @@ -149,20 +170,34 @@ export class TemplMappListingComponent implements OnInit { getValue(file: string) { return this.templateAndMappingMap.get(file); } + initDelete(file) { console.log(file); - this.fileToDelete = file; + const templateKey = 'Templates/' + file + '-template'; + // tslint:disable-next-line: forin + for (const templateType in TemplateType) { + const fileName = templateKey + '.' + TemplateType[templateType]; + if (this.packageCreationStore.state.templates.files.has(fileName)) { + this.fileToDelete = fileName; + break; + } + } + } + condifrmDelete() { - console.log(this.templateAndMappingMap); - this.templateAndMappingMap.delete(this.fileToDelete); + const fullName = this.fileToDelete.split('/')[1]; + const file = fullName.substr(0, fullName.lastIndexOf('-')); + const ext = fullName.substr(fullName.lastIndexOf('.') + 1); + this.templateAndMappingMap.delete(file); if (this.templateAndMappingMap.size <= 0) { this.openCreationView(); } // Delete from templates - this.packageCreationStore.state.templates.files.delete('Templates/' + this.fileToDelete + '-template.vtl'); + this.packageCreationStore.state.templates.files.delete('Templates/' + file + '-template.' + ext); // Delete from Mapping - this.packageCreationStore.state.mapping.files.delete('Templates/' + this.fileToDelete + '-mapping.json'); + this.packageCreationStore.state.mapping.files.delete('Templates/' + file + '-mapping.json'); + console.log(this.templateAndMappingMap); } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts index 341d29f66..15361b8ad 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/template-mapping.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { ActivatedRoute } from '@angular/router'; import { PackageCreationStore } from '../package-creation.store'; import { SharedService } from './shared-service'; @@ -8,7 +8,7 @@ import { SharedService } from './shared-service'; templateUrl: './template-mapping.component.html', styleUrls: ['./template-mapping.component.css'] }) -export class TemplateMappingComponent implements OnInit { +export class TemplateMappingComponent implements OnInit, OnDestroy { creationView = false; listView = true; @@ -18,6 +18,11 @@ export class TemplateMappingComponent implements OnInit { private sharedService: SharedService ) { } + ngOnDestroy(): void { + // this.sharedService.list.unsubscribe(); + // this.sharedService.mode.unsubscribe(); + // this.pakcageStore.unsubscribe(); + } ngOnInit() { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts deleted file mode 100644 index e90377e0c..000000000 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.spec.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { XmlParser } from './XmlParser'; - -fdescribe('ImportsTabComponent', () => { - const parser: XmlParser = new XmlParser(); - - - beforeEach(() => { - }); - - it('Test xml Parser', () => { - const fileContent = `<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> - <vdns-instances> - <vdns-instance> - <ip-addr>$vdns_int_private_ip_0</ip-addr> - <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> - <enabled>false</enabled> - <tag>dddd</tag> - </vdns-instance> - </vdns-instances> - </vlb-business-vnf-onap-plugin>`; - - const res = parser.getVariables(fileContent); - console.log(res); - expect(res.length).toEqual(2); - expect(res[0]).toEqual('vdns_int_private_ip_0'); - expect(res[1]).toEqual('vdns_onap_private_ip_0'); - }); -}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts new file mode 100644 index 000000000..c9e0a1891 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ASCII-Parser.ts @@ -0,0 +1,19 @@ +import { Parser } from './Parser'; + +export class ASCIIParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('$(')) { + const xmlSplit = fileContent.split('$('); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf(')')); + if (res && res.length > 0) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts new file mode 100644 index 000000000..cb1359aa0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaXML.ts @@ -0,0 +1,31 @@ +import { Parser } from './Parser'; + +export class JinjaXMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('>[')) { + const xmlSplit = fileContent.split('>['); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf(']</')); + if (res && res.length > 0) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} + +/* + +<?xml version="1.0" encoding="UTF-8"?> +<configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> +<system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> +<host-name operation="delete" /> +<host-name operation="create">[hostname]</host-name> +</system> +</configuration> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts new file mode 100644 index 000000000..6ecee9070 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/JinjaYML.ts @@ -0,0 +1,43 @@ +import { Parser } from './Parser'; + +export class JinjaYMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('{{')) { + // '[{]+[ ]*.[V-v]alues.' old regex + const xmlSplit = fileContent.split(new RegExp('[{]+[ ]*.')); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf('}}')); + if (res && res.length > 0) { + console.log(res); + if (res.includes('Value')) { + this.variables.add(this.extractValues(res.trim())); + } else { + this.variables.add(this.extractParent(res.trim()).toLowerCase()); + } + } + } + } + return [...this.variables]; + } + + extractValues(value) { + return value.split('Values.')[1]; + } + extractParent(value): string { + return value.split('.')[0]; + } + +} + +/* +vf-module-name: {{ .Values.vpg_name_0 }} +<?xml version="1.0" encoding="UTF-8"?> +<configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> +<system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> +<host-name operation="delete" /> +<host-name operation="create">[hostname]</host-name> +</system> +</configuration> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts new file mode 100644 index 000000000..3a1880c99 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.spec.ts @@ -0,0 +1,153 @@ +import { XmlParser } from './XmlParser'; +import { ParserFactory } from './ParserFactory'; +import { FileExtension } from '../TemplateType'; +import { JinjaXMLParser } from './JinjaXML'; + +fdescribe('ImportsTabComponent', () => { + + const parserFactory = new ParserFactory(); + + + beforeEach(() => { + }); + + it('Test xml Parser', () => { + const fileContent = `<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> + </vlb-business-vnf-onap-plugin>`; + + const parser = parserFactory.getParser(fileContent, FileExtension.XML); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(2); + expect(res[0]).toEqual('vdns_int_private_ip_0'); + expect(res[1]).toEqual('vdns_onap_private_ip_0'); + }); + + it('Test J2 XML Parser', () => { + const fileContent = `<?xml version="1.0" encoding="UTF-8"?> + <configuration xmlns:junos="http://xml.juniper.net/junos/17.4R1/junos"> + <system xmlns="http://yang.juniper.net/junos-qfx/conf/system"> + <host-name operation="delete" /> + <host-name operation="create">[hostname]</host-name> + </system> + </configuration>`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(typeof (res)); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('hostname'); + + }); + + it('Test J2 YML Parser', () => { + const fileContent = `apiVersion: v1 + kind: Service + metadata: + name: {{ .Values.vpg_name_0 }}-ssh + labels: + vnf-name: {{ .Values.vnf_name }} + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }} + spec: + type: NodePort + ports: + port: 22 + nodePort: \${vpg-management-port} + selector: + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }}`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(4); + expect(res[0]).toEqual('vpg_name_0'); + expect(res[1]).toEqual('vnf_name'); + + }); + + it('Test ASCII Parser', () => { + const fileContent = ` + config system interface + edit "internal" + set vdom "root" + set ip $(subnet1_fgt_ip) 255.255.255.0 #1 + set allowaccess ping https ssh http fgfm capwap + set type hard-switch + set stp enable + set role lan + next + end + config system dhcp server + edit 1 + set dns-service default + set default-gateway $(subnet1_fgt_ip) #2 + set netmask 255.255.255.0 + set interface "internal" + config ip-range + edit 1 + set start-ip $(subnet1_fgt_ip)4,150 #3 + set end-ip $(subnet1_fgt_ip)4,200 #4 + next + end + next + end + Options + `; + + const parser = parserFactory.getParser(fileContent, FileExtension.Jinja); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('subnet1_fgt_ip'); + + + }); + + + + + + it('Test Velocity YML Parser', () => { + const fileContent = `apiVersion: v1 + kind: Service + metadata: + name: {{ .Values.vpg_name_0 }}-ssh + labels: + vnf-name: {{ .Values.vnf_name }} + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }} + spec: + type: NodePort + ports: + port: 22 + nodePort: \${vpg-management-port} + selector: + vf-module-name: {{ .Values.vpg_name_0 }} + release: {{ .Release.Name }} + chart: {{ .Chart.Name }}`; + + const parser = parserFactory.getParser(fileContent, FileExtension.Velocity); + const res = parser.getVariables(fileContent); + console.log(res); + expect(res.length).toEqual(1); + expect(res[0]).toEqual('vpg-management-port'); + + }); + + + +}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.ts index 495c64307..f189a84ca 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/Parser.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/Parser.ts @@ -1,3 +1,4 @@ export interface Parser { + variables: Set<string>; getVariables(fileContent: string): string[]; } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts new file mode 100644 index 000000000..b64afeed0 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/ParserFactory.ts @@ -0,0 +1,73 @@ + +import { XmlParser } from './XmlParser'; +import { Parser } from './Parser'; +import { VtlParser } from './VtlParser'; +import { FileExtension } from '../TemplateType'; +import { JinjaXMLParser } from './JinjaXML'; +import { VtlYMLParser } from './VtlYMLParser'; +import { JinjaYMLParser } from './JinjaYML'; +import { ASCIIParser } from './ASCII-Parser'; + +export class ParserFactory { + + getParser(fileContent: string, fileExtension: string): Parser { + let parser: Parser; + console.log('file extension =' + fileExtension); + + if (fileExtension === FileExtension.Velocity) { + + if (this.isXML(fileContent)) { + parser = new XmlParser(); + } else if (this.isJSON(fileContent)) { + parser = new VtlParser(); + } else if (this.isASCII(fileContent)) { + parser = new ASCIIParser(); + } else { + console.log('Velocity YML parser....'); + parser = new VtlYMLParser(); + } + + } else if (fileExtension === FileExtension.Jinja) { + + if (this.isXML(fileContent)) { + parser = new JinjaXMLParser(); + } else if (this.isJSON(fileContent)) { + // TODO: implement JSON parser + } else if (this.isASCII(fileContent)) { + parser = new ASCIIParser(); + } else { + console.log('Jinja YML parser....'); + parser = new JinjaYMLParser(); + } + + } else if (fileExtension === FileExtension.XML) { + parser = new XmlParser(); + } + return parser; + } + + private isXML(fileContent: string): boolean { + return fileContent.includes('<?xml version="1.0" encoding="UTF-8"?>'); + } + + private isJSON(fileContent: string): boolean { + try { + JSON.parse(fileContent); + } catch (e) { + return false; + } + return true; + } + + private isASCII(fileContent: string): boolean { + if ( + fileContent.includes('end') && + fileContent.includes('set') && + fileContent.includes('$(') + ) { + return true; + } + + return false; + } +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts new file mode 100644 index 000000000..ca80a297c --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlParser.ts @@ -0,0 +1,53 @@ +import { Parser } from './Parser'; + +export class VtlParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + const variables: string[] = []; + const stringsSlittedByBraces = fileContent.split('${'); + const stringsDefaultByDollarSignOnly = fileContent.split('"$'); + + for (let i = 1; i < stringsSlittedByBraces.length; i++) { + const element = stringsSlittedByBraces[i]; + if (element) { + const firstElement = element.split('}')[0]; + if (!variables.includes(firstElement)) { + variables.push(firstElement); + } else { + console.log(firstElement); + } + } + } + + for (let i = 1; i < stringsDefaultByDollarSignOnly.length; i++) { + const element = stringsDefaultByDollarSignOnly[i]; + if (element && !element.includes('$')) { + const firstElement = element.split('"')[0] + .replace('{', '') + .replace('}', '').trim(); + if (!variables.includes(firstElement)) { + variables.push(firstElement); + } + } + } + this.variables = new Set(variables); + return [...variables]; + } + +} + +/* + +<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <tag>aaaa</tag> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> +</vlb-business-vnf-onap-plugin> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts new file mode 100644 index 000000000..6c3a0e0fd --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/VtlYMLParser.ts @@ -0,0 +1,35 @@ +import { Parser } from './Parser'; + +export class VtlYMLParser implements Parser { + variables: Set<string> = new Set(); + getVariables(fileContent: string): string[] { + if (fileContent.includes('${')) { + const xmlSplit = fileContent.split('${'); + for (const val of xmlSplit) { + const res = val.substring(0, val.indexOf('}')); + if (res && res.length > 0 && !res.includes('{')) { + this.variables.add(res); + } + + } + } + return [...this.variables]; + } + +} + +/* + +<vlb-business-vnf-onap-plugin xmlns="urn:opendaylight:params:xml:ns:yang:vlb-business-vnf-onap-plugin"> + <vdns-instances> + <vdns-instance> + <ip-addr>$vdns_int_private_ip_0</ip-addr> + <oam-ip-addr>$vdns_onap_private_ip_0</oam-ip-addr> + <tag>aaaa</tag> + <enabled>false</enabled> + <tag>dddd</tag> + </vdns-instance> + </vdns-instances> +</vlb-business-vnf-onap-plugin> + +*/ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/XmlParser.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/XmlParser.ts index 4feb7032a..69bc8b627 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/XmlParser.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/ParserFactory/XmlParser.ts @@ -1,18 +1,17 @@ import { Parser } from './Parser'; -import { variable } from '@angular/compiler/src/output/output_ast'; export class XmlParser implements Parser { + variables: Set<string> = new Set(); getVariables(fileContent: string): string[] { - const variables = []; const xmlSplit = fileContent.split('$'); for (const val of xmlSplit) { const res = val.substring(0, val.indexOf('</')); if (res && res.length > 0) { - variables.push(res); + this.variables.add(res); } } - return variables; + return [...this.variables]; } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts new file mode 100644 index 000000000..04a829e8a --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template-mapping/utils/TemplateType.ts @@ -0,0 +1,13 @@ +export enum TemplateType { + Velocity = 'vtl', + Koltin = 'kt', + Jinja = 'j2', +} + +export enum FileExtension { + Velocity = 'vtl', + Koltin = 'kt', + Jinja = 'j2', + CSV = 'csv', + XML = 'xml' +} diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts index 9c8775514..4b12bb130 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/package-creation/template.store.ts @@ -28,6 +28,7 @@ export class TemplateInfo { fileName: string; fileContent: string; type: string; + ext: string; mapping = []; @@ -35,6 +36,7 @@ export class TemplateInfo { this.fileName = ''; this.fileContent = ''; this.type = ''; + this.ext = ''; } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/filter-by-tags/filter-by-tags.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/filter-by-tags/filter-by-tags.component.ts index 0555fd5ab..6f02bbab8 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/filter-by-tags/filter-by-tags.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/filter-by-tags/filter-by-tags.component.ts @@ -114,6 +114,7 @@ export class TagsFilteringComponent implements OnInit { this.checkBoxTages = ''; this.checkboxes.forEach((element) => { element.nativeElement.checked = false; + this.packagesStore.getAll(); }); } } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/guideSteps.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/guideSteps.ts index 5026980de..6601e2f17 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/guideSteps.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/guideSteps.ts @@ -23,28 +23,28 @@ export const steps = [ }, { anchorId: 'metadataTab', - content: 'Set your package basic information', + content: 'It captures the model entities that compose the cba package name, version, description and searchable tags.', title: 'Metadata Tab', route: 'packages/createPackage' }, { anchorId: 'mt-packageName', - content: 'Set your package name (required)', + content: 'Set your package name (required).', title: 'Package name', }, { anchorId: 'mt-packageVersion', - content: 'Set your package version like 1.0.0 (required)', + content: 'Set your package version like 1.0.0 (required).', title: 'Package version', }, { anchorId: 'mt-packageDescription', - content: 'Set your package description (required)', + content: 'Set your package description (required).', title: 'Package description', }, { anchorId: 'mt-packageTags', - content: 'Set your package Tags (Optional)', + content: 'Set your package Tags (Optional).', title: 'Package tag', }, // { @@ -55,66 +55,66 @@ export const steps = [ // Temaplate & Mapping { anchorId: 'tm-templateTab', - content: 'Create Your \'Template & Mapping \' files', + content: 'A template is an artifact, and uses Modeling Concepts#artifact-mapping-resource and artifact-template-velocity. ', title: 'Temaplate & Mapping', stepId: 'tm-templateTab' }, { anchorId: 'tm-templateName', - content: 'Set your Template & Mapping Name', + content: 'Set your Template & Mapping Name.', title: 'Temaplte & Mapping name', stepId: 'tm-templateName' }, { anchorId: 'tm-templateType', - content: 'Set your Template Type', + content: 'Set your Template Type.', title: 'Temaplte Type', }, { anchorId: 'tm-templateContent', - content: 'Click \'Import File\' to get content from a file, or write template content manually', + content: 'Click \'Import File\' to get content from a file, or write template content manually.', title: 'Template Content', }, { anchorId: 'tm-mappingContent', - content: 'Set your mapping content from the current template, or from an external file (XML, CSV)', + content: 'Set your mapping content from the current template, or from an external file (XML, CSV).', title: 'Mapping Content', }, { anchorId: 'tm-templateFinish', - content: 'Click your \' Finish \' button when you finish ', + content: 'Click your \'Finish\' button to save your template.', title: 'Finish', stepId: 'tm-templateFinish' }, - { - anchorId: 'tm-templateEdit', - content: 'Create another new Template or Click on the previous one to edit', - title: 'Create & Edit', - stepId: 'tm-templateEdit' - }, + // { + // anchorId: 'tm-templateEdit', + // content: 'Create another new Template or Click on the previous one to edit.', + // title: 'Create & Edit', + // stepId: 'tm-templateEdit' + // }, // Script { anchorId: 'st-scriptsTab', - content: 'Move To Scripts Tab to set your Kotlin and Python scripts', + content: 'It is Kotlin/Python scripts that allows the execution of a sequence of instructions as part of CDS workflow execution.', title: 'Scripts', stepId: 'st-scriptsTab' }, { anchorId: 'st-scriptsImport', - content: 'Click \' Import File\'button kotlin and python files', + content: 'Click to import kotlin or python files.', title: 'Import File' }, // DSL { anchorId: 'dslTab', - content: 'Write your Authentication Properties in Javascript', - title: 'ESAP', + content: 'Interaction with external systems is made dynamic, removing development cycle to support new endpoint.', + title: 'External Systems support', stepId: 'dslTab' }, // save package { anchorId: 'packageSave', - content: 'Click \' Save \' button to create your package', + content: 'Click to save your package.', title: 'Save' } ]; diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.css b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.css new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.css diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.html new file mode 100644 index 000000000..d578582fd --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.html @@ -0,0 +1,59 @@ +<div class="modal fade" id="importPackageModal" tabindex="-1" role="dialog" aria-labelledby="importPackageModal" + aria-hidden="true"> + <div class="modal-dialog" role="document"> + <div class="modal-content"> + <div class="modal-header"> + <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> --> + <img src="assets/img/icon-close.svg"/> + </button> + </div> + <div class="modal-body"> + <ngx-file-drop accept=".zip" 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"/> + </div> + <div class="folder-upload-text"> + Drag & Drop file + </div> + <div class="folder-upload-text">or + <button type="button" class="btn btn-sm btn-primary" (click)="openFileSelector()">Browse + Files + </button> + </div> + <div class="folder-upload-type">Allowed file type: zip</div> + </ng-template> + </ngx-file-drop> + <div class="upload-table"> + <table class="table"> + <thead> + <tr *ngFor="let item of uploadedFiles; let i=index"> + <th width="40"><img src="assets/img/icon-file-code.svg"/></th> + <th>{{ item.name }}</th> + <th (click)="removeInitFile(i)" width="40" class="text-right"><img + src="assets/img/icon-remove-file.svg"/></th> + </tr> + </thead> + </table> + </div> + </div> + <div class="modal-footer"> + <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal" + (click)="resetTheUploadedFiles()">Cancel + </button> + <button type="button" class="btn btn-sm btn-primary" [disabled]="uploadedFiles?.length<=0" + data-dismiss="modal" (click)="importAndSave()"> + Import&Save + </button> + <button type="button" class="btn btn-sm btn-primary" [disabled]="uploadedFiles?.length<=0" + data-dismiss="modal" (click)="importPackageAndViewIt()"> + Import + </button> + + </div> + </div> + </div> +</div> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.spec.ts new file mode 100644 index 000000000..c594b34aa --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ImportPackageComponent } from './import-package.component'; + +describe('ImportPackageComponent', () => { + let component: ImportPackageComponent; + let fixture: ComponentFixture<ImportPackageComponent>; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ImportPackageComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ImportPackageComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.ts new file mode 100644 index 000000000..7496338d6 --- /dev/null +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/import-package/import-package.component.ts @@ -0,0 +1,126 @@ +import {Component, OnInit} from '@angular/core'; +import {FileSystemFileEntry, NgxFileDropEntry} from 'ngx-file-drop'; +import {PackageCreationExtractionService} from '../../package-creation/package-creation-extraction.service'; +import {Router} from '@angular/router'; +import {PackageCreationStore} from '../../package-creation/package-creation.store'; +import * as JSZip from 'jszip'; +import {PackageCreationService} from '../../package-creation/package-creation.service'; +import {ToastrService} from 'ngx-toastr'; +import {PackagesStore} from '../../packages.store'; + +@Component({ + selector: 'app-import-package', + templateUrl: './import-package.component.html', + styleUrls: ['./import-package.component.css'] +}) +export class ImportPackageComponent implements OnInit { + + public uploadedFiles: FileSystemFileEntry[] = []; + private fileNames: Set<string> = new Set(); + fileToDelete: any = {}; + zipFile: JSZip = new JSZip(); + public files: NgxFileDropEntry[] = []; + + constructor(private packageCreationExtractionService: PackageCreationExtractionService, + private packageCreationStore: PackageCreationStore, + private packageCreationService: PackageCreationService, + private toastService: ToastrService, + private packagesStore: PackagesStore, + private router: Router) { + + } + + ngOnInit() { + + } + + removeInitFile(index) { + this.uploadedFiles.splice(index, 1); + } + + public dropped(files: NgxFileDropEntry[]) { + this.files = files; + for (const droppedFile of files) { + // Is it a file? & Not added before + if (droppedFile.fileEntry.isFile) { + const fileEntry = droppedFile.fileEntry as FileSystemFileEntry; + this.uploadedFiles.push(fileEntry); + console.log(fileEntry.name); + this.fileNames.add(fileEntry.name); + + } + } + } + + initDelete(file) { + console.log(file); + this.fileToDelete = file; + } + + removeFile() { + const filename = this.fileToDelete.key; + for (let i = 0; i < this.uploadedFiles.length; i++) { + console.log(this.uploadedFiles[i]); + if (this.uploadedFiles[i].name === filename) { + this.uploadedFiles.splice(i, 1); + break; + } + } + } + + resetTheUploadedFiles() { + this.uploadedFiles = []; + } + + + public fileOver(event) { + console.log(event); + } + + public fileLeave(event) { + console.log(event); + } + + importPackageAndViewIt() { + this.openFilesInCreationPackage(); + this.saveFileToStore(); + } + + saveFileToStore() { + console.log(this.uploadedFiles.length); + const file = this.getFile(this.uploadedFiles[this.uploadedFiles.length - 1]); + this.packageCreationStore.clear(); + this.packageCreationExtractionService.extractBlobToStore(file); + } + + openFilesInCreationPackage() { + this.router.navigate(['/packages/createPackage/']); + } + + async getFile(fileEntry) { + try { + return await new Promise((resolve, reject) => fileEntry.file(resolve, reject)); + } catch (err) { + console.log(err); + } + } + + importAndSave() { + const file = this.getFile(this.uploadedFiles[this.uploadedFiles.length - 1]); + this.zipFile = new JSZip(); + this.zipFile.loadAsync(file).then(zip => { + this.zipFile = zip; + console.log(this.zipFile); + this.resetTheUploadedFiles(); + this.zipFile.generateAsync({type: 'blob'}).then(blob => { + this.packageCreationService.savePackage(blob).subscribe( + bluePrintDetailModels => { + this.toastService.info('package is imported and saved successfully '); + this.router.navigate(['/packages']); + this.packagesStore.getAll(); + }, error => + this.toastService.error('there is an error happened ' + error)); + }); + }); + } +} 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 1390a7b78..0bb4f1f41 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 @@ -12,7 +12,8 @@ Package </a> <br /> - <a href="#" id="clone-btn" role="button" aria-pressed="true" class="btn-import-package float"><i + <a data-target="#importPackageModal" data-toggle="modal" id="clone-btn" role="button" + aria-pressed="true" class="btn-import-package float"><i class="icon-import-blue" aria-hidden="true"></i>Import Package </a> <ngx-ui-loader></ngx-ui-loader> @@ -121,3 +122,6 @@ </div> </div> </div> + + +<app-import-package></app-import-package> diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.ts index 3cecd33fd..4d0e108cf 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/package-list/package-list.component.ts @@ -39,10 +39,6 @@ export class PackageListComponent implements OnInit { ngOnInit() { this.packagesStore.getAll(); - - - - } view(id) { diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-dashboard.component.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-dashboard.component.ts index c6b9c41f6..9862608b4 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-dashboard.component.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-dashboard.component.ts @@ -39,8 +39,6 @@ export class PackagesDashboardComponent implements OnInit, OnDestroy { ngOnInit() { console.log('PackagesDashboardComponent'); - - this.tourService.initialize([...steps]); this.checkTour(); } @@ -53,10 +51,17 @@ export class PackagesDashboardComponent implements OnInit, OnDestroy { } start() { + + this.tourService.initialize([...steps]); console.log('start .................'); this.tourService.start(); + localStorage.setItem('tour-guide', 'start'); this.tourService.events$.subscribe(res => { console.log(res); + + if (res.name === 'end') { + localStorage.setItem('tour-guide', 'end'); + } if (res.value && res.value.anchorId) { if (res.value.anchorId.includes('mt-')) { $('#nav-metadata-tab').trigger('click'); @@ -76,6 +81,7 @@ export class PackagesDashboardComponent implements OnInit, OnDestroy { if (res.value.anchorId.includes('st-')) { $('#nav-scripts-tab').trigger('click'); } + } }); } diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-header/packages-header.component.html b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-header/packages-header.component.html index 936c2da8d..17955ec4e 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-header/packages-header.component.html +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages-dashboard/packages-header/packages-header.component.html @@ -23,6 +23,16 @@ </p> </li> --> <li> + <i class="icon-get_started" aria-hidden="true"></i> + <p> + <input id="clicker3" type="checkbox" /> + <label for="clicker"> + Getting Started + <span>Quick steps to help you get started</span> + </label> + </p> + </li> + <li> <a href="https://wiki.onap.org/display/DW/CDS+Designer+Guide" target="_blank"> <i class="icon-user_guide" aria-hidden="true"></i> <p> 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 8e5d8b0b8..d152e1ef3 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,36 +1,40 @@ -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'; -import { NgxUiLoaderModule } from 'ngx-ui-loader'; +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'; +import {NgxUiLoaderModule} from 'ngx-ui-loader'; import {TourMatMenuModule} from 'ngx-tour-md-menu'; +import {ComponentCanDeactivateGuard} from '../../../common/core/canDactivate/ComponentCanDeactivateGuard'; +import { ImportPackageComponent } from './packages-dashboard/import-package/import-package.component'; +import { FunctionsAttributeComponent } from './designer/functions-attribute/functions-attribute.component'; +import { ActionAttributesComponent } from './designer/action-attributes/action-attributes.component'; @NgModule({ declarations: [PackagesDashboardComponent, @@ -53,6 +57,10 @@ import {TourMatMenuModule} from 'ngx-tour-md-menu'; MetadataTabComponent, DslDefinitionsTabComponent, DesignerSourceViewComponent, + ImportPackageComponent, + FunctionsAttributeComponent, + ActionAttributesComponent, + ], imports: [ CommonModule, @@ -68,7 +76,7 @@ import {TourMatMenuModule} from 'ngx-tour-md-menu'; NgxUiLoaderModule, TourMatMenuModule.forRoot() ], - providers: [ApiService, JsonPipe], + providers: [ApiService, JsonPipe, ComponentCanDeactivateGuard], bootstrap: [] }) export class PackagesModule { 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 f357bc167..d9671d04c 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 @@ -1,10 +1,11 @@ import {NgModule} from '@angular/core'; -import {Routes, RouterModule} from '@angular/router'; +import {RouterModule, Routes} from '@angular/router'; import {PackagesDashboardComponent} from './packages-dashboard/packages-dashboard.component'; 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'; +import {DesignerSourceViewComponent} from './designer/source-view/source-view.component'; +import {ComponentCanDeactivateGuard} from '../../../common/core/canDactivate/ComponentCanDeactivateGuard'; const routes: Routes = [ @@ -14,8 +15,8 @@ const routes: Routes = [ }, {path: 'designer/:id', component: DesignerComponent}, {path: 'designer/source/:id', component: DesignerSourceViewComponent}, - {path: 'package/:id', component: ConfigurationDashboardComponent}, - {path: 'createPackage', component: PackageCreationComponent} + {path: 'package/:id', component: ConfigurationDashboardComponent, canDeactivate: [ComponentCanDeactivateGuard]}, + {path: 'createPackage', component: PackageCreationComponent, canDeactivate: [ComponentCanDeactivateGuard]} ]; @NgModule({ diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.spec.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.spec.ts index 98b18bf9d..379aaddf2 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.spec.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.spec.ts @@ -1,14 +1,14 @@ -import {TestBed} from '@angular/core/testing'; -import {PackagesStore} from './packages.store'; -import {HttpClientTestingModule, HttpTestingController} from '@angular/common/http/testing'; -import {PackagesApiService} from './packages-api.service'; -import {of} from 'rxjs'; -import {BluePrintPage} from './model/BluePrint.model'; -import {getBluePrintPageMock} from './blueprint.page.mock'; -import {PackagesDashboardState} from './model/packages-dashboard.state'; - -fdescribe('PackagesStore', () => { - let store: PackagesStore; +import { TestBed } from '@angular/core/testing'; +import { PackagesStore } from './packages.store'; +import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; +import { PackagesApiService } from './packages-api.service'; +import { of } from 'rxjs'; +import { BluePrintPage } from './model/BluePrint.model'; +import { getBluePrintPageMock } from './blueprint.page.mock'; +import { PackagesDashboardState } from './model/packages-dashboard.state'; + +describe('PackagesStore', () => { + // store: PackagesStore; const MOCK_BLUEPRINTS_PAGE: BluePrintPage = getBluePrintPageMock(); @@ -34,7 +34,7 @@ fdescribe('PackagesStore', () => { // set the value to return when the ` getPagedPackages` spy is called. packagesServiceSpy.getPagedPackages.and.returnValue(of([MOCK_BLUEPRINTS_PAGE])); - store = new PackagesStore(packagesServiceSpy); + // store = new PackagesStore(packagesServiceSpy); // Todo check the Abbas's code /*store.getPagedPackages(0, 2); @@ -49,11 +49,11 @@ fdescribe('PackagesStore', () => { // set the value to return when the `getPagedPackages` spy is called. packagesServiceSpy.getPagedPackages.and.returnValue(of([MOCK_BLUEPRINTS_PAGE])); - store = new PackagesStore(packagesServiceSpy); - store.getAll(); - store.state$.subscribe(page => { - expect(store.state.page).toEqual(MOCK_BLUEPRINTS_PAGE); - }); + // store = new PackagesStore(packagesServiceSpy); + // store.getAll(); + // store.state$.subscribe(page => { + // expect(store.state.page).toEqual(MOCK_BLUEPRINTS_PAGE); + // }); }); }); diff --git a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.ts b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.ts index b6d008b67..1377d256a 100644 --- a/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.ts +++ b/cds-ui/designer-client/src/app/modules/feature-modules/packages/packages.store.ts @@ -32,7 +32,7 @@ import { NgxUiLoaderService } from 'ngx-ui-loader'; }) export class PackagesStore extends Store<PackagesDashboardState> { // TDOD fixed for now as there is no requirement to change it from UI - public pageSize = 5; + public pageSize = 15; private bluePrintContent: BluePrintPage = new BluePrintPage(); constructor( diff --git a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.eot b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.eot Binary files differindex 0ef083807..2bdafa68d 100755 --- a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.eot +++ b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.eot diff --git a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.svg b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.svg index d5bbb8308..7b07f9c3f 100755 --- a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.svg +++ b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.svg @@ -17,6 +17,12 @@ <glyph unicode="" glyph-name="icon-enrich" horiz-adv-x="723" d="M643.818 562.272h-240.316l20.882 363.431c1.945 33.821-43.138 47.578-60.352 18.306l-312.986-532.253c-12.694-21.586 2.893-48.888 27.965-48.888h240.317l-20.884-363.431c-1.945-33.823 43.14-47.574 60.352-18.306l312.986 532.251c12.692 21.589-2.895 48.89-27.965 48.89zM370.919 129.754l15.154 263.697c1.069 18.617-13.757 34.301-32.389 34.301h-217.964l216.186 367.635-15.152-263.698c-1.069-18.617 13.757-34.301 32.389-34.301h217.962l-216.186-367.633zM67.885 180.705l-56.849-56.849c-12.669-12.669-12.669-33.209 0-45.878 12.667-12.669 33.209-12.671 45.878 0l56.849 56.849c12.669 12.669 12.669 33.209 0 45.878-12.667 12.671-33.209 12.671-45.878 0zM67.885 714.493c12.667-12.669 33.209-12.671 45.878 0 12.669 12.669 12.669 33.209 0 45.878l-56.849 56.849c-12.667 12.669-33.209 12.669-45.878 0s-12.669-33.209 0-45.878l56.849-56.849zM654.942 180.705c-12.667 12.669-33.209 12.669-45.878 0s-12.669-33.209 0-45.878l56.849-56.849c12.667-12.669 33.209-12.671 45.878 0 12.669 12.669 12.669 33.209 0 45.878l-56.849 56.849zM654.942 714.493l56.849 56.849c12.669 12.669 12.669 33.209 0 45.878-12.667 12.669-33.209 12.669-45.878 0l-56.849-56.849c-12.669-12.669-12.669-33.209 0-45.878 12.665-12.667 33.209-12.669 45.878 0z" /> <glyph unicode="" glyph-name="icon-get_started" d="M1003.008 959.872c-199.893 3.584-427.861-100.907-572.16-262.997-137.899-2.603-272.171-59.136-371.029-157.995-5.76-5.675-7.808-14.165-5.291-21.845 2.56-7.723 9.216-13.312 17.237-14.464l164.437-23.552-20.309-22.741c-7.552-8.448-7.168-21.291 0.853-29.312l274.219-274.219c4.139-4.139 9.6-6.229 15.104-6.229 5.077 0 10.155 1.792 14.208 5.419l22.741 20.309 23.552-164.437c1.152-8.021 7.467-13.909 15.104-16.469 1.963-0.64 4.011-0.939 6.101-0.939 6.059 0 12.245 2.645 16.512 6.869 97.493 97.493 154.027 231.765 156.629 369.664 162.261 144.597 267.605 372.48 262.955 572.117-0.299 11.349-9.472 20.523-20.864 20.821zM806.4 591.573c-20.779-20.779-48.085-31.189-75.435-31.189s-54.656 10.411-75.435 31.189c-41.557 41.6-41.557 109.269 0 150.869 41.6 41.6 109.269 41.6 150.869 0s41.6-109.312 0-150.869zM116.224 238.72c-45.653-45.653-108.331-251.904-115.328-275.243-2.261-7.509-0.171-15.659 5.333-21.205 4.096-4.096 9.515-6.272 15.104-6.272 2.048 0 4.096 0.299 6.144 0.896 23.339 6.997 229.589 69.675 275.243 115.328 51.413 51.413 51.413 135.083 0 186.496-51.456 51.413-135.083 51.371-186.496 0z" /> <glyph unicode="" glyph-name="icon-user_guide" d="M182.318 221.526v738.474h-49.18c-72.456 0-131.404-58.948-131.404-131.404v-648.796c30.102 25.97 69.248 41.728 112.030 41.728h68.554zM795.95 450.1c6.458 0 12.862-0.236 19.214-0.66v510.56h-572.956v-738.474h273.492c26.68 130.278 142.202 228.574 280.25 228.574zM423.968 783.658h200.44v-59.89h-200.44zM356.262 653.638h335.852v-59.89h-335.852zM549.012 19.818h-395.51v59.89h369.092c-8.198 26.514-12.636 54.66-12.688 83.818h-396.142c-62.73 0-113.764-51.034-113.764-113.762 0-62.73 51.034-113.764 113.764-113.764h509.716c-29.982 22.73-55.356 51.222-74.468 83.818zM795.95 392.1c-125.748 0-228.052-102.302-228.052-228.050s102.304-228.050 228.052-228.050c125.746 0 228.050 102.304 228.050 228.050 0 125.748-102.304 228.050-228.050 228.050zM795.928 300.576c16.818 0 29.272-13.746 30-30 0.726-16.202-14.308-30-30-30-16.818 0-29.272 13.746-30 30-0.726 16.202 14.308 30 30 30zM825.996 47.13h-60v153.598h60z" /> +<glyph unicode="" glyph-name="icon-autoMap" horiz-adv-x="904" d="M865.588 451.765c0-65.786-53.332-119.118-119.118-119.118s-119.118 53.332-119.118 119.118c0 65.786 53.332 119.118 119.118 119.118s119.118-53.332 119.118-119.118zM19.853 940.147h230.294v-230.294h-230.294zM19.853 193.676h230.294v-230.294h-230.294zM19.853 566.912h230.294v-230.294h-230.294zM885.441 451.765c0 76.628-62.343 138.971-138.971 138.971s-138.971-62.343-138.971-138.971c0-76.628 62.343-138.971 138.971-138.971s138.971 62.343 138.971 138.971zM746.471 352.5c-54.735 0-99.265 44.53-99.265 99.265s44.53 99.265 99.265 99.265c54.735 0 99.265-44.53 99.265-99.265s-44.53-99.265-99.265-99.265zM250.147 960h-230.294c-10.966 0-19.853-8.887-19.853-19.853v-230.294c0-10.966 8.887-19.853 19.853-19.853h230.294c10.966 0 19.853 8.887 19.853 19.853v230.294c0 10.966-8.887 19.853-19.853 19.853zM230.294 729.706h-190.588v190.588h190.588v-190.588zM250.147 213.529h-230.294c-10.966 0-19.853-8.887-19.853-19.853v-230.294c0-10.966 8.887-19.853 19.853-19.853h230.294c10.966 0 19.853 8.887 19.853 19.853v230.294c0 10.966-8.887 19.853-19.853 19.853zM230.294-16.765h-190.588v190.588h190.588v-190.588zM250.147 586.765h-230.294c-10.966 0-19.853-8.887-19.853-19.853v-230.294c0-10.966 8.887-19.853 19.853-19.853h230.294c10.966 0 19.853 8.887 19.853 19.853v230.294c0 10.966-8.887 19.853-19.853 19.853zM230.294 356.471h-190.588v190.588h190.588v-190.588zM329.559 431.912h138.971l-31.765-23.824c-8.771-6.576-10.547-19.023-3.971-27.794 3.901-5.196 9.864-7.941 15.898-7.941 4.149 0 8.321 1.295 11.896 3.971l79.412 59.559c0.101 0.070 7.941 5.956 7.941 15.882 0 6.126-3.017 12.214-7.941 15.882l-79.412 59.559c-8.771 6.584-21.218 4.8-27.794-3.971s-4.8-21.218 3.971-27.794l31.765-23.824h-138.971c-10.966 0-19.853-8.887-19.853-19.853s8.887-19.853 19.853-19.853zM329.559 805.147h168.463l138.971-138.971h-49.345c-10.966 0-19.853-8.887-19.853-19.853s8.887-19.853 19.853-19.853h99.265c12.726 0 22.621 13.215 19.062 25.413l-27.794 95.294c-3.071 10.524-14.099 16.58-24.622 13.502-10.524-3.071-16.565-14.091-13.494-24.622l6.91-23.699-126.687 126.687c-3.722 3.715-8.771 5.809-14.037 5.809h-176.691c-10.966 0-19.853-8.887-19.853-19.853s8.887-19.853 19.853-19.853zM686.912 273.088h-99.265c-10.966 0-19.853-8.887-19.853-19.853s8.887-19.853 19.853-19.853h49.345l-138.971-138.971h-168.463c-10.966 0-19.853-8.887-19.853-19.853s8.887-19.853 19.853-19.853h176.691c5.266 0 10.314 2.094 14.037 5.816l126.687 126.687-6.918-23.707c-3.071-10.531 2.978-21.551 13.502-24.615 1.861-0.543 3.73-0.807 5.568-0.807 8.6 0 16.518 5.638 19.054 14.3 0 0 27.662 94.86 27.794 95.294 3.552 12.206-6.39 25.413-19.062 25.413v0z" /> +<glyph unicode="" glyph-name="icon-required-star" d="M996.821 593.749l-314.795 48.085-141.099 300.544c-10.539 22.443-47.36 22.443-57.899 0l-141.056-300.544-314.795-48.085c-25.856-3.968-36.181-35.413-18.048-53.973l228.693-234.411-54.059-331.392c-4.309-26.325 23.808-46.080 47.061-33.152l281.173 155.392 281.173-155.435c23.040-12.8 51.413 6.571 47.061 33.152l-54.059 331.392 228.693 234.411c18.133 18.603 7.765 50.048-18.048 54.016v0z" /> +<glyph unicode="" glyph-name="icon-source" horiz-adv-x="1365" d="M451.884 287.277c-0.917 6.337-4.31 12.047-9.433 15.881l-259.965 194.408 259.965 194.408c5.123 3.834 8.516 9.544 9.433 15.881 0.91 6.337-0.724 12.771-4.565 17.908l-41.298 55.22c-7.992 10.674-23.107 12.86-33.782 4.868l-359.655-268.957c-6.089-4.551-9.681-11.716-9.681-19.328s3.593-14.777 9.681-19.328l359.655-268.957c4.33-3.248 9.406-4.806 14.433-4.806 7.351 0 14.612 3.337 19.349 9.675l41.298 55.22c3.834 5.137 5.475 11.571 4.565 17.908zM1349.929 516.894l-359.641 268.957c-10.674 7.985-25.79 5.799-33.775-4.868l-41.298-55.22c-3.834-5.13-5.475-11.571-4.565-17.908 0.917-6.33 4.303-12.047 9.433-15.881l259.958-194.408-259.958-194.408c-5.13-3.834-8.516-9.55-9.433-15.881-0.91-6.337 0.724-12.778 4.565-17.908l41.298-55.22c4.744-6.337 11.998-9.675 19.349-9.675 5.027 0 10.095 1.565 14.433 4.806l359.641 268.957c6.089 4.551 9.681 11.716 9.681 19.328s-3.6 14.777-9.688 19.328zM912.043 929.411l-63.516 26.858c-5.889 2.496-12.536 2.538-18.473 0.138-5.93-2.407-10.668-7.068-13.157-12.964l-379.259-897.010c-5.192-12.274 0.552-26.438 12.833-31.63l63.516-26.858c3-1.276 6.199-1.903 9.399-1.903 3.082 0 6.165 0.593 9.075 1.772 5.93 2.407 10.661 7.068 13.157 12.964l379.259 897.010c5.186 12.274-0.559 26.431-12.833 31.623z" /> +<glyph unicode="" glyph-name="icon-add-circle" d="M512 960c-282.785 0-512-229.215-512-512s229.215-512 512-512c282.785 0 512 229.249 512 512s-229.215 512-512 512zM512 0c-247.425 0-448 200.575-448 448s200.575 448 448 448c247.425 0 448-200.575 448-448s-200.575-448-448-448zM704 480h-160v160c0 17.664-14.336 32-32 32s-32-14.336-32-32v-160h-160c-17.664 0-32-14.336-32-32s14.336-32 32-32h160v-160c0-17.664 14.336-32 32-32s32 14.336 32 32v160h160c17.664 0 32 14.336 32 32s-14.336 32-32 32z" /> +<glyph unicode="" glyph-name="icon-function-attribute" horiz-adv-x="1229" d="M1166.428 461.798c3.568 8.632 1.58 18.556-5.028 25.151l-415.328 415.328c-9.167 8.851-23.772 8.598-32.629-0.569-8.633-8.944-8.633-23.117 0-32.058l375.967-375.967h-1005.695c-12.742-0.002-23.075-10.331-23.075-23.077s10.331-23.075 23.075-23.075h1005.695l-375.918-375.918c-9.167-8.851-9.42-23.46-0.569-32.629 8.851-9.167 23.46-9.418 32.629-0.569 0.192 0.188 0.38 0.373 0.569 0.569l415.328 415.328c2.132 2.144 3.826 4.686 4.981 7.481zM729.778 32.212c-12.742-0.026-23.094 10.289-23.114 23.035-0.012 6.144 2.431 12.036 6.778 16.376l399.041 398.99-399.041 398.992c-8.851 9.167-8.598 23.772 0.569 32.629 8.944 8.633 23.117 8.633 32.058 0l415.328-415.328c9.010-9.012 9.010-23.615 0-32.629l-415.328-415.328c-4.321-4.312-10.178-6.736-16.29-6.736zM1145.107 447.538h-1061.393c-12.742 0-23.075 10.331-23.075 23.072s10.331 23.075 23.075 23.075h1061.396c12.742 0 23.075-10.331 23.075-23.075s-10.331-23.072-23.077-23.072z" /> +<glyph unicode="" glyph-name="icon-custom-attribute" d="M35.552 421.088c-19.808 0-35.552 16.256-35.552 36.064s15.744 35.552 35.552 35.552h431.2v431.232c0.032 19.808 16.288 36.064 36.096 36.064s35.552-16.256 35.552-36.064v-431.232h431.2c19.808 0 36.064-15.744 36.064-35.552s-16.256-36.064-36.064-36.064h-431.2v-431.232c0-19.808-15.744-36.064-35.552-36.064s-36.064 16.256-36.064 36.064v431.232h-431.232z" /> <glyph unicode="" glyph-name="icon-add" d="M512 960c-282.785 0-512-229.215-512-512s229.215-512 512-512c282.785 0 512 229.249 512 512s-229.215 512-512 512zM512 0c-247.425 0-448 200.575-448 448s200.575 448 448 448c247.425 0 448-200.575 448-448s-200.575-448-448-448zM704 480h-160v160c0 17.664-14.336 32-32 32s-32-14.336-32-32v-160h-160c-17.664 0-32-14.336-32-32s14.336-32 32-32h160v-160c0-17.664 14.336-32 32-32s32 14.336 32 32v160h160c17.664 0 32 14.336 32 32s-14.336 32-32 32z" /> <glyph unicode="" glyph-name="icon-archive-sm" d="M943.405 684.258h-864.783c-10.653 0-19.867-3.887-27.644-11.668-7.781-7.777-11.668-16.991-11.668-27.637v-589.626c0-10.644 3.887-19.863 11.668-27.637 7.777-7.781 16.991-11.677 27.644-11.677h864.783c10.647 0 19.854 3.896 27.637 11.677 7.775 7.773 11.662 16.991 11.662 27.637v589.626c0 10.653-3.872 19.858-11.662 27.637-7.775 7.781-16.991 11.668-27.637 11.668zM617.255 499.387c-7.773-7.779-16.991-11.668-27.637-11.668h-157.233c-10.64 0-19.854 3.892-27.637 11.668-7.777 7.781-11.668 16.991-11.668 27.644 0 10.644 3.892 19.858 11.668 27.637 7.781 7.781 16.995 11.673 27.637 11.673h157.249c10.638 0 19.85-3.892 27.637-11.673 7.775-7.777 11.662-16.991 11.662-27.637 0-10.651-3.896-19.863-11.677-27.644zM1010.357 947.749c-7.783 7.781-16.991 11.668-27.639 11.668h-943.409c-10.644 0-19.858-3.887-27.637-11.668-7.779-7.777-11.671-16.991-11.671-27.637v-157.233c0-10.644 3.892-19.854 11.673-27.637 7.779-7.781 16.991-11.668 27.637-11.668h943.394c10.644 0 19.863 3.887 27.652 11.668 7.773 7.781 11.66 16.991 11.66 27.637v157.233c0 10.653-3.887 19.86-11.66 27.637z" /> <glyph unicode="" glyph-name="icon-btn-card-config" d="M971.283 561.778h-95.801c-15.398 0-28.084 8.476-33.982 22.699s-2.901 29.203 7.964 40.088l67.736 67.717c9.956 9.956 15.436 23.211 15.436 37.281 0 14.089-5.48 27.326-15.436 37.3l-86.338 86.338c-19.911 19.911-54.632 19.949-74.581 0l-67.717-67.717c-10.885-10.866-25.903-13.9-40.088-7.983-14.222 5.897-22.699 18.584-22.699 33.982v95.801c0 29.070-23.647 52.717-52.717 52.717h-122.121c-29.070 0-52.717-23.647-52.717-52.717v-95.801c0-15.398-8.476-28.084-22.699-33.982-14.184-5.935-29.203-2.882-40.088 7.983l-67.717 67.717c-19.949 19.949-54.67 19.911-74.581 0l-86.338-86.338c-9.956-9.956-15.436-23.211-15.436-37.3 0-14.071 5.48-27.307 15.436-37.281l67.736-67.717c10.866-10.885 13.843-25.865 7.964-40.088s-18.584-22.699-33.982-22.699h-95.801c-29.070 0-52.717-23.647-52.717-52.717v-122.103c0-29.089 23.647-52.736 52.717-52.736h95.801c15.398 0 28.084-8.476 33.982-22.699s2.901-29.203-7.964-40.088l-67.736-67.717c-9.956-9.956-15.436-23.211-15.436-37.281 0-14.089 5.48-27.326 15.436-37.3l86.338-86.338c19.93-19.93 54.632-19.968 74.581 0l67.717 67.736c10.885 10.866 25.847 13.862 40.088 7.964 14.222-5.897 22.699-18.584 22.699-33.982v-95.801c0-29.070 23.647-52.717 52.717-52.717h122.103c29.070 0 52.717 23.647 52.717 52.717v95.801c0 15.398 8.476 28.084 22.699 33.982 14.241 5.916 29.203 2.901 40.088-7.964l67.717-67.736c19.949-19.949 54.67-19.911 74.581 0l86.338 86.338c9.956 9.956 15.436 23.211 15.436 37.3 0 14.071-5.48 27.307-15.436 37.281l-67.736 67.717c-10.866 10.885-13.843 25.865-7.964 40.088s18.603 22.699 34.001 22.699h95.801c29.070 0 52.717 23.647 52.717 52.717v122.121c0 29.070-23.647 52.717-52.717 52.717zM986.074 386.939c0-8.154-6.637-14.791-14.791-14.791h-95.801c-30.796 0-57.249-17.673-69.025-46.118-11.795-28.444-5.594-59.657 16.194-81.427l67.736-67.717c5.784-5.784 5.784-15.17 0-20.935l-86.338-86.338c-5.765-5.765-15.151-5.803-20.935 0l-67.717 67.736c-21.788 21.788-52.983 27.951-81.427 16.194-28.444-11.776-46.118-38.229-46.118-69.025v-95.801c0-8.154-6.637-14.791-14.791-14.791h-122.121c-8.154 0-14.791 6.637-14.791 14.791v95.801c0 30.796-17.673 57.249-46.118 69.025-9.538 3.963-19.361 5.897-29.070 5.897-19.228 0-37.869-7.585-52.357-22.073l-67.717-67.736c-5.803-5.803-15.189-5.765-20.935 0l-86.338 86.338c-5.784 5.784-5.784 15.17 0 20.935l67.736 67.717c21.769 21.769 27.989 52.983 16.194 81.427-11.776 28.425-38.229 46.099-69.025 46.099h-95.801c-8.154 0-14.791 6.637-14.791 14.791v122.121c0 8.154 6.637 14.791 14.791 14.791h95.801c30.796 0 57.249 17.673 69.025 46.118 11.795 28.444 5.594 59.657-16.194 81.427l-67.736 67.717c-5.784 5.784-5.784 15.17 0 20.935l86.338 86.338c5.765 5.784 15.151 5.784 20.935 0l67.717-67.717c21.751-21.751 52.945-27.989 81.427-16.194 28.444 11.757 46.118 38.21 46.118 69.006v95.801c0 8.154 6.637 14.791 14.791 14.791h122.103c8.173 0 14.81-6.637 14.81-14.791v-95.801c0-30.796 17.673-57.249 46.118-69.025 28.482-11.795 59.657-5.575 81.427 16.194l67.717 67.717c5.803 5.784 15.189 5.784 20.935 0l86.338-86.338c5.784-5.784 5.784-15.17 0-20.935l-67.736-67.717c-21.769-21.769-27.989-52.983-16.194-81.427 11.776-28.444 38.229-46.118 69.025-46.118h95.801c8.154 0.019 14.791-6.618 14.791-14.772v-122.121zM512 618.667c-94.113 0-170.667-76.553-170.667-170.667s76.553-170.667 170.667-170.667c94.113 0 170.667 76.553 170.667 170.667s-76.553 170.667-170.667 170.667zM512 315.259c-73.178 0-132.741 59.563-132.741 132.741s59.563 132.741 132.741 132.741c73.178 0 132.741-59.563 132.741-132.741s-59.563-132.741-132.741-132.741z" /> diff --git a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.ttf b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.ttf Binary files differindex ea6de579c..48987f472 100755 --- a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.ttf +++ b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.ttf diff --git a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.woff b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.woff Binary files differindex 5cb900050..6bea7e8eb 100755 --- a/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.woff +++ b/cds-ui/designer-client/src/assets/icomoon/fonts/icomoon.woff diff --git a/cds-ui/designer-client/src/assets/icomoon/style.css b/cds-ui/designer-client/src/assets/icomoon/style.css index 130115635..899647321 100755 --- a/cds-ui/designer-client/src/assets/icomoon/style.css +++ b/cds-ui/designer-client/src/assets/icomoon/style.css @@ -1,10 +1,10 @@ @font-face { font-family: 'icomoon'; - src: url('fonts/icomoon.eot?pqs8r8'); - src: url('fonts/icomoon.eot?pqs8r8#iefix') format('embedded-opentype'), - url('fonts/icomoon.ttf?pqs8r8') format('truetype'), - url('fonts/icomoon.woff?pqs8r8') format('woff'), - url('fonts/icomoon.svg?pqs8r8#icomoon') format('svg'); + src: url('fonts/icomoon.eot?h11si2'); + src: url('fonts/icomoon.eot?h11si2#iefix') format('embedded-opentype'), + url('fonts/icomoon.ttf?h11si2') format('truetype'), + url('fonts/icomoon.woff?h11si2') format('woff'), + url('fonts/icomoon.svg?h11si2#icomoon') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -35,6 +35,27 @@ -moz-osx-font-smoothing: grayscale; } +.icon-function-attribute:before { + content: "\e90e"; +} +.icon-custom-attribute:before { + content: "\e90f"; + color: #1b3e6f; +} +.icon-add-circle:before { + content: "\e90d"; + color: #103d73; +} +.icon-required-star:before { + content: "\e90b"; + color: #ff6469; +} +.icon-source:before { + content: "\e90c"; +} +.icon-autoMap:before { + content: "\e90a"; +} .icon-get_started:before { content: "\e908"; } diff --git a/cds-ui/designer-client/src/assets/img/trash-solid.svg b/cds-ui/designer-client/src/assets/img/trash-solid.svg new file mode 100644 index 000000000..e40a23d12 --- /dev/null +++ b/cds-ui/designer-client/src/assets/img/trash-solid.svg @@ -0,0 +1 @@ +<svg aria-hidden="true" focusable="false" data-prefix="fas" data-icon="trash" class="svg-inline--fa fa-trash fa-w-14" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><path fill="currentColor" d="M432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16zM53.2 467a48 48 0 0 0 47.9 45h245.8a48 48 0 0 0 47.9-45L416 128H32z"></path></svg>
\ No newline at end of file diff --git a/cds-ui/designer-client/src/styles.css b/cds-ui/designer-client/src/styles.css index 1464cc295..b215dd46a 100644 --- a/cds-ui/designer-client/src/styles.css +++ b/cds-ui/designer-client/src/styles.css @@ -18,6 +18,9 @@ body{ transition: 0.3s !important; } /*Bootstrap*/ +.custom-control-input:checked ~ .custom-control-label::before{ + border-color: transparent !important; +} .btn-outline-danger{ background: #fff !important; border: solid 1px #ECEDF2 !important; @@ -30,6 +33,28 @@ body{ border: solid 1px #C3CDDB !important; border-radius: 0 !important; } +.reuiredInput .custom-control-label::before{ + width: 18px !important; + height: 18px !important; + border-radius: 50% !important; +} + +.reuiredInput .custom-control-label::after{ + content: "_"; + color: #C4CEDB !important; + width: 18px !important; + height: 18px !important; + line-height: 6px; + text-align: center; +} +.reuiredInput .custom-control-input:checked ~ .custom-control-label::after{ + top: 4px !important; + left: -24px !important; + content: ""; +} +.reuiredInput .custom-control-input:checked ~ .custom-control-label::before{ + background: #66BB00 !important; +} .custom-control-input:checked ~ .custom-control-label::before{ background: #1B3E6F !important; } @@ -974,6 +999,11 @@ height: 40px; text-indent: unset; text-align: center; } +.helpMenu li:hover, +.helpMenu li:hover i, +.helpMenu li:hover p{ + cursor: pointer; +} .helpMenu li:not(:last-child){ margin-bottom: 9px; } @@ -990,7 +1020,7 @@ height: 40px; padding: 6px; } .helpMenu .dropdown-content a{ - padding: 0 12px; + padding: 5px 12px !important; text-align: left; text-indent: 0; font-size: 14px; @@ -1049,7 +1079,7 @@ height: 40px; -webkit-box-shadow: 0 4px 10px 0 #eef0f5; box-shadow: 0 4px 10px 0 #eef0f5; position: relative; - z-index: 8; + z-index: 300; /* position: fixed; width: calc(100% - 50px); */ } @@ -1627,6 +1657,7 @@ ul.package-contributers{ margin-bottom: 26px; width: 100px; height: 30px; + line-height: 15px; background: #1B3E6F; color: #fff; font-size: 12px; @@ -1920,6 +1951,7 @@ ul.package-contributers{ color: #1B3E6F; content: attr(data-tooltip); font-size: 12px; + font-weight: bold !important; line-height: 1.2; border-radius: 3px; } @@ -2076,22 +2108,26 @@ ul.package-contributers{ color:#1B3E6F; background-color: #C3CDDB !important; border: solid 1px #C3CDDB; - border-radius: 3px !important; - border-top-left-radius: 0 !important; + border-radius: 1px !important; + /* border-top-left-radius: 0 !important; */ font-size: 12px; opacity: 1.0 !important; } -.bs-tooltip-auto[x-placement^=top] .arrow::before, .bs-tooltip-top .arrow::before { +.bs-tooltip-auto[x-placement^=top] .arrow::before, +.bs-tooltip-top .arrow::before { border-top-color: #C3CDDB !important; } -.bs-tooltip-auto[x-placement^=right] .arrow::before, .bs-tooltip-right .arrow::before { +.bs-tooltip-auto[x-placement^=right] .arrow::before, +.bs-tooltip-right .arrow::before { border-right-color: #C3CDDB !important; } -.bs-tooltip-auto[x-placement^=bottom] .arrow::before, .bs-tooltip-bottom .arrow::before { +.bs-tooltip-auto[x-placement^=bottom] .arrow::before, +.bs-tooltip-bottom .arrow::before { border-bottom-color: #C3CDDB !important; } -.bs-tooltip-auto[x-placement^=left] .arrow::before, .bs-tooltip-left .arrow::before { +.bs-tooltip-auto[x-placement^=left] .arrow::before, +.bs-tooltip-left .arrow::before { border-left-color: #C3CDDB !important; } @@ -2509,9 +2545,11 @@ animation: glowing 1500ms infinite; } -.action-button.delete i{ +/* .action-button.delete i{ color: #BABBC3; -} +} */ +.action-button.delete, +.action-button.delete i, .action-button.delete:hover, .action-button.delete:hover .icon-delete-sm{ color: #FF6469 !important; @@ -2890,7 +2928,7 @@ animation: glowing 1500ms infinite; top: 13px; } .ace_scroller{ - overflow: auto !important; + /* overflow: auto !important; */ } .ace_print-margin{ left: 100% !important; @@ -3001,6 +3039,36 @@ padding: 0 10px 0 0; .mapping-source-load.hover-disable:hover i{ background: transparent; } +.mapping-editBar{ + margin-bottom: 1rem; +} +.mapping-editBar .custom-checkbox, +.mapping-editBar .btn{ + margin: 0 4px !important; + padding: 9px !important; + width: 36px; + height: 36px; + background: #F4F9FE; + border-radius: 50% !important; + text-align: center; + line-height: 14px; +} +.mapping-editBar .custom-checkbox{ + margin-left: 0 !important; +} +.mapping-editBar .custom-control-label{ + top: -2px; + left: 16px; +} +.mapping-editBar .btn i{ + color: #1B3E6F; + font-size: 18px; + opacity: .5; +} +.mapping-editBar .custom-checkbox:hover, +.mapping-editBar .btn:hover i{ + opacity: 1; +} .template-mapping-list{ background: #F4F9FE; border: 1px solid #E9F3FF; @@ -3013,6 +3081,7 @@ padding: 0 10px 0 0; } .template-mapping-list:hover, .template-mapping-list.active { + cursor: pointer; /* background: #1B3E6F; */ text-decoration: none; /* color: #fff !important; */ @@ -3164,8 +3233,8 @@ margin-right: 5px; font-size: 13px; } .template-mapping-action .btn-primary{ - background:#5DBDBA !important ; - border-color:#5DBDBA !important ; + background:#66BB00 !important ; + border-color:#66BB00 !important ; color: #fff !important ; } .template-mapping-action .btn-outline-secondary{ @@ -3366,10 +3435,10 @@ table.dataTable.no-footer{ overflow: auto; padding: 20px; padding-top: 9px; - background: #fff; - color: #1B3E6F; + background: #1B3E6F; + color: #fff; border-top: solid 6px #1273EB; - box-shadow: 0 2px 6px 0 rgba(47, 83, 151, 0.18) !important; + box-shadow: 0 2px 13px 6px rgba(47, 83, 151, .17) !important; border-radius: 3px !important; /* border-top-right-radius: 0 !important; border-bottom-right-radius: 0 !important; */ @@ -3413,14 +3482,14 @@ for simplicity border: 0; background: none; font-weight: normal; - color: #1273EB; + color: #E0E8F2; font-size: 12px; } /*Wizard Content*/ .mat-menu-panel{ - box-shadow: 0 2px 6px 0 rgba(47, 83, 151, 0.18) !important; + box-shadow: 0 2px 13px 6px rgba(47, 83, 151, .17) !important; border-radius: 3px !important; - border-bottom: solid 3px #1273EB; + border-top: solid 3px #1273EB; } .mat-menu-panel::after { content: ''; @@ -3430,13 +3499,13 @@ for simplicity position: absolute; border-left: 8px solid transparent; border-right: 8px solid transparent; - border-bottom: 8px solid #fff; + border-bottom: 8px solid #1273EB; left: 9px; top: -8px; } .mat-card{ - background: #fff !important; - color: #1B3E6F !important; + background: #1B3E6F !important; + color: #fff !important; font-family: inherit !important; border-radius: 0 !important; } @@ -3450,7 +3519,7 @@ for simplicity font-size: 16px !important; } .mat-icon-button[disabled]{ - color: rgba(27, 62, 111, .5) !important; + color: rgba(224, 232, 242, .5) !important; } diff --git a/cds-ui/pom.xml b/cds-ui/pom.xml index abf9348e1..cf70f5e88 100644 --- a/cds-ui/pom.xml +++ b/cds-ui/pom.xml @@ -23,18 +23,16 @@ limitations under the License. <modelVersion>4.0.0</modelVersion> <parent> - <groupId>org.onap.ccsdk.parent</groupId> - <artifactId>spring-boot-starter-parent</artifactId> - <version>2.0.1-SNAPSHOT</version> - <relativePath/> + <groupId>org.onap.ccsdk.cds</groupId> + <artifactId>cds-aggregator</artifactId> + <version>1.1.0-SNAPSHOT</version> + <relativePath>..</relativePath> </parent> - <groupId>org.onap.ccsdk.cds</groupId> - <artifactId>ui</artifactId> - <version>1.0.0-SNAPSHOT</version> + <artifactId>cds-ui</artifactId> <packaging>pom</packaging> - <name>CDS UI Parent</name> + <name>UI Parent</name> <description>Creates Controller Design Studio UI Docker container</description> <modules> @@ -45,11 +43,6 @@ limitations under the License. </modules> <properties> - <image.name>onap/ccsdk-cds-ui</image.name> - <ccsdk.project.version>${project.version}</ccsdk.project.version> - <ccsdk.distribution.version>${project.version}</ccsdk.distribution.version> - <ccsdk.build.timestamp>${maven.build.timestamp}</ccsdk.build.timestamp> - <maven.build.timestamp.format>yyyyMMdd'T'HHmmss'Z'</maven.build.timestamp.format> - <docker.verbose>true</docker.verbose> + <npm.executable>npm</npm.executable> </properties> </project> diff --git a/cds-ui/server/pom.xml b/cds-ui/server/pom.xml index 11bfd9fd7..c485cb27a 100644 --- a/cds-ui/server/pom.xml +++ b/cds-ui/server/pom.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8"?> -<!-- +<!-- ============LICENSE_START========================================== =================================================================== Copyright (C) 2018-19 IBM Intellectual Property. All rights reserved. @@ -24,23 +24,18 @@ limitations under the License. <parent> <groupId>org.onap.ccsdk.cds</groupId> - <artifactId>ui</artifactId> - <version>1.0.0-SNAPSHOT</version> + <artifactId>cds-ui</artifactId> + <version>1.1.0-SNAPSHOT</version> <relativePath>..</relativePath> </parent> - <artifactId>ui-server</artifactId> - <version>1.0.0-SNAPSHOT</version> + <artifactId>cds-ui-server</artifactId> <packaging>pom</packaging> - <name>CDS UI Server</name> + <name>UI Server</name> <properties> - <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> - <npm.executable>npm</npm.executable> - <onap.nexus.url>https://nexus.onap.org</onap.nexus.url> <image.name>onap/ccsdk-cds-ui-server</image.name> - <docker.push.phase>deploy</docker.push.phase> </properties> <build> @@ -59,9 +54,9 @@ limitations under the License. <configuration> <artifactItems> <artifactItem> - <groupId>org.onap.ccsdk.cds.blueprintsprocessor</groupId> + <groupId>org.onap.ccsdk.cds.blueprintsprocessor.modules</groupId> <artifactId>blueprint-proto</artifactId> - <version>${project.version}</version> + <version>${ccsdk.cds.version}</version> <type>jar</type> <overWrite>true</overWrite> <outputDirectory>${project.build.directory}/generated/proto-definition/proto</outputDirectory> @@ -148,7 +143,7 @@ limitations under the License. <plugin> <groupId>io.fabric8</groupId> <artifactId>docker-maven-plugin</artifactId> - <version>0.26.1</version> + <version>0.34.0</version> <inherited>false</inherited> <configuration> <images> @@ -165,18 +160,12 @@ limitations under the License. </build> </image> </images> - <verbose>true</verbose> + <verbose>${docker.verbose}</verbose> + <skipPush>${docker.skip.push}</skipPush> </configuration> <executions> <execution> - <id>generate-images</id> - <phase>package</phase> - <goals> - <goal>build</goal> - </goals> - </execution> - <execution> - <id>push-images</id> + <id>build-push-images</id> <phase>${docker.push.phase}</phase> <goals> <goal>build</goal> diff --git a/cds-ui/server/src/controllers/blueprint-rest.controller.ts b/cds-ui/server/src/controllers/blueprint-rest.controller.ts index 870f9793f..91d7e66e3 100644 --- a/cds-ui/server/src/controllers/blueprint-rest.controller.ts +++ b/cds-ui/server/src/controllers/blueprint-rest.controller.ts @@ -307,7 +307,7 @@ export class BlueprintRestController { if (appConfig.action.grpcEnabled) return this.uploadFileToBlueprintProcessorGrpc(file, 'PUBLISH', response); else - return this.uploadFileToBlueprintProcessor(file, '/execution-service/upload/', response); + return this.uploadFileToBlueprintProcessor(file, '/blueprint-model/publish', response); }, err => { reject(err); }); |