From: kumaran.m Date: Fri, 1 May 2020 14:18:54 +0000 (+0530) Subject: Initial Commit - NG UI X-Git-Tag: v7.1.3^0 X-Git-Url: https://osm.etsi.org/gitweb/?a=commitdiff_plain;h=3b4814aa2d3dec621dadb52f058ba95a3dc3a86a;p=osm%2FNG-UI.git Initial Commit - NG UI * Roboto and font-awesome fonts are added in package.json * Replace Nginx alpine varient to stable * Devops files are added * Docker file aligned as per community reviews * Enhancement - NS primitive, Azure inclusion and domain name * RWD changes Change-Id: If543efbf127964cbd8f4be4c5a67260c91407fd9 Signed-off-by: kumaran.m --- diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..3903e75 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ +# Copyright 2020 TATA ELXSI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +max_line_length = off +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9a88115 --- /dev/null +++ b/.gitignore @@ -0,0 +1,61 @@ +# Copyright 2020 TATA ELXSI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +# See http://help.github.com/ignore-files/ for more about ignoring files. + +# compiled output +/dist +/tmp +/out-tsc + +# dependencies +/node_modules +package-lock.json + +# profiling files +chrome-profiler-events.json +speed-measure-plugin.json + +# IDEs and editors +/.idea +.project +.classpath +.c9/ +*.launch +.settings/ +*.sublime-workspace + +# IDE - VSCode +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history/* + +# misc +/.sass-cache +/connect.lock +/coverage +/libpeerconnection.log +npm-debug.log +yarn-error.log +testem.log +/typings + +# System Files +.DS_Store +Thumbs.db diff --git a/Dockerfile b/Dockerfile index 54f0fd5..e7c221b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,3 @@ -# Copyright 2020 ETSI -# # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at @@ -13,7 +11,15 @@ # See the License for the specific language governing permissions and # limitations under the License. -FROM ubuntu:18.04 +# This Dockerfile is intented for devops and deb package generation +# +# Use Dockerfile.local for running osm/NBI in a docker container from source +# Use Dockerfile.fromdeb for running osm/NBI in a docker container from last stable package + + +FROM ubuntu:16.04 -RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get -y install git \ - make python3 debhelper python3-setuptools apt-utils +RUN apt-get update && apt-get -y install git make libcurl4-gnutls-dev \ + libgnutls-dev debhelper apt-utils dh-make + + \ No newline at end of file diff --git a/README.md b/README.md index 9f1db33..a2117a0 100644 --- a/README.md +++ b/README.md @@ -1,68 +1,124 @@ -# Project Title -One Paragraph of project description goes here +## Angular Based OSM NG UI +This project focuses on the implementation of a web GUI to interact with the Northbound API of OSM. + +The project is based on ([Angular](https://angular.io/)), a One framework for Mobile & desktop, app-design framework and development platform for creating efficient and sophisticated single-page web apps. + +## Table of Contents + +* [Community](#community) +* [Getting Started](#getting-started) +* [Prerequisites](#prerequisites) +* [Installation](#installation) +* [Running the application](#running-the-application) +* [Check the lint](#check-the-lint) +* [Supported Browsers](#supported-browsers) +* [Deployment](#deployment) +* [Built With](#built-with) +* [Contributing](#contributing) +* [Versioning](#versioning) +* [License](#license) + +## Community + +Contact [kumaran.m@tataelxsi.co.in](mailto:kumaran.m@tataelxsi.co.in), [rajesh.s@tataelxsi.co.in](mailto:rajesh.s@tataelxsi.co.in), [barath.r@tataelxsi.co.in](mailto:barath.r@tataelxsi.co.in) for architecture and design discussions, requests for help, features request and bug reports on NG UI. ## Getting Started -These instructions will get you a copy of the project up and running on your local machine for development and testing purposes. See deployment for notes on how to deploy the project on a live system. +Following instructions in the sections below will get you a copy of the project up and running on your local machine for development and testing purposes. See Deployment section for notes on how to deploy the project on a live system. ### Prerequisites -What things you need to install the software and how to install them +Angular Setup, Install, & Build Guide -``` -Give examples -``` +1. Install Node.js from [here](https://nodejs.org/en/download/) +To check if nodejs is installed on your system, type below command. This will help you see the version of nodejs currently installed on your system. +`node -version` +After downloading Node.js, the node package manager (npm) should automatically be installed. Test it out by doing: +`npm --version` +2. Install Angluar CLI. [More details](https://cli.angular.io/) Angular can be installed Globally (or) Locally, +Install Globally +`npm install -g @angular/cli` +Install Locally +`npm install @angular/cli` +After installation done you can check the version using below command. It will display version details of angular-cli +`ng version` -### Installing +We are done with the installation of Angular -A step by step series of examples that tell you how to get a development env running +### Installation -Say what the step will be +Clone the NG UI from the repository -``` -Give the example -``` +`git clone "https://osm.etsi.org/gerrit/osm/NG-UI"` -And repeat +Install the packages -``` -until finished -``` +`cd NG-UI` -End with an example of getting some data out of the system or using it for a little demo +`npm install` -## Running the tests +### Running the application -Explain how to run the automated tests for this system +The following instructions is for running NG UI locally for development purpose, +On the folder project + +Open `proxy.conf.json` + +Add the below code +```typescript +{ + "/osm/*": { + "target": "https://OSM-NBI-IP:9999", + "secure": false, + "logLevel": "info" + } +} ``` -Give an example -``` +To run the application give the below command + +`npm run proxy` +- To Run the NG-UI page Navigate to + +## Check the lint + +To check the typescript lint run the below command + +`npm run lint` + +## Supported Browsers + +- Edge (42.17134.1098.0) and IE 11 (Windows) +- Firefox (75.0)(Ubunutu) +- Firefox (75.0)(Windows) +- Chrome (81.0.4044.92) (Ubunutu) +- Chrome (81.0.4044.122) (Windows) ## Deployment -Add additional notes about how to deploy this on a live system +To deploy the NG UI use the [Dockerfile](Dockerfile) ## Built With -* [Python](www.python.org/) - The language used +* [Angular Frame work](https://angular.io/) - The languages used are Javascript, Typescript, HTML, and SCSS ## Contributing @@ -75,4 +131,3 @@ We use [SemVer](http://semver.org/) for versioning. For the versions available, ## License This project is licensed under the Apache2 License - see the [LICENSE.md](LICENSE) file for details - diff --git a/angular.json b/angular.json new file mode 100644 index 0000000..5420910 --- /dev/null +++ b/angular.json @@ -0,0 +1,145 @@ +{ + "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "version": 1, + "newProjectRoot": "projects", + "projects": { + "osm": { + "root": "", + "sourceRoot": "src", + "projectType": "application", + "prefix": "app", + "schematics": { + "@schematics/angular:component": { + "styleext": "scss" + } + }, + "architect": { + "build": { + "builder": "@angular-devkit/build-angular:browser", + "options": { + "outputPath": "dist/osm", + "index": "src/index.html", + "main": "src/main.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.app.json", + "assets": [ + "src/favicon.ico", + "src/assets" + ], + "styles": [ + "src/assets/scss/style.scss", + "node_modules/ol/ol.css", + "node_modules/@fortawesome/fontawesome-free/css/all.min.css" + ], + "scripts": [ + "src/assets/js/tar.js" + ], + "es5BrowserSupport": true + }, + "configurations": { + "production": { + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "optimization": true, + "outputHashing": "all", + "sourceMap": false, + "extractCss": true, + "namedChunks": false, + "aot": true, + "extractLicenses": true, + "vendorChunk": false, + "buildOptimizer": true, + "budgets": [ + { + "type": "initial", + "maximumWarning": "2mb", + "maximumError": "5mb" + } + ] + } + } + }, + "serve": { + "builder": "@angular-devkit/build-angular:dev-server", + "options": { + "browserTarget": "osm:build" + }, + "configurations": { + "production": { + "browserTarget": "osm:build:production" + } + } + }, + "extract-i18n": { + "builder": "@angular-devkit/build-angular:extract-i18n", + "options": { + "browserTarget": "osm:build" + } + }, + "test": { + "builder": "@angular-devkit/build-angular:karma", + "options": { + "main": "src/test.ts", + "polyfills": "src/polyfills.ts", + "tsConfig": "src/tsconfig.spec.json", + "karmaConfig": "src/karma.conf.js", + "styles": [ + "src/styles.css", + "node_modules/ol/ol.css" + ], + "scripts": [], + "assets": [ + "src/favicon.ico", + "src/assets" + ] + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": [ + "src/tsconfig.app.json", + "src/tsconfig.spec.json" + ], + "exclude": [ + "**/node_modules/**" + ] + } + } + } + }, + "osm-e2e": { + "root": "e2e/", + "projectType": "application", + "prefix": "", + "architect": { + "e2e": { + "builder": "@angular-devkit/build-angular:protractor", + "options": { + "protractorConfig": "e2e/protractor.conf.js", + "devServerTarget": "osm:serve" + }, + "configurations": { + "production": { + "devServerTarget": "osm:serve:production" + } + } + }, + "lint": { + "builder": "@angular-devkit/build-angular:tslint", + "options": { + "tsConfig": "e2e/tsconfig.e2e.json", + "exclude": [ + "**/node_modules/**" + ] + } + } + } + } + }, + "defaultProject": "osm" +} \ No newline at end of file diff --git a/browserslist b/browserslist new file mode 100644 index 0000000..412910d --- /dev/null +++ b/browserslist @@ -0,0 +1,28 @@ +# Copyright 2020 TATA ELXSI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + +# This file is currently used by autoprefixer to adjust CSS to support the below specified browsers +# For additional information regarding the format and rule options, please see: +# https://github.com/browserslist/browserslist#queries +# +# For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed + +> 0.5% +last 2 versions +Firefox ESR +not dead +not IE 9-11 \ No newline at end of file diff --git a/build-debpkg.sh b/build-debpkg.sh index 9a0960a..07a6d43 100755 --- a/build-debpkg.sh +++ b/build-debpkg.sh @@ -15,8 +15,8 @@ # under the License. -PKG_DIRECTORIES="lib static template" -PKG_FILES="LICENSE README.md" +PKG_DIRECTORIES="nginx src" +PKG_FILES="angular.json browserslist CONTRIBUTING.md package.json proxy.conf.json tsconfig.json tslint.json LICENSE README.md" MDG_NAME=ngui DEB_INSTALL=debian/osm-${MDG_NAME}.install export DEBEMAIL="gerardo.garciadeblas@telefonica.com" @@ -52,5 +52,3 @@ pushd $PKG_DIR dh_make -y --indep --createorig --a -c apache dpkg-buildpackage -uc -us -tc -rfakeroot popd - - diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 0000000..78643d4 --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,54 @@ +# Copyright 2020 TATA ELXSI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in), VIJAY NAG (vijaynag.bs@tataelxsi.co.in) + +FROM ubuntu:16.04 +# Installing node dependencies. +RUN apt-get update && apt-get install -y curl xz-utils gnupg2 \ + && apt-get update && apt-get install -y apt-transport-https \ + && curl -s https://deb.nodesource.com/gpgkey/nodesource.gpg.key | apt-key add - \ + && echo "deb https://deb.nodesource.com/node_10.x xenial main" | tee -a /etc/apt/sources.list.d/nodesource.list \ + && echo "deb-src https://deb.nodesource.com/node_10.x xenial main" | tee -a /etc/apt/sources.list.d/nodesource.list \ + && apt-get update && apt-get install -y nodejs \ + && apt-get install -y nginx + +# Preparing working environment. +RUN mkdir -p /usr/src/osm-angularapp +WORKDIR /usr/src/osm-angularapp + +# Installing dependencies. +COPY ./package.json /usr/src/osm-angularapp/ +RUN npm install + +# Copy osm-angularapp source into image. +COPY ./ /usr/src/osm-angularapp + +# Building app. +RUN npm run build + +# Removing nginx default page. +RUN rm -rf /usr/share/nginx/html/* + +# Copying nginx configuration. +COPY nginx/nginx.conf /etc/nginx/sites-available/default +RUN cp -r /usr/src/osm-angularapp/dist/osm/* /usr/share/nginx/html + +# Exposing ports. +EXPOSE 80 + +# Starting server. +CMD ["nginx", "-g", "daemon off;"] + diff --git a/nginx/nginx.conf b/nginx/nginx.conf new file mode 100644 index 0000000..d686603 --- /dev/null +++ b/nginx/nginx.conf @@ -0,0 +1,34 @@ +# Copyright 2020 TATA ELXSI +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or +# implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + +server { + listen 80; + server_name localhost; + root /usr/share/nginx/html; + index index.html index.htm; + client_max_body_size 15M; + + location /osm { + proxy_pass https://nbi:9999; + proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; + proxy_set_header Accept-Encoding ""; + } + + location / { + try_files $uri $uri/ /index.html; + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..fc1d601 --- /dev/null +++ b/package.json @@ -0,0 +1,91 @@ +{ + "name": "osm", + "version": "1.0.2", + "scripts": { + "ng": "ng", + "start": "ng serve", + "build": "ng build --prod --aot", + "test": "ng test", + "lint": "tslint --type-check --project tsconfig.json -c tslint.json", + "e2e": "ng e2e", + "proxy": "ng serve --proxy-config proxy.conf.json" + }, + "private": true, + "dependencies": { + "@akveo/ng2-completer": "^9.0.1", + "@angular/animations": "~9.1.0", + "@angular/cdk": "^7.3.7", + "@angular/common": "~9.1.0", + "@angular/compiler": "~9.1.0", + "@angular/core": "~9.1.0", + "@angular/flex-layout": "^9.0.0-beta.29", + "@angular/forms": "~9.1.0", + "@angular/localize": "^9.1.2", + "@angular/platform-browser": "~9.1.0", + "@angular/platform-browser-dynamic": "~9.1.0", + "@angular/router": "~9.1.0", + "@ctrl/ngx-codemirror": "^2.2.1", + "@fortawesome/fontawesome-free": "^5.13.0", + "@ng-bootstrap/ng-bootstrap": "^5.3.0", + "@ng-idle/core": "^8.0.0-beta.4", + "@ng-idle/keepalive": "^8.0.0-beta.4", + "@ng-select/ng-select": "^3.7.3", + "@ngx-translate/core": "^12.1.2", + "@ngx-translate/http-loader": "^4.0.0", + "@nomadreservations/ngx-codemirror": "^2.0.0", + "@types/d3": "^5.7.2", + "@types/js-yaml": "^3.12.1", + "@types/jsonpath": "^0.2.0", + "@types/ol": "^5.3.5", + "angular-notifier": "^6.0.1", + "bootstrap": "^4.4.1", + "chart.js": "^2.8.0", + "codemirror": "^5.51.0", + "core-js": "^2.5.4", + "d3": "^5.9.2", + "http-status-codes": "^1.3.2", + "js-untar": "^2.0.0", + "js-yaml": "^3.13.1", + "jsonpath": "^1.0.2", + "ng-sidebar": "^9.2.0", + "ng2-charts": "^3.0.0-beta.5", + "ng2-file-upload": "^1.3.0", + "ng2-smart-table": "^1.6.0", + "ol": "^5.3.3", + "pako": "^1.0.10", + "roboto-fontface": "^0.10.0", + "rxjs": "^6.5.4", + "rxjs-compat": "^6.5.5", + "stream": "0.0.2", + "text-encoding": "^0.7.0", + "tslib": "^1.11.1", + "web-animations-js": "^2.3.2", + "zone.js": "~0.10.3" + }, + "devDependencies": { + "@angular-devkit/build-angular": "~0.901.0", + "@angular/cli": "~9.1.0", + "@angular/compiler-cli": "~9.1.0", + "@angular/language-service": "~9.1.0", + "@types/jasmine": "~2.8.8", + "@types/jasminewd2": "~2.0.3", + "@types/jquery": "^3.3.31", + "@types/node": "^8.10.59", + "codelyzer": "^5.0.1", + "jasmine-core": "~2.99.1", + "jasmine-spec-reporter": "~4.2.1", + "karma": "~3.1.1", + "karma-chrome-launcher": "~2.2.0", + "karma-coverage-istanbul-reporter": "~2.0.1", + "karma-jasmine": "~1.1.2", + "karma-jasmine-html-reporter": "^0.2.2", + "ng2-completer": "^3.0.3", + "node-sass": "^4.14.1", + "protractor": "~5.4.0", + "ts-node": "~7.0.0", + "tslint": "^5.11.0", + "tslint-html-report": "^2.0.3", + "tslint-microsoft-contrib": "^6.1.1", + "typescript": "~3.8.3" + } +} diff --git a/proxy.conf.json b/proxy.conf.json new file mode 100644 index 0000000..e6a63c6 --- /dev/null +++ b/proxy.conf.json @@ -0,0 +1,7 @@ +{ + "/osm/*": { + "target": "https://nbi:9999", + "secure": false, + "logLevel": "info" + } +} \ No newline at end of file diff --git a/src/app/AppComponent.html b/src/app/AppComponent.html new file mode 100644 index 0000000..bee03c8 --- /dev/null +++ b/src/app/AppComponent.html @@ -0,0 +1,19 @@ + + + \ No newline at end of file diff --git a/src/app/AppComponent.scss b/src/app/AppComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/AppComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/AppComponent.ts b/src/app/AppComponent.ts new file mode 100644 index 0000000..04ad8d8 --- /dev/null +++ b/src/app/AppComponent.ts @@ -0,0 +1,123 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ + +/** + * @file App Components + */ +import { Component, HostListener, Injector } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { DEFAULT_INTERRUPTSOURCES, Idle } from '@ng-idle/core'; +import { AuthenticationService } from 'AuthenticationService'; +import { DeviceCheckService } from 'DeviceCheckService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes AppComponent.html as template url + */ +@Component({ + selector: 'app-root', + templateUrl: './AppComponent.html', + styleUrls: ['./AppComponent.scss'] +}) +/** Exporting a class @exports AppComponent */ +export class AppComponent { + /** To inject services @public */ + public injector: Injector; + /** Instance for modal service @public */ + public modalService: NgbModal; + /** Device Check service @private */ + private deviceCheckService: DeviceCheckService; + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + /** Handle idle time out service @private */ + private idle: Idle; + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.idle = this.injector.get(Idle); + this.authService = this.injector.get(AuthenticationService); + this.modalService = this.injector.get(NgbModal); + this.deviceCheckService = this.injector.get(DeviceCheckService); + this.handleIdle(); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.sharedService.fetchOSMVersion(); + } + + /** To handle handleIdle @public */ + public handleIdle(): void { + const idleTime: number = 1200; + const idleTimeOutWarning: number = 5; + // sets an idle timeout in seconds. + this.idle.setIdle(idleTime); + //sets a timeout period in seconds. after idleTime seconds of inactivity, the user will be considered timed out. + this.idle.setTimeout(idleTimeOutWarning); + // sets the default interrupts, in this case, things like clicks, scrolls, touches to the document + this.idle.setInterrupts(DEFAULT_INTERRUPTSOURCES); + this.idle.watch(true); + this.idleTimeOut(); + } + + /** Method to capture idle time out event @public */ + public idleTimeOut(): void { + this.idle.onTimeout.subscribe(() => { + this.idle.stop(); + if (localStorage.getItem('id_token') !== null) { + this.authService.logout(); + } + }); + } + + /** Handling Window's Storage Hostlistener @public */ + @HostListener('window:storage', ['$event']) + public handleLocalStorageEvent(evt: StorageEvent): void { + // On Token Change + if (evt.key === 'token_state' && !isNullOrUndefined(evt.key)) { + if (evt.oldValue !== evt.newValue) { + window.location.reload(); + } + } + // On Langauges Change + if (evt.key === 'languageCode' && !isNullOrUndefined(evt.key)) { + if (evt.oldValue !== evt.newValue) { + window.location.reload(); + } + } + } + + /** Handling Window's POP State Hostlistener @public */ + @HostListener('window:popstate', ['$event']) + public handleOnPOPState(evt: PopStateEvent): void { + this.modalService.dismissAll(); + } + + /** Handling Window's orientationchange Hostlistener @public */ + @HostListener('window:resize', ['$event']) + public onResize(event: Event): void { + this.deviceCheckService.checkDeviceType(); + } +} diff --git a/src/app/AppModule.ts b/src/app/AppModule.ts new file mode 100644 index 0000000..02fa736 --- /dev/null +++ b/src/app/AppModule.ts @@ -0,0 +1,231 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Instance Module file + */ +import { CommonModule, LOCATION_INITIALIZED } from '@angular/common'; +import { HTTP_INTERCEPTORS, HttpClient, HttpClientModule } from '@angular/common/http'; +import { APP_INITIALIZER, Injector, NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { BrowserModule } from '@angular/platform-browser'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { RouterModule } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateLoader, TranslateModule, TranslateService } from '@ngx-translate/core'; +import { TranslateHttpLoader } from '@ngx-translate/http-loader'; +import { NotifierModule, NotifierOptions } from 'angular-notifier'; +import { AuthInterceptorService } from 'AuthInterceptorService'; +import { HeaderComponent } from 'HeaderComponent'; +import { LayoutComponent } from 'LayoutComponent'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { SidebarComponent } from 'SidebarComponent'; +import { AppComponent } from './AppComponent'; + +import { appRoutes } from './approutes.module'; + +import { DataService } from 'DataService'; +import { ProjectService } from 'ProjectService'; +import { SharedService } from 'SharedService'; + +import { CodemirrorModule } from '@ctrl/ngx-codemirror'; +import { NgSelectModule } from '@ng-select/ng-select'; + +import { NgIdleKeepaliveModule } from '@ng-idle/keepalive'; +import { AuthenticationService } from 'AuthenticationService'; +import { AuthGuardService } from 'AuthGuardService'; +import { BreadcrumbComponent } from 'BreadCrumb'; +import { ComposePackages } from 'ComposePackages'; +import { ConfirmationTopologyComponent } from 'ConfirmationTopology'; +import { DeleteComponent } from 'DeleteComponent'; +import { DeviceCheckService } from 'DeviceCheckService'; +import { GoToTopDirective } from 'GoToTopDirective'; +import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate'; +import { InstantiateNsComponent } from 'InstantiateNs'; +import { LoaderModule } from 'LoaderModule'; +import { LoginComponent } from 'LoginComponent'; +import { NetsliceInstancesActionComponent } from 'NetsliceInstancesActionComponent'; +import { NetslicePackagesActionComponent } from 'NetslicePackagesAction'; +import { NSInstancesActionComponent } from 'NSInstancesActionComponent'; +import { NsPackagesActionComponent } from 'NsPackagesAction'; +import { PageNotFoundComponent } from 'PageNotFound'; +import { PDUInstancesActionComponent } from 'PDUInstancesActionComponent'; +import { ProjectLinkComponent } from 'ProjectLinkComponent'; +import { ProjectsActionComponent } from 'ProjectsAction'; +import { SDNControllerActionComponent } from 'SDNControllerActionComponent'; +import { ShowInfoComponent } from 'ShowInfoComponent'; +import { SwitchProjectComponent } from 'SwitchProjectComponent'; +import { UsersActionComponent } from 'UsersActionComponent'; +import { UserSettingsComponent } from 'UserSettingsComponent'; +import { VimAccountsActionComponent } from 'VimAccountsAction'; +import { VNFInstancesActionComponent } from 'VNFInstancesActionComponent'; +import { VNFLinkComponent } from 'VNFLinkComponent'; +import { VNFPackagesActionComponent } from 'VNFPackagesAction'; +import { WIMAccountsActionComponent } from 'WIMAccountsAction'; + +/** + * Custom angular notifier options + */ +const customNotifierOptions: NotifierOptions = { + position: { horizontal: { position: 'right' }, vertical: { position: 'top' } }, + behaviour: { autoHide: 3000, onClick: 'hide', onMouseover: 'pauseAutoHide' } +}; + +/** + * An NgModule is a class adorned with the @NgModule decorator function. + * @NgModule takes a metadata object that tells Angular how to compile and run module code. + */ +@NgModule({ + declarations: [ + AppComponent, + LayoutComponent, + HeaderComponent, + SidebarComponent, + LoginComponent, + PageNotFoundComponent, + VNFPackagesActionComponent, + NsPackagesActionComponent, + NSInstancesActionComponent, + VNFInstancesActionComponent, + VNFLinkComponent, + NetsliceInstancesActionComponent, + BreadcrumbComponent, + DeleteComponent, + NetslicePackagesActionComponent, + UsersActionComponent, + VimAccountsActionComponent, + ProjectsActionComponent, + ProjectLinkComponent, + UserSettingsComponent, + ShowInfoComponent, + InstantiateNetSliceTemplateComponent, + InstantiateNsComponent, + ConfirmationTopologyComponent, + ComposePackages, + WIMAccountsActionComponent, + PDUInstancesActionComponent, + SDNControllerActionComponent, + SwitchProjectComponent, + GoToTopDirective + ], + imports: [ + NotifierModule.withConfig(customNotifierOptions), + CommonModule, + BrowserModule, + BrowserAnimationsModule, + FormsModule, + ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), + Ng2SmartTableModule, + CodemirrorModule, + NgSelectModule, + HttpClientModule, + TranslateModule.forRoot({ + loader: { + provide: TranslateLoader, + useFactory: HttpLoaderFactory, + deps: [HttpClient] + } + }), + NgbModule, + NgSelectModule, + RouterModule.forRoot(appRoutes, { useHash: false }), + NgIdleKeepaliveModule.forRoot(), + LoaderModule + ], + providers: [ + { + provide: APP_INITIALIZER, + useFactory: appInitializerFactory, + deps: [TranslateService, Injector], + multi: true + }, + { + provide: HTTP_INTERCEPTORS, + useClass: AuthInterceptorService, + multi: true + }, + RestService, + AuthenticationService, + AuthGuardService, + DataService, + ProjectService, + SharedService, + DeviceCheckService + ], + bootstrap: [AppComponent], + entryComponents: [ + VNFPackagesActionComponent, + NsPackagesActionComponent, + NSInstancesActionComponent, + VNFInstancesActionComponent, + VNFLinkComponent, + NetsliceInstancesActionComponent, + BreadcrumbComponent, + DeleteComponent, + NetslicePackagesActionComponent, + UsersActionComponent, + VimAccountsActionComponent, + ProjectsActionComponent, + ProjectLinkComponent, + UserSettingsComponent, + ShowInfoComponent, + InstantiateNetSliceTemplateComponent, + InstantiateNsComponent, + ConfirmationTopologyComponent, + ComposePackages, + WIMAccountsActionComponent, + PDUInstancesActionComponent, + SDNControllerActionComponent, + SwitchProjectComponent + ] +}) + +/** Exporting a class @exports AppModule */ +export class AppModule { + /** Variables declared to avoid state-less class */ + private appModule: string; +} + +/** + * HttpLoaderFactory is for translate service of the application. + */ +// tslint:disable:function-name +export function HttpLoaderFactory(http: HttpClient): TranslateHttpLoader { + const now: number = new Date().getTime(); + return new TranslateHttpLoader(http, './assets/i18n/', '.json?locale=' + now); +} +/** + * HttpLoaderFactory is for translate service of the application. + */ +// tslint:disable:function-name +export function appInitializerFactory(translate: TranslateService, injector: Injector): Object { + // tslint:disable-next-line: no-any + return async (): Promise => { + await injector.get(LOCATION_INITIALIZED, Promise.resolve(null)); + translate.setDefaultLang('en'); + const languageCode: string = localStorage.getItem('languageCode'); + if (languageCode !== null && languageCode !== undefined && languageCode !== '') { + await translate.use(languageCode).toPromise().catch(() => { + translate.setDefaultLang('en'); + }); + } else { + await translate.use('en').toPromise(); + localStorage.setItem('languageCode', 'en'); + } + }; +} diff --git a/src/app/approutes.module.ts b/src/app/approutes.module.ts new file mode 100644 index 0000000..e2f863c --- /dev/null +++ b/src/app/approutes.module.ts @@ -0,0 +1,114 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Routing Module + */ +import { Routes } from '@angular/router'; +import { AuthGuardService } from 'AuthGuardService'; +import { LayoutComponent } from 'LayoutComponent'; +import { LoginComponent } from 'LoginComponent'; +import { PageNotFoundComponent } from 'PageNotFound'; + +/** Exporting a function using Routes @exports AppRoutes */ +export const appRoutes: Routes = [ + { + path: 'login', + component: LoginComponent + }, + { + path: '', + component: LayoutComponent, + canActivate: [AuthGuardService], + children: [ + { + path: '', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./dashboard/DashboardModule') + .then((m: typeof import('./dashboard/DashboardModule')) => m.DashboardModule), + canActivate: [AuthGuardService] + }, + { + path: 'packages', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./packages/PackagesModule') + .then((m: typeof import('./packages/PackagesModule')) => m.PackagesModule), + canActivate: [AuthGuardService] + }, + { + path: 'instances', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./instances/InstancesModule') + .then((m: typeof import('./instances/InstancesModule')) => m.InstancesModule), + canActivate: [AuthGuardService] + }, + { + path: 'vim', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./vim-accounts/VimAccountsModule') + .then((m: typeof import('./vim-accounts/VimAccountsModule')) => m.VimAccountsModule), + canActivate: [AuthGuardService] + }, + { + path: 'wim', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./wim-accounts/WIMAccountsModule') + .then((m: typeof import('./wim-accounts/WIMAccountsModule')) => m.WIMAccountsModule), + canActivate: [AuthGuardService] + }, + { + path: 'sdn', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./sdn-controller/SDNControllerModule') + .then((m: typeof import('./sdn-controller/SDNControllerModule')) => m.SDNControllerModule), + canActivate: [AuthGuardService] + }, + { + path: 'users', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./users/UsersModule') + .then((m: typeof import('./users/UsersModule')) => m.UsersModule), + canActivate: [AuthGuardService] + }, + { + path: 'projects', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./projects/ProjectsModule') + .then((m: typeof import('./projects/ProjectsModule')) => m.ProjectsModule), + canActivate: [AuthGuardService] + }, + { + path: 'roles', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./roles/RolesModule') + .then((m: typeof import('./roles/RolesModule')) => m.RolesModule), + canActivate: [AuthGuardService] + }, + { + path: 'k8s', + // tslint:disable-next-line: no-any + loadChildren: async (): Promise => import('./k8s/K8sModule') + .then((m: typeof import('./k8s/K8sModule')) => m.K8sModule), + canActivate: [AuthGuardService] + } + ] + }, + { + path: '**', + component: PageNotFoundComponent + } +]; diff --git a/src/app/dashboard/DashboardComponent.html b/src/app/dashboard/DashboardComponent.html new file mode 100644 index 0000000..5b09dc9 --- /dev/null +++ b/src/app/dashboard/DashboardComponent.html @@ -0,0 +1,167 @@ + +
+
+
+
+
+
+
+ {{'PAGE.DASHBOARD.UPTIME' | translate}} {{'PAGE.DASHBOARD.RUNNINGINSTANCES' | translate}} +
+
+ {{'PAGE.DASHBOARD.NOINSTANCES' | translate}} +
+
+ +
+
+
+ +
+
+
+
+ {{'PAGE.DASHBOARD.FAILEDINSTANCES' | translate}} +
+
+
    +
  • + {{'PAGE.DASHBOARD.NOINSTANCES' | translate}}
  • +
  • + {{nsFailedInstance.name}} + + {{nsFailedInstance.name}} + + + + +
  • +
+
+
+ +
+
+
+
+
+
+ +

{{ (nsdPackageCount)?nsdPackageCount:0 }}

+
{{'NSPACKAGES' | translate}}
+ + + +
+
+
+
+ +

{{ (nsInstanceCount)?nsInstanceCount:0 }}

+
{{'NSINSTANCES' | translate}}
+ + + +
+
+
+
+
+
+ +

{{ (vnfdPackageCount)?vnfdPackageCount:0 }}

+
{{'VNFPACKAGES' | translate}}
+ + + +
+
+
+
+ +

{{ (vnfInstanceCount)?vnfInstanceCount:0 }}

+
{{'VNFINSTANCES' | translate}}
+ + + +
+
+
+
+
+
+ +

{{ (vimAccountCount)?vimAccountCount:0 }}

+
{{'VIMACCOUNTS' | translate}}
+ + + +
+
+
+
+ +

{{ (sdnControllerCount)?sdnControllerCount:0 }}

+
{{'SDNCONTROLLER' | translate}}
+ + + +
+
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/dashboard/DashboardComponent.scss b/src/app/dashboard/DashboardComponent.scss new file mode 100644 index 0000000..df3c6b1 --- /dev/null +++ b/src/app/dashboard/DashboardComponent.scss @@ -0,0 +1,160 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + @import "../../assets/scss/mixins/mixin"; + @import "../../assets/scss/variable"; + $min-height-set: 200px; + .dashboard { + .custom-card { + word-wrap: break-word; + @include box-shadow(0px, 1px, 15px, 0px, rgba(69, 90, 100, 0.1)); + @include transition(all, 0.2s, null, null); + @include roundedCorners(5); + @include border(all, 1, solid, rgba(238, 238, 238, 0.75)); + color: $white; + &.card-hover { + @include transition(all, 0.25s, ease, null); + &:hover { + -moz-transform: translateY(-4px) scale(1.01); + -ms-transform: translateY(-4px) scale(1.01); + -o-transform: translateY(-4px) scale(1.01); + transform: translateY(-4px) scale(1.01); + } + } + &.pink-card { + @include background( + linear-gradient(to left top, #d81b60, #e0306d, #e7407a, #ee4f87, #f55c94), + null, + null, + null, + null + ); + } + &.purple-card { + @include background( + linear-gradient(to left top, #605ca8, #736ebb, #8681ce, #9994e2, #aca7f6), + null, + null, + null, + null + ); + } + &.aqua-card { + @include background( + linear-gradient(to left top, #00c0ef, #00cdf5, #00dafa, #00e6fd, #0af3ff), + null, + null, + null, + null + ); + } + .custom-card-header { + @include background(null, $primary, null, null, null); + @include roundedTop(5); + a { + color: $white; + @include flexbox(flex, space-between, null, null, center, null); + @include padding-value(12, 20, 12, 20); + } + } + .card-body { + @include padding-value(5, 5, 5, 10); + &.list-overflow { + overflow-y: scroll; + .list-group { + .list-group-item { + cursor: default; + @include border(all, 0, solid, $black-coral); + @include border(bottom, 1, solid, rgba(0, 0, 0, 0.125)); + @include padding-value(10, 0, 10, 0); + @include margin-value(0, 0, 0, 0); + color: $gray-600; + i { + cursor: pointer; + @include font(null, 14px, null); + &.activeProjectLink { + cursor: default; + } + } + &:last-child { + @include border(bottom, 0, solid, rgba(0, 0, 0, 0.125)); + } + } + } + &.failed-instances { + max-height: $min-height-set; + } + &.project-list { + max-height: 65vh; + } + } + } + } + .instances { + .graph-section { + min-height: $min-height-set; + @include flexbox(null, center, null, null, null, null); + @include padding-value(10, 10, 10, 10); + .card-title { + color: $gray-600; + } + .instances-canvas { + @include flexbox(none !important, null, null, null, null, null); + &.show-canvas { + @include flexbox(block !important, null, null, null, null, null); + } + #canvas{ + @include wh-value(100%, $min-height-set); + } + } + } + } + .module-counts { + .status-card { + overflow: hidden; + @include wh-value(null, 130px); + @include roundedCorners(4); + @include box-shadow(0px, 5px, 20px, 2px, $transparent-dark-bg); + cursor: pointer; + @include flexbox(null, null, null, null, center, null); + @include padding-value(20, 20, 20, 20); + @include border(all, 0, solid, $gray-80); + i { + @include font(null, 2rem, null); + @include margin-value(0, 0, 8, 0); + } + h6 { + @include font(null, 0.8rem, null); + } + &:hover .link-icon { + @include position_value(null, null, -60px, null, null); + } + .link-icon { + @include background(null, rgba(255, 255, 255, 0.5), null, null, null); + @include position_value(absolute, 0px, -130px, null, null); + @include wh-value(130px, 130px); + @include font(null, 30px, null); + @include padding-value(40, 20, 40, 20); + @include roundedCornersPercentage(50%); + @include transition(all, 0.3s, ease-in-out, null); + i { + @include font(null, 1.875rem, null); + } + } + } + } + } \ No newline at end of file diff --git a/src/app/dashboard/DashboardComponent.ts b/src/app/dashboard/DashboardComponent.ts new file mode 100644 index 0000000..4ab802f --- /dev/null +++ b/src/app/dashboard/DashboardComponent.ts @@ -0,0 +1,402 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Dashboard Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { AuthenticationService } from 'AuthenticationService'; +import { Chart } from 'chart.js'; +import { ERRORDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { NSDDetails } from 'NSDModel'; +import { NSInstanceDetails } from 'NSInstanceModel'; +import { ProjectData, ProjectDetails } from 'ProjectModel'; +import { ProjectService } from 'ProjectService'; +import { RestService } from 'RestService'; +import { Observable, Subscription } from 'rxjs'; +import { SDNControllerModel } from 'SDNControllerModel'; +import { SharedService } from 'SharedService'; +import { ProjectRoleMappings, UserDetail } from 'UserModel'; +import { VimAccountDetails } from 'VimAccountModel'; +import { VNFDDetails } from 'VNFDModel'; +import { VNFInstanceDetails } from 'VNFInstanceModel'; + +/** + * Creating component + * @Component takes DashboardComponent.html as template url + */ +@Component({ + styleUrls: ['./DashboardComponent.scss'], + templateUrl: './DashboardComponent.html' +}) + +/** + * This file created during the angular project creation + */ + +/** Exporting a class @exports DashboardComponent */ +export class DashboardComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Observable holds logined value @public */ + public username$: Observable; + + /** Variables holds admin is logged or not @public */ + public isAdmin: boolean; + + /** List of NS failed Instances @public */ + public nsFailedInstances: {}[] = []; + + /** Setting up count for vnfdPackages @public */ + public vnfdPackageCount: number; + + /** Setting up count for nsdPackage @public */ + public nsdPackageCount: number; + + /** Setting up count for nsInstance @public */ + public nsInstanceCount: number; + + /** Setting up count for vnfInstance @public */ + public vnfInstanceCount: number; + + /** Setting up count for vimAccount @public */ + public vimAccountCount: number; + + /** Setting up count for sdnController @public */ + public sdnControllerCount: number; + + /** Variables holds current project details @public */ + public currentProjectDetails: {}; + + /** Array holds all the projects @public */ + public projectList: {}[] = []; + + /** Array holds all the projects @public */ + public allProjectList: {}[] = []; + + /** Variables holds the selected project @public */ + public selectedProject: Observable; + + /** Check the Instances loading results @public */ + public isCanvasLoadingResults: boolean = true; + + /** Check the Projects loading results @public */ + public isProjectsLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** List of NS Success Instances @private */ + public nsRunningInstance: string[] = []; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + /** Used to subscribe vnfdPackage @private */ + private vnfdPackageCountSub: Subscription; + + /** Used to subscribe nsdPackage @private */ + private nsdPackageCountSub: Subscription; + + /** Used to subscribe nsInstance @private */ + private nsInstanceCountSub: Subscription; + + /** Used to subscribe vnfInstance @private */ + private vnfInstanceCountSub: Subscription; + + /** Used to subscribe vimAccount @private */ + private vimAccountCountSub: Subscription; + + /** Used to subscribe sdnController @private */ + private sdnControllerCountSub: Subscription; + + /** No of Hours of NS Success Instances @private */ + private noOfHours: number[] = []; + + /** collects charts objects @private */ + private charts: object = []; + + /** Contains all methods related to projects @private */ + private projectService: ProjectService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains NS Instance Details */ + private nsInstancesDataArr: {}[]; + + /** Container created time array @private */ + private createdTimes: string[] = []; + + /** Contains slice limit const @private */ + private sliceLimit: number = 10; + + /** Contians hour converter @private */ + private hourConverter: number = 3600; + + /** Contians color code for chart @private */ + private chartColorPink: string = '#e4397c'; + + /** Contians color code for chart @private */ + private chartColorPurple: string = '#605ca8'; + + /** Contians color code for chart @private */ + private chartColorCyan: string = '#00c0ef'; + + /** Contians color code for chart @private */ + private chartColorBlue: string = '#054C8C'; + + /** Contians color code for chart @private */ + private chartColorYellow: string = '#ffce56'; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.authService = this.injector.get(AuthenticationService); + this.projectService = this.injector.get(ProjectService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.username$ = this.authService.username; + this.isAdmin = (localStorage.getItem('isAdmin') === 'true') ? true : false; + this.selectedProject = this.authService.ProjectName; + this.checkAdminPrivilege(); + this.getUserAccessedProjects(); + this.getAllProjects(); + this.getVnfdPackageCount(); + this.getNsdPackageCount(); + this.getNsInstanceCount(); + this.getVnfInstanceCount(); + this.getVimAccountCount(); + this.getSDNControllerCount(); + } + + /** Get all the projects @public */ + public getUserAccessedProjects(): void { + this.projectService.getUserProjects().subscribe((projects: UserDetail) => { + const projectList: {}[] = projects.project_role_mappings; + this.projectList = projectList.filter( + (thing: ProjectRoleMappings, i: number, arr: []) => arr + .findIndex((t: ProjectRoleMappings) => t.project_name === thing.project_name) === i + ); + }, (error: Error) => { + // TODO: Handle failure + }); + } + + /** Fetching all the Project in dashboard @public */ + public getAllProjects(): void { + this.isProjectsLoadingResults = true; + this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectDetails[]) => { + this.allProjectList = []; + projectsData.forEach((projectData: ProjectDetails) => { + const projectDataObj: ProjectData = this.generateProjectData(projectData); + this.allProjectList.push(projectDataObj); + }); + this.isProjectsLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isProjectsLoadingResults = false; + }); + } + + /** Generate Projects object from loop and return for the datasource @public */ + public generateProjectData(projectData: ProjectDetails): ProjectData { + return { + projectName: projectData.name, + modificationDate: this.sharedService.convertEpochTime(projectData._admin.modified), + creationDate: this.sharedService.convertEpochTime(projectData._admin.created), + id: projectData._id, + project: projectData._id + }; + } + + /** Function to check admin privilege @public */ + public checkAdminPrivilege(): void { + if (!this.isAdmin) { + this.projectService.getCurrentProjectDetails().subscribe((projectDetails: {}) => { + this.currentProjectDetails = projectDetails; + }, (error: Error) => { + // TODO: Handle failure + }); + } + } + + /** Get VNFD Package details @public */ + public getVnfdPackageCount(): void { + this.vnfdPackageCountSub = this.restService.getResource(environment.VNFPACKAGESCONTENT_URL) + .subscribe((vnfdPackageData: VNFDDetails[]) => { + this.vnfdPackageCount = vnfdPackageData.length; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Get NSD Package details @public */ + public getNsdPackageCount(): void { + this.nsdPackageCountSub = this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL) + .subscribe((nsdPackageData: NSDDetails[]) => { + this.nsdPackageCount = nsdPackageData.length; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Get NS Instance details @public */ + public getNsInstanceCount(): void { + this.isCanvasLoadingResults = true; + this.nsInstanceCountSub = this.restService.getResource(environment.NSDINSTANCES_URL) + .subscribe((nsInstancesData: NSInstanceDetails[]) => { + this.nsInstancesDataArr = nsInstancesData; + this.nsInstanceCount = nsInstancesData.length; + this.nsInstanceChart(); + this.isCanvasLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isCanvasLoadingResults = false; + }); + } + + /** Get NS Instance chart details @public */ + public nsInstanceChart(): void { + this.nsInstancesDataArr.forEach((nsdInstanceData: NSDDetails) => { + const operationalStatus: string = nsdInstanceData['operational-status']; + const configStatus: string = nsdInstanceData['config-status']; + if (operationalStatus === 'failed' || configStatus === 'failed') { + this.nsFailedInstances.push(nsdInstanceData); + } else if (operationalStatus === 'running' && configStatus === 'configured') { + this.nsRunningInstance.push(nsdInstanceData.name); + this.createdTimes.push(((nsdInstanceData._admin.created).toString()).slice(0, this.sliceLimit)); + } + }); + const now: Date = new Date(); + const currentTime: number = Number((now.getTime().toString().slice(0, this.sliceLimit))); + this.createdTimes.forEach((createdTime: string) => { + this.noOfHours.push((Math.round((currentTime - Number(createdTime)) / this.hourConverter))); + }); + this.drawNsChart(); + } + + /** Prepare and sketch NS instance chart */ + public drawNsChart(): void { + this.charts = new Chart('canvas', { + type: 'bar', + data: { + labels: this.nsRunningInstance, + datasets: [{ + data: this.noOfHours, + label: this.translateService.instant('NOOFHOURS'), + borderColor: [this.chartColorPurple, this.chartColorPink, this.chartColorCyan, + this.chartColorBlue, this.chartColorYellow], + fill: false, + backgroundColor: [this.chartColorPurple, this.chartColorPink, this.chartColorCyan, + this.chartColorBlue, this.chartColorYellow] + }] + }, + options: { + legend: { display: false }, + scales: { + xAxes: [{ + display: true, + ticks: { + // tslint:disable-next-line: no-any + callback: (label: any, index: number, labels: string): string => { + const length: number = 20; + const ending: string = '...'; + if (label.length > length) { + return label.substring(0, length - ending.length) + ending; + } else { + return label; + } + } + }, + scaleLabel: { + display: true, + labelString: this.translateService.instant('INSTANCES') + } + }], + yAxes: [{ + ticks: { + beginAtZero: true + }, + display: true, + scaleLabel: { + display: true, + labelString: this.translateService.instant('NOOFHOURS') + } + }] + } + } + }); + } + + /** Get VNFD instance details @public */ + public getVnfInstanceCount(): void { + this.vnfInstanceCountSub = this.restService.getResource(environment.NSDINSTANCES_URL) + .subscribe((vnfInstanceData: VNFInstanceDetails[]) => { + this.vnfInstanceCount = vnfInstanceData.length; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Get VIM account details @public */ + public getVimAccountCount(): void { + this.vimAccountCountSub = this.restService.getResource(environment.VIMACCOUNTS_URL) + .subscribe((vimAccountData: VimAccountDetails[]) => { + this.vimAccountCount = vimAccountData.length; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Get SDN Controller Count @public */ + public getSDNControllerCount(): void { + this.sdnControllerCountSub = this.restService.getResource(environment.SDNCONTROLLER_URL) + .subscribe((sdnControllerData: SDNControllerModel[]) => { + this.sdnControllerCount = sdnControllerData.length; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** + * Lifecyle Hooks the trigger before component is deleted + */ + public ngOnDestroy(): void { + this.vnfdPackageCountSub.unsubscribe(); + this.nsdPackageCountSub.unsubscribe(); + this.nsInstanceCountSub.unsubscribe(); + this.vnfInstanceCountSub.unsubscribe(); + this.vimAccountCountSub.unsubscribe(); + this.sdnControllerCountSub.unsubscribe(); + } +} diff --git a/src/app/dashboard/DashboardModule.ts b/src/app/dashboard/DashboardModule.ts new file mode 100644 index 0000000..4d882e2 --- /dev/null +++ b/src/app/dashboard/DashboardModule.ts @@ -0,0 +1,61 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Dashboard Module + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; +import { DashboardComponent } from 'DashboardComponent'; +import { LoaderModule } from 'LoaderModule'; +import { ChartsModule } from 'ng2-charts'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** const values for dashboard Routes */ +const routes: Routes = [ + { + path: '', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo] + }, + component: DashboardComponent + } +]; +/** + * An NgModule is a class adorned with the @NgModule decorator function. + * @NgModule takes a metadata object that tells Angular how to compile and run module code. + */ +@NgModule({ + imports: [FormsModule, CommonModule, HttpClientModule, FlexLayoutModule, TranslateModule, + ChartsModule, RouterModule.forChild(routes), NgbModule, LoaderModule], + declarations: [DashboardComponent] +}) +/** Exporting a class @exports DashboardModule */ +export class DashboardModule { + /** Variables declared to avoid state-less class */ + private dashboardModule: string; +} diff --git a/src/app/instances/InstancesComponent.html b/src/app/instances/InstancesComponent.html new file mode 100644 index 0000000..06b8876 --- /dev/null +++ b/src/app/instances/InstancesComponent.html @@ -0,0 +1,18 @@ + + diff --git a/src/app/instances/InstancesComponent.scss b/src/app/instances/InstancesComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/instances/InstancesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/instances/InstancesComponent.ts b/src/app/instances/InstancesComponent.ts new file mode 100644 index 0000000..fe46d8c --- /dev/null +++ b/src/app/instances/InstancesComponent.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Instance components + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; +/** + * Creating component + * @Component takes InstancesComponent.html as template url + */ +@Component({ + selector: 'app-instances', + templateUrl: './InstancesComponent.html', + styleUrls: ['./InstancesComponent.scss'] +}) +/** Exporting a class @exports InstancesComponent */ +export class InstancesComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/instances') { + this.router.navigate(['/instances/ns']).catch(); + } + } +} diff --git a/src/app/instances/InstancesModule.ts b/src/app/instances/InstancesModule.ts new file mode 100644 index 0000000..7e47d32 --- /dev/null +++ b/src/app/instances/InstancesModule.ts @@ -0,0 +1,132 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Instance module + */ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { CodemirrorModule } from '@ctrl/ngx-codemirror'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { AddPDUInstancesComponent } from 'AddPDUInstancesComponent'; +import { DataService } from 'DataService'; +import { HistoryOperationsComponent } from 'HistoryOperationsComponent'; +import { InstancesComponent } from 'InstancesComponent'; +import { LoaderModule } from 'LoaderModule'; +import { NetsliceInstancesComponent } from 'NetsliceInstancesComponent'; +import { SidebarModule } from 'ng-sidebar'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { NSInstancesComponent } from 'NSInstancesComponent'; +import { NSPrimitiveComponent } from 'NSPrimitiveComponent'; +import { NSTopologyComponent } from 'NSTopologyComponent'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { PDUInstancesComponent } from 'PDUInstancesComponent'; +import { VNFInstancesComponent } from 'VNFInstancesComponent'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** Exporting a function using Routes @exports routes */ +const routes: Routes = [ + { + path: '', + component: InstancesComponent, + children: [ + { + path: 'ns', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'NSINSTANCES', url: null }] + }, + component: NSInstancesComponent + }, + { + path: 'vnf', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VNFINSTANCES', url: null }] + }, + component: VNFInstancesComponent + }, + { + path: 'pdu', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'PDUINSTANCES', url: null }] + }, + component: PDUInstancesComponent + }, + { + path: 'netslice', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'PAGE.DASHBOARD.NETSLICEINSTANCE', url: null }] + }, + component: NetsliceInstancesComponent + }, + { + path: ':type/history-operations/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: '{type}', url: '/instances/{type}' }, { title: '{id}', url: null }] + }, + component: HistoryOperationsComponent + }, + { + path: 'ns/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'NSINSTANCES', url: '/instances/ns' }, { title: '{id}', url: null }] + }, + component: NSTopologyComponent + } + ] + } +]; + +/** + * An NgModule is a class adorned with the @NgModule decorator function. + * @NgModule takes a metadata object that tells Angular how to compile and run module code. + */ +@NgModule({ + imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, TranslateModule, + CodemirrorModule, CommonModule, Ng2SmartTableModule, FlexLayoutModule, RouterModule.forChild(routes), NgbModule, + NgSelectModule, PagePerRowModule, LoaderModule, SidebarModule.forRoot(), PageReloadModule], + declarations: [InstancesComponent, NSInstancesComponent, VNFInstancesComponent, PDUInstancesComponent, AddPDUInstancesComponent, + NetsliceInstancesComponent, HistoryOperationsComponent, NSTopologyComponent, NSPrimitiveComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + providers: [DataService], + entryComponents: [NSPrimitiveComponent, AddPDUInstancesComponent] +}) +/** Exporting a class @exports InstancesModule */ +export class InstancesModule { + /** Resolves state-less class */ + private instancesModule: string; + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.instancesModule = ''; + } +} diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.html b/src/app/instances/netslice-instances/NetsliceInstancesComponent.html new file mode 100644 index 0000000..e8b3c0c --- /dev/null +++ b/src/app/instances/netslice-instances/NetsliceInstancesComponent.html @@ -0,0 +1,44 @@ + +
+
{{'PAGE.DASHBOARD.NETSLICEINSTANCE' | translate}}
+ + + +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.scss b/src/app/instances/netslice-instances/NetsliceInstancesComponent.scss new file mode 100644 index 0000000..0ecd95d --- /dev/null +++ b/src/app/instances/netslice-instances/NetsliceInstancesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ \ No newline at end of file diff --git a/src/app/instances/netslice-instances/NetsliceInstancesComponent.ts b/src/app/instances/netslice-instances/NetsliceInstancesComponent.ts new file mode 100644 index 0000000..3b9564a --- /dev/null +++ b/src/app/instances/netslice-instances/NetsliceInstancesComponent.ts @@ -0,0 +1,283 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Netslice Instance Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate'; +import { NetsliceInstancesActionComponent } from 'NetsliceInstancesActionComponent'; +import { NSTInstanceData, NSTInstanceDetails } from 'NetworkSliceModel'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes NetsliceInstancesComponent.html as template url + */ +@Component({ + templateUrl: './NetsliceInstancesComponent.html', + styleUrls: ['./NetsliceInstancesComponent.scss'] +}) + +/** Exporting a class @exports NetsliceInstancesComponent */ +export class NetsliceInstancesComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Datasource instance inititated @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Datasource table Data for the NST @public */ + public nstInstanceData: NSTInstanceData[] = []; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.operationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.operationalStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.operationalStateThirdStep; + + /** Config State init data @public */ + public configStateFirstStep: string = CONFIGCONSTANT.configStateFirstStep; + + /** Config State init data @public */ + public configStateSecondStep: string = CONFIGCONSTANT.configStateSecondStep; + + /** Config State init data @public */ + public configStateThirdStep: string = CONFIGCONSTANT.configStateThirdStep; + + /** config status assign @public */ + public configStatusCheck: string; + + /** To consume REST API calls @private */ + private dataService: DataService; + + /** Utilizes rest service for any CRUD operations @public */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + this.dataService = this.injector.get(DataService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table listing manipulation @private */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @private */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'net-slice-instance' }); + this.dataService.changeMessage(event.data); + } + + /** Instantiate Net Slice using modalservice @public */ + public instantiateNetSlice(): void { + const modalRef: NgbModalRef = this.modalService.open(InstantiateNetSliceTemplateComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.generateData(); + } + }).catch(); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + columns: this.columnLists, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnLists = { + name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '15%' }, + NstName: { title: this.translateService.instant('NSTNAME'), width: '15%' }, + OperationalStatus: { + type: 'html', + title: this.translateService.instant('OPERATIONALSTATUS'), + width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): string => { + if (row.OperationalStatus === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.OperationalStatus === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.OperationalStatus === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.OperationalStatus}`; + } + } + }, + ConfigStatus: { + type: 'html', + title: this.translateService.instant('CONFIGSTATUS'), + width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.configStateFirstStep, title: this.configStateFirstStep }, + { value: this.configStateSecondStep, title: this.configStateSecondStep }, + { value: this.configStateThirdStep, title: this.configStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): string => { + if (row.ConfigStatus === this.configStateFirstStep) { + return ` + + `; + } else if (row.ConfigStatus === this.configStateSecondStep) { + return ` + + `; + } else if (row.ConfigStatus === this.configStateThirdStep) { + return ` + + `; + } else { + return `${row.ConfigStatus}`; + } + } + }, + DetailedStatus: { title: this.translateService.instant('DETAILEDSTATUS'), width: '15%' }, + Actions: { + name: 'Action', width: '10%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: NSTInstanceData, row: NSTInstanceData): NSTInstanceData => row, + renderComponent: NetsliceInstancesActionComponent + } + }; + } + + /** generateData initiate the net-slice-instance list @public */ + public generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.NETWORKSLICEINSTANCESCONTENT_URL) + .subscribe((netSliceInstancesData: NSTInstanceDetails[]) => { + this.nstInstanceData = []; + netSliceInstancesData.forEach((netSliceInstanceData: NSTInstanceDetails) => { + if (netSliceInstanceData['config-status'] !== undefined) { + this.configStatusCheck = netSliceInstanceData['config-status']; + } else { + this.configStatusCheck = netSliceInstanceData['operational-status']; + } + const netSliceDataObj: NSTInstanceData = { + name: netSliceInstanceData.name, + identifier: netSliceInstanceData.id, + NstName: netSliceInstanceData['nst-ref'], + OperationalStatus: netSliceInstanceData['operational-status'], + ConfigStatus: this.configStatusCheck, + DetailedStatus: netSliceInstanceData['detailed-status'] + }; + this.nstInstanceData.push(netSliceDataObj); + }); + if (this.nstInstanceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.nstInstanceData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } +} diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.html b/src/app/instances/ns-history-operations/HistoryOperationsComponent.html new file mode 100644 index 0000000..7890a13 --- /dev/null +++ b/src/app/instances/ns-history-operations/HistoryOperationsComponent.html @@ -0,0 +1,36 @@ + +
+
{{'HISTORYOFOPERATIONS' | translate}}
+
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.scss b/src/app/instances/ns-history-operations/HistoryOperationsComponent.scss new file mode 100644 index 0000000..fdec4ed --- /dev/null +++ b/src/app/instances/ns-history-operations/HistoryOperationsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ diff --git a/src/app/instances/ns-history-operations/HistoryOperationsComponent.ts b/src/app/instances/ns-history-operations/HistoryOperationsComponent.ts new file mode 100644 index 0000000..a0cac86 --- /dev/null +++ b/src/app/instances/ns-history-operations/HistoryOperationsComponent.ts @@ -0,0 +1,265 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file NS History Of Operations Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import { LocalDataSource } from 'ng2-smart-table'; +import { NSDInstanceData } from 'NSInstanceModel'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; + +/** + * Creating component + * @Component takes HistoryOperationsComponent.html as template url + */ +@Component({ + templateUrl: './HistoryOperationsComponent.html', + styleUrls: ['./HistoryOperationsComponent.scss'] +}) +/** Exporting a class @exports HistoryOperationsComponent */ +export class HistoryOperationsComponent implements OnInit { + /** Injector to invoke other services @public */ + public injector: Injector; + + /** NS Instance array @public */ + public nsAndnstInstanceData: object[] = []; + + /** Datasource instance @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Instance component are stored in settings @public */ + public settings: {} = {}; + + /** Contains objects for smart table title and filter settings @public */ + public columnList: {} = {}; + + /** Variable handles the page name @public */ + public page: string; + + /** Variable handles the title name @public */ + public titleName: string; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** History State init data @public */ + public historyStateFirstStep: string = CONFIGCONSTANT.historyStateFirstStep; + + /** History State running data @public */ + public historyStateSecondStep: string = CONFIGCONSTANT.historyStateSecondStep; + + /** History State failed data @public */ + public historyStateThirdStep: string = CONFIGCONSTANT.historyStateThirdStep; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** variables contains paramsID @private */ + private paramsID: string; + + /** variables contains paramsID @private */ + private paramsType: string; + + /** variables conatins URL of the History operations @public */ + private historyURL: string; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + /** Service holds the router information @private */ + private router: Router; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.modalService = this.injector.get(NgbModal); + this.translateService = this.injector.get(TranslateService); + this.router = this.injector.get(Router); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.paramsID = this.activatedRoute.snapshot.paramMap.get('id'); + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.paramsType = this.activatedRoute.snapshot.paramMap.get('type'); + if (this.paramsType === 'ns') { + this.historyURL = environment.NSHISTORYOPERATIONS_URL + '/?nsInstanceId=' + this.paramsID; + this.page = 'ns-history-operation'; + this.titleName = 'INSTANCEDETAILS'; + } else if (this.paramsType === 'netslice') { + this.historyURL = environment.NSTHISTORYOPERATIONS_URL + '/?netsliceInstanceId=' + this.paramsID; + this.page = 'nst-history-operation'; + this.titleName = 'INSTANCEDETAILS'; + } + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + columns: this.columnList, + actions: { + add: false, edit: false, delete: false, position: 'right', + custom: [{ + name: 'showInformation', title: ''}] + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnList = { + id: { title: this.translateService.instant('ID'), width: '30%' }, + type: { title: this.translateService.instant('TYPE'), width: '20%' }, + state: { + type: 'html', title: this.translateService.instant('OPERATIONSTATE'), width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.historyStateFirstStep, title: this.historyStateFirstStep }, + { value: this.historyStateSecondStep, title: this.historyStateSecondStep }, + { value: this.historyStateThirdStep, title: this.historyStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => { + if (row.state === this.historyStateFirstStep) { + return ` + + `; + } else if (row.state === this.historyStateSecondStep) { + return ` + + `; + } else if (row.state === this.historyStateThirdStep) { + return ` + + `; + } else { + return `${row.state}`; + } + } + }, + startTime: { title: this.translateService.instant('STARTTIME'), width: '15%' }, + statusEnteredTime: { title: this.translateService.instant('STATUSENTEREDTIME'), width: '15%' } + }; + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + this.dataService.changeMessage(event.data); + } + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + /** show information methods modal with ns history info */ + public showInformation(event: MessageEvent): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: event.data.id, + page: this.page, + titleName: this.titleName + }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** generateData initiate the ns-instance list @private */ + private generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(this.historyURL).subscribe((nsdInstancesData: {}[]) => { + this.nsAndnstInstanceData = []; + nsdInstancesData.forEach((nsdAndnstInstanceData: NSDInstanceData) => { + const nsAndnstDataObj: {} = { + id: nsdAndnstInstanceData.id, + type: nsdAndnstInstanceData.lcmOperationType, + state: nsdAndnstInstanceData.operationState, + startTime: this.sharedService.convertEpochTime(nsdAndnstInstanceData.startTime), + statusEnteredTime: this.sharedService.convertEpochTime(nsdAndnstInstanceData.statusEnteredTime) + }; + this.nsAndnstInstanceData.push(nsAndnstDataObj); + }); + + if (this.nsAndnstInstanceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.nsAndnstInstanceData).then((data: {}) => { + //empty block + }).catch(); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + }); + } +} diff --git a/src/app/instances/ns-instances/NSInstancesComponent.html b/src/app/instances/ns-instances/NSInstancesComponent.html new file mode 100644 index 0000000..6047a2f --- /dev/null +++ b/src/app/instances/ns-instances/NSInstancesComponent.html @@ -0,0 +1,43 @@ + +
+
{{'NSINSTANCES' | translate}}
+ + + +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/ns-instances/NSInstancesComponent.scss b/src/app/instances/ns-instances/NSInstancesComponent.scss new file mode 100644 index 0000000..0ecd95d --- /dev/null +++ b/src/app/instances/ns-instances/NSInstancesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ \ No newline at end of file diff --git a/src/app/instances/ns-instances/NSInstancesComponent.ts b/src/app/instances/ns-instances/NSInstancesComponent.ts new file mode 100644 index 0000000..07184da --- /dev/null +++ b/src/app/instances/ns-instances/NSInstancesComponent.ts @@ -0,0 +1,278 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file NS Instance Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { InstantiateNsComponent } from 'InstantiateNs'; +import { LocalDataSource } from 'ng2-smart-table'; +import { NSDInstanceData, NSInstanceDetails } from 'NSInstanceModel'; +import { NSInstancesActionComponent } from 'NSInstancesActionComponent'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes NSInstancesComponent.html as template url + */ +@Component({ + templateUrl: './NSInstancesComponent.html', + styleUrls: ['./NSInstancesComponent.scss'] +}) +/** Exporting a class @exports NSInstancesComponent */ +export class NSInstancesComponent implements OnInit { + /** Injector to invoke other services @public */ + public injector: Injector; + + /** NS Instance array @public */ + public nsInstanceData: object[] = []; + + /** Datasource instance @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** SelectedRows array @public */ + public selectedRows: object[] = []; + + /** Selected list array @public */ + public selectList: object[] = []; + + /** Instance component are stored in settings @public */ + public settings: {} = {}; + + /** Contains objects for menu settings @public */ + public columnList: {} = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.operationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.operationalStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.operationalStateThirdStep; + + /** Config State init data @public */ + public configStateFirstStep: string = CONFIGCONSTANT.configStateFirstStep; + + /** Config State init data @public */ + public configStateSecondStep: string = CONFIGCONSTANT.configStateSecondStep; + + /** Config State init data @public */ + public configStateThirdStep: string = CONFIGCONSTANT.configStateThirdStep; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + columns: this.columnList, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnList = { + name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + NsdName: { title: this.translateService.instant('NSDNAME'), width: '15%' }, + OperationalStatus: { + title: this.translateService.instant('OPERATIONALSTATUS'), width: '10%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => { + if (row.OperationalStatus === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.OperationalStatus === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.OperationalStatus === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.OperationalStatus}`; + } + } + }, + ConfigStatus: { + title: this.translateService.instant('CONFIGSTATUS'), width: '10%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.configStateFirstStep, title: this.configStateFirstStep }, + { value: this.configStateSecondStep, title: this.configStateSecondStep }, + { value: this.configStateThirdStep, title: this.configStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): string => { + if (row.ConfigStatus === this.configStateFirstStep) { + return ` + + `; + } else if (row.ConfigStatus === this.configStateSecondStep) { + return ` + + `; + } else if (row.ConfigStatus === this.configStateThirdStep) { + return ` + + `; + } else { + return `${row.ConfigStatus}`; + } + } + }, + DetailedStatus: { title: this.translateService.instant('DETAILEDSTATUS'), width: '15%' }, + Actions: { + name: 'Action', width: '15%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: NSDInstanceData, row: NSDInstanceData): NSDInstanceData => row, + renderComponent: NSInstancesActionComponent + } + }; + } + + /** generateData initiate the ns-instance list @public */ + public generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => { + this.nsInstanceData = []; + nsdInstancesData.forEach((nsdInstanceData: NSInstanceDetails) => { + const nsDataObj: NSDInstanceData = { + name: nsdInstanceData.name, + identifier: nsdInstanceData.id, + NsdName: nsdInstanceData['nsd-name-ref'], + OperationalStatus: nsdInstanceData['operational-status'], + ConfigStatus: nsdInstanceData['config-status'], + DetailedStatus: nsdInstanceData['detailed-status'], + memberIndex: nsdInstanceData.nsd['constituent-vnfd'], + nsConfig: nsdInstanceData.nsd['ns-configuration'] + }; + this.nsInstanceData.push(nsDataObj); + }); + if (this.nsInstanceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.nsInstanceData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'ns-instance' }); + this.dataService.changeMessage(event.data); + } + + /** Instantiate NS using modalservice @public */ + public instantiateNS(): void { + const modalRef: NgbModalRef = this.modalService.open(InstantiateNsComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.generateData(); + } + }).catch(); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } +} diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.html b/src/app/instances/ns-primitive/NSPrimitiveComponent.html new file mode 100644 index 0000000..646c8ae --- /dev/null +++ b/src/app/instances/ns-primitive/NSPrimitiveComponent.html @@ -0,0 +1,92 @@ + + +
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.scss b/src/app/instances/ns-primitive/NSPrimitiveComponent.scss new file mode 100644 index 0000000..edad97f --- /dev/null +++ b/src/app/instances/ns-primitive/NSPrimitiveComponent.scss @@ -0,0 +1,34 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; + +.primitive-params-head { + @include padding-value(10, 10, 10, 10); + line-height: 2em; + .btn-params { + @include border(all, 1, solid, $white); + } +} + +.remove-params { + display: flex; + align-items: center; + font-size: 20px; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/instances/ns-primitive/NSPrimitiveComponent.ts b/src/app/instances/ns-primitive/NSPrimitiveComponent.ts new file mode 100644 index 0000000..02269d3 --- /dev/null +++ b/src/app/instances/ns-primitive/NSPrimitiveComponent.ts @@ -0,0 +1,271 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file NS Instance Primitive Component + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, URLPARAMS } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { NSData } from 'NSDModel'; +import { NSPrimitiveParams } from 'NSInstanceModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes NSPrimitiveComponent.html as template url + */ +@Component({ + templateUrl: './NSPrimitiveComponent.html', + styleUrls: ['./NSPrimitiveComponent.scss'] +}) +/** Exporting a class @exports NSPrimitiveComponent */ +export class NSPrimitiveComponent implements OnInit { + /** Form valid on submit trigger @public */ + public submitted: boolean = false; + + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup instance added to the form @ html @public */ + public primitiveForm: FormGroup; + + /** Primitive params array @public */ + public primitiveParams: FormArray; + + /** Variable set for twoway binding @public */ + public nsdId: string; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Contains list of primitive parameter @public */ + public primitiveParameter: {}[] = []; + + /** Input contains component objects @public */ + @Input() public params: URLPARAMS; + + /** Contains list of primitive actions @public */ + public primitiveList: {}[]; + + /** Contains objects that is used to hold types of primitive @public */ + public primitiveTypeList: {}[] = []; + + /** Model value used to hold selected primitive type @public */ + public primitiveType: string; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** packages data service collections @private */ + private dataService: DataService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains objects that is used to convert key/value pair @private */ + private objectPrimitiveParams: {} = {}; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); + this.sharedService = this.injector.get(SharedService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + this.primitiveTypeList = [{ title: this.translateService.instant('VNFPRIMITIVE'), value: 'VNF_Primitive' }]; + this.primitiveType = 'VNF_Primitive'; + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + /** Setting up initial value for NSD */ + this.dataService.currentMessage.subscribe((event: NSData) => { + if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) { + this.nsdId = event.identifier; + } + }); + if (!isNullOrUndefined(this.params.nsConfig)) { + this.primitiveTypeList.push({ title: this.translateService.instant('NSPRIMITIVE'), value: 'NS_Primitive' }); + } + this.initializeForm(); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.primitiveForm.controls; } + + /** initialize Forms @public */ + public initializeForm(): void { + this.primitiveForm = this.formBuilder.group({ + primitive: [null, [Validators.required]], + vnf_member_index: [null, [Validators.required]], + primitive_params: this.formBuilder.array([this.primitiveParamsBuilder()]) + }); + } + + /** Generate primitive params @public */ + public primitiveParamsBuilder(): FormGroup { + return this.formBuilder.group({ + primitive_params_name: [null, [Validators.required]], + primitive_params_value: ['', [Validators.required]] + }); + } + + /** Handle FormArray Controls @public */ + public getControls(): AbstractControl[] { + return (this.getFormControl('primitive_params') as FormArray).controls; + } + + /** Push all primitive params on user's action @public */ + public createPrimitiveParams(): void { + this.primitiveParams = this.getFormControl('primitive_params') as FormArray; + this.primitiveParams.push(this.primitiveParamsBuilder()); + } + + /** Remove primitive params on user's action @public */ + public removePrimitiveParams(index: number): void { + this.primitiveParams.removeAt(index); + } + + /** Execute NS Primitive @public */ + public execNSPrimitive(): void { + this.submitted = true; + this.objectPrimitiveParams = {}; + this.sharedService.cleanForm(this.primitiveForm); + if (this.primitiveForm.invalid) { return; } // Proceed, onces form is valid + this.primitiveForm.value.primitive_params.forEach((params: NSPrimitiveParams) => { + if (params.primitive_params_name !== null && params.primitive_params_value !== '') { + this.objectPrimitiveParams[params.primitive_params_name] = params.primitive_params_value; + } + }); + //Prepare primitive params + const primitiveParamsPayLoads: {} = { + primitive: this.primitiveForm.value.primitive, + primitive_params: this.objectPrimitiveParams + }; + if (this.primitiveType === 'VNF_Primitive') { + // tslint:disable-next-line: no-string-literal + primitiveParamsPayLoads['vnf_member_index'] = this.primitiveForm.value.vnf_member_index; + } + const apiURLHeader: APIURLHEADER = { + url: environment.NSDINSTANCES_URL + '/' + this.nsdId + '/action' + }; + this.isLoadingResults = true; + this.restService.postResource(apiURLHeader, primitiveParamsPayLoads).subscribe((result: {}) => { + this.activeModal.dismiss(); + this.notifierService.notify('success', this.translateService.instant('PAGE.NSPRIMITIVE.EXECUTEDSUCCESSFULLY')); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + }); + } + /** Primitive type change event @public */ + public primitiveTypeChange(data: { value: string }): void { + this.primitiveList = []; + this.primitiveParameter = []; + this.initializeForm(); + if (data.value === 'NS_Primitive') { + this.primitiveList = !isNullOrUndefined(this.params.nsConfig['config-primitive']) ? + this.params.nsConfig['config-primitive'] : []; + this.getFormControl('vnf_member_index').setValidators([]); + } + } + /** Member index change event */ + public indexChange(data: {}): void { + if (data) { + this.getVnfdInfo(data['vnfd-id-ref']); + } else { + this.primitiveList = []; + this.getFormControl('primitive').setValue(null); + this.primitiveParameter = []; + } + } + /** Primivtive change event */ + public primitiveChange(data: { parameter: {}[] }): void { + this.primitiveParameter = []; + const formArr: FormArray = this.getFormControl('primitive_params') as FormArray; + formArr.controls = []; + this.createPrimitiveParams(); + if (data) { + this.updatePrimitive(data); + } + } + /** Update primitive value based on parameter */ + private updatePrimitive(primitive: { parameter: {}[] }): void { + if (primitive.parameter) { + this.primitiveParameter = primitive.parameter; + } else { + this.primitiveParameter = []; + const formArr: AbstractControl[] = this.getControls(); + formArr.forEach((formGp: FormGroup) => { + formGp.controls.primitive_params_name.setValidators([]); + formGp.controls.primitive_params_name.updateValueAndValidity(); + formGp.controls.primitive_params_value.setValidators([]); + formGp.controls.primitive_params_value.updateValueAndValidity(); + }); + } + } + /** Get primivitive actions from vnfd data */ + private getVnfdInfo(vnfdRef: string): void { + this.primitiveList = []; + this.primitiveParameter = []; + this.getFormControl('primitive').setValue(null); + const apiUrl: string = environment.VNFPACKAGES_URL + '?short-name=' + vnfdRef; + this.isLoadingResults = true; + this.restService.getResource(apiUrl) + .subscribe((vnfdInfo: {}) => { + if (vnfdInfo[0]['vnf-configuration']) { + this.primitiveList = vnfdInfo[0]['vnf-configuration']['config-primitive']; + } + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }); + } + /** Used to get the AbstractControl of controlName passed @private */ + private getFormControl(controlName: string): AbstractControl { + return this.primitiveForm.controls[controlName]; + } +} diff --git a/src/app/instances/ns-topology/NSTopologyComponent.html b/src/app/instances/ns-topology/NSTopologyComponent.html new file mode 100644 index 0000000..0a3051c --- /dev/null +++ b/src/app/instances/ns-topology/NSTopologyComponent.html @@ -0,0 +1,173 @@ + + + + + + + + +
+ +
+
+
+
+
+
+
+
+ +
+
+
+ + +
VNFR
+ + +
VL
+ + +
CP
+
+
+
+
+ +
+
+
+
+
+ \ No newline at end of file diff --git a/src/app/instances/ns-topology/NSTopologyComponent.scss b/src/app/instances/ns-topology/NSTopologyComponent.scss new file mode 100644 index 0000000..d750ccc --- /dev/null +++ b/src/app/instances/ns-topology/NSTopologyComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/instances/ns-topology/NSTopologyComponent.ts b/src/app/instances/ns-topology/NSTopologyComponent.ts new file mode 100644 index 0000000..44c6309 --- /dev/null +++ b/src/app/instances/ns-topology/NSTopologyComponent.ts @@ -0,0 +1,573 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file NS Topology Component + */ +/* tslint:disable:no-increment-decrement */ +import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { ERRORDATA } from 'CommonModel'; +import * as d3 from 'd3'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import { VNFDCONNECTIONPOINTREF } from 'NSDModel'; +import { COMPOSERNODES, CONNECTIONPOINT, NSD, NSDVLD, NSINFO, NSInstanceDetails, NSINSTANCENODES, VLINFO, VNFRINFO } from 'NSInstanceModel'; +import { GRAPHDETAILS, Tick, TickPath } from 'NSTopologyModel'; +import { RestService } from 'src/services/RestService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes NSTopologyComponent.html as template url + */ +@Component({ + selector: 'app-ns-topology', + templateUrl: './NSTopologyComponent.html', + styleUrls: ['./NSTopologyComponent.scss'], + encapsulation: ViewEncapsulation.None +}) +/** Exporting a class @exports NSTopologyComponent */ +export class NSTopologyComponent { + /** Injector to invoke other services @public */ + public injector: Injector; + /** View child contains graphContainer ref @public */ + @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef; + /** Holds the basic information of NS @public */ + public nsInfo: NSINFO; + /** Contains tranlsate instance @private */ + public translateService: TranslateService; + /** Add the activeclass for the selected @public */ + public activeClass: string = 'active'; + /** Add the fixed class for the freeze @public */ + public fixedClass: string = 'fixed'; + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + /** Assign the forcesimulation active @public */ + public forceSimulationActive: boolean = false; + /** Assign pinned class for the button when freezed @public */ + public classApplied: boolean = false; + /** Contains sidebar open status @public */ + public sideBarOpened: boolean = true; + /** Need to show the NS Details @public */ + public isShowNSDetails: boolean = true; + /** Need to show the VL Details @public */ + public isShowVLetails: boolean = false; + /** Need to show the VNFR Details @public */ + public isShowVNFRDetails: boolean = false; + /** Show right side info of Virtual Link @public */ + public virtualLink: VLINFO; + /** Show right side info of Virtual Link @public */ + public vnfr: VNFRINFO; + + /** Contains lastkeypressed instance @private */ + private lastKeyDown: number = -1; + /** Instance of the rest service @private */ + private restService: RestService; + /** Holds the instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + /** Holds the NS Id @private */ + private nsIdentifier: string; + /** Contains SVG attributes @private */ + // tslint:disable-next-line:no-any + private svg: any; + /** Contains forced node animations @private */ + // tslint:disable-next-line:no-any + private force: any; + /** Contains path information of the node */ + // tslint:disable-next-line:no-any + private path: any; + /** Contains node network @private */ + // tslint:disable-next-line:no-any + private network: any; + /** Contains node square @private */ + // tslint:disable-next-line:no-any + private square: any; + /** Contains node circle @private */ + // tslint:disable-next-line:no-any + private circle: any; + /** Contains the NS information @private */ + private nsData: NSInstanceDetails; + /** Contains NDS information of a descriptors */ + private nsdData: NSD; + /** Contains node information @private */ + private nodes: NSINSTANCENODES[] = []; + /** Contains links information @private */ + private links: {}[] = []; + /** holds cp count/iteration @private */ + private cpCount: number; + /** VNFD nodes @private */ + private vnfdNodes: {}[] = []; + /** VLD nodes @private */ + private vldNodes: {}[] = []; + /** Connection CP nodes @private */ + private cpNodes: {}[] = []; + /** Set timeout @private */ + private TIMEOUT: number = 2000; + /** Rendered nodes represent vnf @private */ + // tslint:disable-next-line:no-any + private gSquare: any; + /** Rendered nodes represent network @private */ + // tslint:disable-next-line:no-any + private gNetwork: any; + /** Rendered nodes represent network @private */ + // tslint:disable-next-line:no-any + private gCircle: any; + /** Service holds the router information @private */ + private router: Router; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.translateService = this.injector.get(TranslateService); + this.router = this.injector.get(Router); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate @public + */ + public ngOnInit(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.nsIdentifier = this.activatedRoute.snapshot.paramMap.get('id'); + this.generateData(); + } + /** Event to freeze the animation @public */ + public onFreeze(): void { + this.classApplied = !this.classApplied; + const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass); + d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive); + if (alreadyFixedIsActive) { + this.force.stop(); + } + this.forceSimulationActive = alreadyFixedIsActive; + this.nodes.forEach((d: COMPOSERNODES) => { + d.fx = (alreadyFixedIsActive) ? null : d.x; + d.fy = (alreadyFixedIsActive) ? null : d.y; + }); + if (alreadyFixedIsActive) { + this.force.restart(); + } + } + /** Events handles when dragended @public */ + public toggleSidebar(): void { + this.sideBarOpened = !this.sideBarOpened; + this.deselectAllNodes(); + this.showRightSideInfo(true, false, false); + } + /** Get the default Configuration of containers @private */ + private getGraphContainerAttr(): GRAPHDETAILS { + return { + width: 700, + height: 400, + nodeHeight: 50, + nodeWidth: 35, + textX: -35, + textY: 30, + radius: 5, + distance: 50, + strength: -500, + forcex: 2, + forcey: 2, + sourcePaddingYes: 17, + sourcePaddingNo: 12, + targetPaddingYes: 4, + targetPaddingNo: 3, + alphaTarget: 0.3, + imageX: -25, + imageY: -25, + shiftKeyCode: 17 + }; + } + /** Show the right-side information @private */ + private showRightSideInfo(nsDetails: boolean, vlDetails: boolean, vnfrDeails: boolean): void { + this.isShowNSDetails = nsDetails; + this.isShowVLetails = vlDetails; + this.isShowVNFRDetails = vnfrDeails; + } + /** De-select all the selected nodes @private */ + private deselectAllNodes(): void { + this.square.select('image').classed(this.activeClass, false); + this.network.select('image').classed(this.activeClass, false); + this.circle.select('image').classed(this.activeClass, false); + } + /** Prepare all the information for node creation @private */ + private generateData(): void { + this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.nsIdentifier).subscribe((nsData: NSInstanceDetails) => { + this.nsData = nsData; + this.nsInfo = { + nsInstanceID: nsData._id, + nsName: nsData.name, + nsOperationalStatus: nsData['operational-status'], + nsConfigStatus: nsData['config-status'], + nsDetailedStatus: nsData['detailed-status'], + nsResourceOrchestrator: nsData['resource-orchestrator'] + }; + if (this.nsData['constituent-vnfr-ref'] !== undefined) { + this.generateVNFRCPNodes(); + } + if (this.nsData.vld !== undefined) { + this.generateVLDNetworkNodes(); + } + setTimeout(() => { + this.pushAllNodes(); + this.generateVNFDCP(); + this.generateVLDCP(); + this.isLoadingResults = false; + this.createNode(this.nodes, this.links); + }, this.TIMEOUT); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + }); + } + + /** Fetching all the VNFR Information @private */ + private generateVNFRCPNodes(): void { + this.nsData['constituent-vnfr-ref'].forEach((vnfdrID: string) => { + this.restService.getResource(environment.VNFINSTANCES_URL + '/' + vnfdrID).subscribe((vndfrDetail: NSD) => { + this.nodes.push({ + id: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'], + nodeTypeRef: 'vnfd', + cp: vndfrDetail['connection-point'], + vdur: vndfrDetail.vdur, + vld: vndfrDetail.vld, + nsID: vndfrDetail['nsr-id-ref'], + vnfdID: vndfrDetail['vnfd-id'], + vimID: vndfrDetail['vim-account-id'], + vndfrID: vndfrDetail.id, + ipAddress: vndfrDetail['ip-address'], + memberIndex: vndfrDetail['member-vnf-index-ref'], + vnfdRef: vndfrDetail['vnfd-ref'], + selectorId: 'nsInst-' + vndfrDetail.id + }); + // Fetching all the connection point of VNF & Interface + vndfrDetail['connection-point'].forEach((cp: CONNECTIONPOINT) => { + this.nodes.push({ + id: cp.name + ':' + vndfrDetail['member-vnf-index-ref'], + vndfCPRef: vndfrDetail['vnfd-ref'] + ':' + vndfrDetail['member-vnf-index-ref'], + nodeTypeRef: 'cp', + name: cp.name + }); + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + }); + } + + /** Fetching all the VLD/Network Information @private */ + private generateVLDNetworkNodes(): void { + this.nsdData = this.nsData.nsd; + this.nsdData.vld.forEach((ref: NSDVLD) => { + this.nodes.push({ + id: ref.id, + nodeTypeRef: 'vld', + name: ref.name, + type: ref.type, + vnfdCP: ref['vnfd-connection-point-ref'], + vimNetworkName: ref['vim-network-name'], + shortName: ref['short-name'], + selectorId: 'nsInst-' + ref.id + }); + }); + } + + /** Pushing connection points of path/links nodes @private */ + private pushAllNodes(): void { + this.nodes.forEach((nodeList: NSINSTANCENODES) => { + if (nodeList.nodeTypeRef === 'vnfd') { + this.vnfdNodes.push(nodeList); + } else if (nodeList.nodeTypeRef === 'vld') { + this.vldNodes.push(nodeList); + } else if (nodeList.nodeTypeRef === 'cp') { + this.cpNodes.push(nodeList); + } + }); + } + + /** Get CP position based on vndf @private */ + private generateVNFDCP(): void { + this.vnfdNodes.forEach((list: NSINSTANCENODES) => { + const vndfPos: number = this.nodes.map((e: NSINSTANCENODES) => { return e.id; }).indexOf(list.id); + this.cpCount = 0; + this.nodes.forEach((res: NSINSTANCENODES) => { + if (res.nodeTypeRef === 'cp' && res.vndfCPRef === list.id) { + this.links.push({ source: this.nodes[vndfPos], target: this.nodes[this.cpCount] }); + } + this.cpCount++; + }); + }); + } + + /** Get CP position based on vld @private */ + private generateVLDCP(): void { + let vldPos: number = 0; + this.vldNodes.forEach((list: NSINSTANCENODES) => { + if (!isNullOrUndefined(list.vnfdCP)) { + list.vnfdCP.forEach((cpRef: VNFDCONNECTIONPOINTREF) => { + this.cpCount = 0; + this.nodes.forEach((res: NSINSTANCENODES) => { + if (res.nodeTypeRef === 'cp' && res.id === cpRef['vnfd-connection-point-ref'] + ':' + cpRef['member-vnf-index-ref']) { + this.links.push({ source: this.nodes[vldPos], target: this.nodes[this.cpCount] }); + } + this.cpCount++; + }); + }); + vldPos++; + } + }); + } + + /** Node is created and render at D3 region @private */ + private createNode(nodes: NSINSTANCENODES[], links: {}[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + d3.selectAll('svg#graphContainer > *').remove(); + d3.select(window).on('keydown', () => { this.keyDown(); }); + d3.select(window).on('keyup', () => { this.keyUp(); }); + this.svg = d3.select('#graphContainer') + .attr('oncontextmenu', 'return false;') + .attr('width', graphContainerAttr.width) + .attr('height', graphContainerAttr.height); + this.force = d3.forceSimulation() + .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength)) + .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance)) + .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex, + graphContainerAttr.height / graphContainerAttr.forcey)) + .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex)) + .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey)) + .on('tick', () => { this.tick(); }); + // handles to link and node element groups + this.path = this.svg.append('svg:g').selectAll('path'); + this.network = this.svg.append('svg:g').selectAll('network'); + this.square = this.svg.append('svg:g').selectAll('rect'); + this.circle = this.svg.append('svg:g').selectAll('circle'); + this.restart(nodes, links); + } + + /** Update force layout (called automatically each iteration) @private */ + private tick(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + // draw directed edges with proper padding from node centers + this.path.attr('class', 'link').attr('d', (d: Tick) => { + const deltaX: number = d.target.x - d.source.x; + const deltaY: number = d.target.y - d.source.y; + const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + const normX: number = deltaX / dist; + const normY: number = deltaY / dist; + const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo; + const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo; + const sourceX: number = d.source.x + (sourcePadding * normX); + const sourceY: number = d.source.y + (sourcePadding * normY); + const targetX: number = d.target.x - (targetPadding * normX); + const targetY: number = d.target.y - (targetPadding * normY); + return `M${sourceX},${sourceY}L${targetX},${targetY}`; + }); + this.network.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + this.square.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + this.circle.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + } + + /** Update graph (called when needed) @private */ + private restart(nodes: NSINSTANCENODES[], links: {}[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.path = this.path.data(links); + const vnfdNodes: {}[] = []; const vldNodes: {}[] = []; const cpNodes: {}[] = []; // NB: Nodes are known by id, not by index! + nodes.forEach((nodeList: NSINSTANCENODES) => { + if (nodeList.nodeTypeRef === 'vnfd') { vnfdNodes.push(nodeList); } + else if (nodeList.nodeTypeRef === 'vld') { vldNodes.push(nodeList); } + else if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); } + }); + this.square = this.square.data(vnfdNodes, (d: { id: number }) => d.id); + this.network = this.network.data(vldNodes, (d: { id: number }) => d.id); + this.circle = this.circle.data(cpNodes, (d: { id: number }) => d.id); + this.resetAndCreateNodes(); + this.force.nodes(nodes).force('link').links(links); //Set the graph in motion + this.force.alphaTarget(graphContainerAttr.alphaTarget).restart(); + } + + /** Rest and create nodes @private */ + private resetAndCreateNodes(): void { + this.path.exit().remove(); + this.square.exit().remove(); + this.network.exit().remove(); + this.circle.exit().remove(); + // tslint:disable-next-line:no-any + const gPath: any = this.path.enter().append('svg:path').attr('class', 'link'); + this.getgSquare(); + this.getgNetwork(); + this.getgCircle(); + this.square = this.gSquare.merge(this.square); + this.network = this.gNetwork.merge(this.network); + this.path = gPath.merge(this.path); + this.circle = this.gCircle.merge(this.circle); + } + + /** Events handles when Shift Click to perform create cp @private */ + // tslint:disable-next-line: no-any + private singleClick(nodeSelected: any, d: COMPOSERNODES): void { + this.selectNodeExclusive(nodeSelected, d); + } + /** Selected nodes @private */ + // tslint:disable-next-line: no-any + private selectNodeExclusive(nodeSelected: any, d: COMPOSERNODES): void { + const alreadyIsActive: boolean = nodeSelected.select('#' + d.selectorId).classed(this.activeClass); + this.deselectAllNodes(); + nodeSelected.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive); + if (d.nodeTypeRef === 'vld' && !alreadyIsActive) { + this.virtualLink = { + id: d.id, + name: d.name, + type: d.type, + shortName: d.shortName, + vimNetworkName: d.vimNetworkName + }; + this.showRightSideInfo(false, true, false); + } else if (d.nodeTypeRef === 'vnfd' && !alreadyIsActive) { + this.vnfr = { + vimID: d.vimID, + _id: d.vndfrID, + ip: d.ipAddress, + nsrID: d.nsID, + id: d.selectorId, + vnfdRef: d.vnfdRef, + vnfdId: d.vnfdID, + memberIndex: d.memberIndex + }; + this.showRightSideInfo(false, false, true); + } else { + this.showRightSideInfo(true, false, false); + } + } + /** Setting all the square/vnf attributes of nodes @private */ + private getgSquare(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gSquare = this.square.enter().append('svg:g'); + this.gSquare.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gSquare.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: COMPOSERNODES) => { return d.selectorId; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/VNFD.svg') + .on('click', (d: COMPOSERNODES) => { this.singleClick(this.gSquare, d); this.onNodeClickToggleSidebar(); }); + this.gSquare.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.id); + } + + /** Settings all the network attributes of nodes @private */ + private getgNetwork(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gNetwork = this.network.enter().append('svg:g'); + this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gNetwork.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: COMPOSERNODES) => { return d.selectorId; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/VL.svg') + .on('click', (d: COMPOSERNODES) => { this.singleClick(this.gNetwork, d); this.onNodeClickToggleSidebar(); }); + this.gNetwork.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.name); + } + + /** Settings all the connection point attributes of nodes @private */ + private getgCircle(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gCircle = this.circle.enter().append('svg:g'); + this.gCircle.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gCircle.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/CP.svg'); + this.gCircle.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.name); + } + + /** Key press event @private */ + private keyDown(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + if (this.lastKeyDown !== -1) { return; } + this.lastKeyDown = d3.event.keyCode; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gSquare.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.gNetwork.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.gCircle.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.svg.classed('ctrl', true); + } + } + /** Key realse event @private */ + private keyUp(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.lastKeyDown = -1; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gSquare.on('.drag', null); + this.gNetwork.on('.drag', null); + this.gCircle.on('.drag', null); + this.svg.classed('ctrl', false); + } + } + /** Events handles when dragstarted @private */ + private dragstarted(d: COMPOSERNODES): void { + d.fx = d.x; + d.fy = d.y; + } + /** Events handles when dragged @private */ + private dragged(d: COMPOSERNODES): void { + d.fx = d.x = d3.event.x; + d.fy = d.y = d3.event.y; + } + /** Events handles when dragended @private */ + private dragended(d: COMPOSERNODES): void { + if (this.forceSimulationActive) { + d.fx = null; + d.fy = null; + } else { + d.fx = d.x; + d.fy = d.y; + this.forceSimulationActive = false; + } + } + /** Events handles when node single click @private */ + private onNodeClickToggleSidebar(): void { + this.sideBarOpened = true; + } +} diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.html b/src/app/instances/pdu-instances/PDUInstancesComponent.html new file mode 100644 index 0000000..3c18bfa --- /dev/null +++ b/src/app/instances/pdu-instances/PDUInstancesComponent.html @@ -0,0 +1,36 @@ + +
+
{{'PDUINSTANCES' | translate}}
+ + + +
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.scss b/src/app/instances/pdu-instances/PDUInstancesComponent.scss new file mode 100644 index 0000000..0ecd95d --- /dev/null +++ b/src/app/instances/pdu-instances/PDUInstancesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ \ No newline at end of file diff --git a/src/app/instances/pdu-instances/PDUInstancesComponent.ts b/src/app/instances/pdu-instances/PDUInstancesComponent.ts new file mode 100644 index 0000000..20b44df --- /dev/null +++ b/src/app/instances/pdu-instances/PDUInstancesComponent.ts @@ -0,0 +1,197 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file PDU Instance Component + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { AddPDUInstancesComponent } from 'AddPDUInstancesComponent'; +import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { PDUInstanceDetails } from 'PDUInstanceModel'; +import { PDUInstancesActionComponent } from 'PDUInstancesActionComponent'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes PDUInstancesComponent.html as template url + */ +@Component({ + templateUrl: './PDUInstancesComponent.html', + styleUrls: ['./PDUInstancesComponent.scss'] +}) +/** Exporting a class @exports PDUInstancesComponent */ +export class PDUInstancesComponent implements OnInit, OnDestroy { + /** Injector to invoke other services @public */ + public injector: Injector; + + /** NS Instance array @public */ + public pduInstanceData: object[] = []; + + /** Datasource instance @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** SelectedRows array @public */ + public selectedRows: object[] = []; + + /** Selected list array @public */ + public selectList: object[] = []; + + /** Instance component are stored in settings @public */ + public settings: {} = {}; + + /** Contains objects for menu settings @public */ + public columnList: {} = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + columns: this.columnList, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnList = { + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' }, + name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + type: { title: this.translateService.instant('TYPE'), width: '15%' }, + usageState: { title: this.translateService.instant('USAGESTATE'), width: '15%' }, + CreatedAt: { title: this.translateService.instant('CREATEDAT'), width: '15%' }, + Actions: { + name: 'Action', width: '10%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: PDUInstanceDetails, row: PDUInstanceDetails): PDUInstanceDetails => row, + renderComponent: PDUInstancesActionComponent + } + }; + } + + /** generateData initiate the ns-instance list @public */ + public generateData(): void { + this.pduInstanceData = []; + this.isLoadingResults = true; + this.restService.getResource(environment.PDUINSTANCE_URL).subscribe((pduInstancesData: PDUInstanceDetails[]) => { + pduInstancesData.forEach((pduInstanceData: PDUInstanceDetails) => { + const pduDataObj: {} = { + name: pduInstanceData.name, + identifier: pduInstanceData._id, + type: pduInstanceData.type, + usageState: pduInstanceData._admin.usageState, + CreatedAt: this.sharedService.convertEpochTime(Number(pduInstanceData._admin.created)) + }; + this.pduInstanceData.push(pduDataObj); + }); + if (this.pduInstanceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.pduInstanceData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'pdu-instances' }); + this.dataService.changeMessage(event.data); + } + + /** Add PDU Instance modal using modalservice @public */ + public addPDUInstanceModal(): void { + const modalRef: NgbModalRef = this.modalService.open(AddPDUInstancesComponent, { backdrop: 'static' }); + modalRef.componentInstance.title = this.translateService.instant('PAGE.PDUINSTANCE.NEWPDUINSTANCE'); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.generateData(); + } + }).catch(); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } +} diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html new file mode 100644 index 0000000..f785426 --- /dev/null +++ b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.html @@ -0,0 +1,95 @@ + + +
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss new file mode 100644 index 0000000..950bb39 --- /dev/null +++ b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.scss @@ -0,0 +1,34 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +@import '../../../../assets/scss/mixins/mixin'; +@import '../../../../assets/scss/variable'; + +.head { + @include padding-value(10, 10, 10, 10); + line-height: 2em; + .btn-params { + @include border(all, 1, solid, $white); + } +} + +.remove-params { + display: flex; + align-items: center; + font-size: 20px; + cursor: pointer; +} \ No newline at end of file diff --git a/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts new file mode 100644 index 0000000..0dcbb60 --- /dev/null +++ b/src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent.ts @@ -0,0 +1,197 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file ADD PDU Instances Component + */ +import { Component, Injector, Input, OnInit, Output } from '@angular/core'; +import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { PDUInstanceDetails } from 'PDUInstanceModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { VimAccountDetails } from 'VimAccountModel'; + +/** + * Creating component + * @Component takes AddPDUInstancesComponent.html as template url + */ +@Component({ + templateUrl: './AddPDUInstancesComponent.html', + styleUrls: ['./AddPDUInstancesComponent.scss'] +}) +/** Exporting a class @exports AddPDUInstancesComponent */ +export class AddPDUInstancesComponent implements OnInit { + /** Form valid on submit trigger @public */ + public submitted: boolean = false; + + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup instance added to the form @ html @public */ + public pduInstancesForm: FormGroup; + + /** Primitive params array @public */ + public pduInterfaces: FormArray; + + /** Variable set for twoway binding @public */ + public pduInstanceId: string; + + /** Set mgmt field to empty on load @public */ + public selectedMgmt: string; + + /** Set vim field to empty on load @public */ + public selectedVIM: string; + + /** Contains boolean value as select options for mgmt @public */ + public mgmtState: {}[] = [{ name: 'True', value: true }, { name: 'False', value: false }]; + + /** Input contains Modal dialog component Instance @private */ + @Input() public title: string; + + /** Contains all the vim accounts list @public */ + public vimAccountSelect: VimAccountDetails; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** packages data service collections @private */ + private dataService: DataService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); + this.sharedService = this.injector.get(SharedService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + /** Setting up initial value for NSD */ + this.dataService.currentMessage.subscribe((event: PDUInstanceDetails) => { + if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) { + this.pduInstanceId = event.identifier; + } + }); + this.generateVIMAccounts(); + this.initializeForm(); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.pduInstancesForm.controls; } + + /** initialize Forms @public */ + public initializeForm(): void { + this.pduInstancesForm = this.formBuilder.group({ + name: ['', [Validators.required]], + type: ['', [Validators.required]], + vim_accounts: ['', [Validators.required]], + interfaces: this.formBuilder.array([this.interfacesBuilder()]) + }); + } + + /** Generate interfaces fields @public */ + public interfacesBuilder(): FormGroup { + return this.formBuilder.group({ + name: ['', [Validators.required]], + 'ip-address': ['', [Validators.required, Validators.pattern(this.sharedService.REGX_IP_PATTERN)]], + mgmt: ['', [Validators.required]], + 'vim-network-name': ['', [Validators.required]] + }); + } + + /** Handle FormArray Controls @public */ + public getControls(): AbstractControl[] { + // tslint:disable-next-line:no-backbone-get-set-outside-model + return (this.pduInstancesForm.get('interfaces') as FormArray).controls; + } + + /** Push all primitive params on user's action @public */ + public createInterfaces(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.pduInterfaces = this.pduInstancesForm.get('interfaces') as FormArray; + this.pduInterfaces.push(this.interfacesBuilder()); + } + + /** Remove interfaces on user's action @public */ + public removeInterfaces(index: number): void { + this.pduInterfaces.removeAt(index); + } + + /** Execute New PDU Instances @public */ + public createPDUInstances(): void { + this.submitted = true; + this.sharedService.cleanForm(this.pduInstancesForm); + if (this.pduInstancesForm.invalid) { return; } // Proceed, onces form is valid + this.isLoadingResults = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + const apiURLHeader: APIURLHEADER = { + url: environment.PDUINSTANCE_URL + }; + this.restService.postResource(apiURLHeader, this.pduInstancesForm.value).subscribe((result: {}) => { + this.activeModal.close(modalData); + this.notifierService.notify('success', this.translateService.instant('PAGE.PDUINSTANCE.CREATEDSUCCESSFULLY')); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Generate vim accounts list @public */ + public generateVIMAccounts(): void { + this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimData: VimAccountDetails) => { + this.vimAccountSelect = vimData; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } +} diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.html b/src/app/instances/vnf-instances/VNFInstancesComponent.html new file mode 100644 index 0000000..e36cc3d --- /dev/null +++ b/src/app/instances/vnf-instances/VNFInstancesComponent.html @@ -0,0 +1,29 @@ + +
+
{{'VNFINSTANCES' | translate}}
+
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.scss b/src/app/instances/vnf-instances/VNFInstancesComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/instances/vnf-instances/VNFInstancesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/instances/vnf-instances/VNFInstancesComponent.ts b/src/app/instances/vnf-instances/VNFInstancesComponent.ts new file mode 100644 index 0000000..d829ee2 --- /dev/null +++ b/src/app/instances/vnf-instances/VNFInstancesComponent.ts @@ -0,0 +1,187 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file NVF Instance Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { ERRORDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { VNFInstanceData, VNFInstanceDetails } from 'VNFInstanceModel'; +import { VNFInstancesActionComponent } from 'VNFInstancesActionComponent'; +import { VNFLinkComponent } from 'VNFLinkComponent'; + +/** + * Creating component + * @Component takes VNFInstancesComponent.html as template url + */ +@Component({ + templateUrl: './VNFInstancesComponent.html', + styleUrls: ['./VNFInstancesComponent.scss'] +}) +/** Exporting a class @exports VNFInstancesComponent */ +export class VNFInstancesComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** smart table data service collections @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Instance component are stored in settings @public */ + public settings: {} = {}; + + /** Contains objects for menu settings @public */ + public columnList: {} = {}; + + /** vnf instance array @public */ + public vnfInstanceData: {}[] = []; + + /** selected rows array @public */ + public selectedRows: string[] = []; + + /** selected list array @public */ + public selectList: string[] = []; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** packages data service collections @private */ + private dataService: DataService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + actions: { add: false, edit: false, delete: false, position: 'right' }, + columns: this.columnList, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnList = { + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%', sortDirection: 'asc' }, + VNFD: { + title: this.translateService.instant('VNFD'), width: '20%', type: 'custom', + valuePrepareFunction: (cell: VNFInstanceData, row: VNFInstanceData): VNFInstanceData => row, + renderComponent: VNFLinkComponent + }, + MemberIndex: { title: this.translateService.instant('MEMBERINDEX'), width: '15%' }, + NS: { title: this.translateService.instant('NS'), width: '20%' }, + CreatedAt: { title: this.translateService.instant('CREATEDAT'), width: '15%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: VNFInstanceData, row: VNFInstanceData): VNFInstanceData => row, + renderComponent: VNFInstancesActionComponent + } + }; + } + + /** generateData initiate the vnf-instance list */ + public generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.VNFINSTANCES_URL).subscribe((vnfInstancesData: VNFInstanceDetails[]) => { + this.vnfInstanceData = []; + vnfInstancesData.forEach((vnfInstanceData: VNFInstanceDetails) => { + const vnfDataObj: {} = + { + VNFD: vnfInstanceData['vnfd-ref'], + identifier: vnfInstanceData._id, + MemberIndex: vnfInstanceData['member-vnf-index-ref'], + NS: vnfInstanceData['nsr-id-ref'], + VNFID: vnfInstanceData['vnfd-id'], + CreatedAt: this.sharedService.convertEpochTime(Number(vnfInstanceData['created-time'])) + }; + this.vnfInstanceData.push(vnfDataObj); + }); + if (this.vnfInstanceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.vnfInstanceData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'vnf-instance' }); + this.dataService.changeMessage(event.data); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } +} diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html new file mode 100644 index 0000000..450e8a3 --- /dev/null +++ b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.html @@ -0,0 +1,18 @@ + +{{value.VNFD}} diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts new file mode 100644 index 0000000..15ea6ff --- /dev/null +++ b/src/app/instances/vnf-instances/vnf-link/VNFLinkComponent.ts @@ -0,0 +1,46 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file VNFD Link Component. + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { VNFInstanceData } from 'VNFInstanceModel'; +/** + * Creating component + * @Component takes VNFLinkComponent.html as template url + */ +@Component({ + selector: 'app-vnf-link', + templateUrl: './VNFLinkComponent.html', + styleUrls: ['./VNFLinkComponent.scss'] +}) +/** Exporting a class @exports VnfLinkComponent */ +export class VNFLinkComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + /** To get the value from the VNFInstance via valuePrepareFunction default Property of ng-smarttable @public */ + public value: VNFInstanceData; + constructor(injector: Injector) { + this.injector = injector; + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + //empty + } + +} diff --git a/src/app/k8s/K8sComponent.html b/src/app/k8s/K8sComponent.html new file mode 100644 index 0000000..3f96ff8 --- /dev/null +++ b/src/app/k8s/K8sComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/k8s/K8sComponent.scss b/src/app/k8s/K8sComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/k8s/K8sComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/k8s/K8sComponent.ts b/src/app/k8s/K8sComponent.ts new file mode 100644 index 0000000..5427a8f --- /dev/null +++ b/src/app/k8s/K8sComponent.ts @@ -0,0 +1,56 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file k8s.ts. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; +/** + * Creating Component + * @Component takes K8sComponent.html as template url + */ +@Component({ + selector: 'app-k8s', + templateUrl: './K8sComponent.html', + styleUrls: ['./K8sComponent.scss'] +}) +/** Exporting a class @exports K8sComponent */ +export class K8sComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** creates k8s component */ + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/k8s') { + this.router.navigate(['/k8s/cluster']).catch(); + } + } + +} diff --git a/src/app/k8s/K8sModule.ts b/src/app/k8s/K8sModule.ts new file mode 100644 index 0000000..51f27b2 --- /dev/null +++ b/src/app/k8s/K8sModule.ts @@ -0,0 +1,106 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file K8s Module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataService } from 'DataService'; +import { K8sActionComponent } from 'K8sActionComponent'; +import { K8sAddClusterComponent } from 'K8sAddClusterComponent'; +import { K8sAddRepoComponent } from 'K8sAddRepoComponent'; +import { K8sClusterComponent } from 'K8sClusterComponent'; +import { K8sComponent } from 'K8sComponent'; +import { K8sRepositoryComponent } from 'K8sRepositoryComponent'; +import { LoaderModule } from 'LoaderModule'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** + * configures routers + */ +const routes: Routes = [ + { + path: '', + component: K8sComponent, + children: [ + { + path: 'cluster', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'PAGE.K8S.MENUK8SCLUSTER', url: null }] + }, + component: K8sClusterComponent + }, + { + path: 'repo', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'PAGE.K8S.MENUK8SREPO', url: null }] + }, + component: K8sRepositoryComponent + } + ] + } +]; +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ + ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), + FormsModule, + CommonModule, + HttpClientModule, + NgSelectModule, + Ng2SmartTableModule, + TranslateModule, + RouterModule.forChild(routes), + NgbModule, + PagePerRowModule, + LoaderModule, + PageReloadModule + ], + declarations: [ + K8sComponent, + K8sClusterComponent, + K8sRepositoryComponent, + K8sActionComponent, + K8sAddClusterComponent, + K8sAddRepoComponent + ], + providers: [DataService], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + entryComponents: [K8sActionComponent, K8sAddClusterComponent, K8sAddRepoComponent] +}) +/** Exporting a class @exports K8sModule */ +export class K8sModule { + /** Variables declared to avoid state-less class */ + private k8sModule: string; +} diff --git a/src/app/k8s/k8s-action/K8sActionComponent.html b/src/app/k8s/k8s-action/K8sActionComponent.html new file mode 100644 index 0000000..c35bb19 --- /dev/null +++ b/src/app/k8s/k8s-action/K8sActionComponent.html @@ -0,0 +1,27 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/k8s/k8s-action/K8sActionComponent.scss b/src/app/k8s/k8s-action/K8sActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/k8s/k8s-action/K8sActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/k8s/k8s-action/K8sActionComponent.ts b/src/app/k8s/k8s-action/K8sActionComponent.ts new file mode 100644 index 0000000..a524277 --- /dev/null +++ b/src/app/k8s/k8s-action/K8sActionComponent.ts @@ -0,0 +1,103 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file K8 Action Component + */ +import { Component, Injector } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { K8SCLUSTERDATADISPLAY, K8SREPODATADISPLAY } from 'K8sModel'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; +/** + * Creating component + * @Component takes K8sActionComponent.html as template url + */ +@Component({ + selector: 'app-k8s-action', + templateUrl: './K8sActionComponent.html', + styleUrls: ['./K8sActionComponent.scss'] +}) +/** Exporting a class @exports K8sActionComponent */ +export class K8sActionComponent{ + /** To inject services @public */ + public injector: Injector; + + /** To get the value from the Users action via valuePrepareFunction default Property of ng-smarttable @public */ + public value: K8SCLUSTERDATADISPLAY | K8SREPODATADISPLAY; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Contains K8s Type @private */ + public getK8sType: string; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains instance ID @private */ + private instanceID: string; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.instanceID = this.value.identifier; + this.getK8sType = this.value.pageType; + } + + /** Delete User Account @public */ + public deleteK8s(pageType: string): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Shows information using modalservice @public */ + public infoK8s(pageType: string): void { + let pageName: string = ''; + let title: string = ''; + if (pageType === 'repo') { + pageName = 'k8s-repo'; + title = 'PAGE.K8S.K8SREPODETAILS'; + } else { + pageName = 'k8s-cluster'; + title = 'PAGE.K8S.K8SCLUSTERDETAILS'; + } + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.instanceID, + page: pageName, + titleName: title + }; + } +} diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html new file mode 100644 index 0000000..84f2150 --- /dev/null +++ b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.html @@ -0,0 +1,92 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts new file mode 100644 index 0000000..0295b35 --- /dev/null +++ b/src/app/k8s/k8s-add-cluster/K8sAddClusterComponent.ts @@ -0,0 +1,233 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file K8sAddClusterComponent.ts. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { VimAccountDetails } from 'VimAccountModel'; +/** + * Creating Component + * @Component takes K8sAddClusterComponent.html as template url + */ +@Component({ + selector: 'app-k8s-add-cluster', + templateUrl: './K8sAddClusterComponent.html', + styleUrls: ['./K8sAddClusterComponent.scss'] +}) +/** Exporting a class @exports K8sAddClusterComponent */ +export class K8sAddClusterComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** FormGroup instance added to the form @ html @public */ + public k8sclusterForm: FormGroup; + + /** Contains all vim account collections */ + public vimAccountSelect: VimAccountDetails; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Variable set for twoway bindng @public */ + public vimAccountId: string; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Element ref for fileInputNets @public */ + @ViewChild('fileInputNets', { static: true }) public fileInputNets: ElementRef; + + /** Element ref for fileInputNetsLabel @public */ + @ViewChild('fileInputNetsLabel', { static: true }) public fileInputNetsLabel: ElementRef; + + /** Element ref for fileInputCredentials @public */ + @ViewChild('fileInputCredentials', { static: true }) public fileInputCredentials: ElementRef; + + /** Element ref for fileInputCredentialsLabel @public */ + @ViewChild('fileInputCredentialsLabel', { static: true }) public fileInputCredentialsLabel: ElementRef; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + public ngOnInit(): void { + /** On Initializing call the methods */ + this.k8sclusterFormAction(); + this.getDetailsvimAccount(); + this.headers = new HttpHeaders({ + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** On modal initializing forms @public */ + public k8sclusterFormAction(): void { + this.k8sclusterForm = this.formBuilder.group({ + name: ['', [Validators.required]], + k8s_version: ['', [Validators.required]], + vim_account: [null, [Validators.required]], + description: ['', [Validators.required]], + nets: ['', [Validators.required]], + credentials: ['', [Validators.required]] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.k8sclusterForm.controls; } + + /** Call the vimAccount details in the selection options @public */ + public getDetailsvimAccount(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccounts: VimAccountDetails) => { + this.vimAccountSelect = vimAccounts; + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** On modal submit k8sAddClusterSubmit will called @public */ + public k8sAddClusterSubmit(): void { + this.submitted = true; + this.sharedService.cleanForm(this.k8sclusterForm); + if (this.k8sclusterForm.invalid) { + return; + } + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + const apiURLHeader: APIURLHEADER = { + url: environment.K8SCLUSTER_URL, + httpOptions: { headers: this.headers } + }; + const validJSONCredentails: boolean = this.sharedService.checkJson(this.k8sclusterForm.value.credentials); + if (validJSONCredentails) { + this.k8sclusterForm.value.credentials = jsyaml.load(this.k8sclusterForm.value.credentials.toString(), { json: true }); + } else { + this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG')); + return; + } + const validJSONNets: boolean = this.sharedService.checkJson(this.k8sclusterForm.value.nets); + if (validJSONNets) { + this.k8sclusterForm.value.nets = jsyaml.load(this.k8sclusterForm.value.nets.toString(), { json: true }); + } else { + this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG')); + return; + } + this.isLoadingResults = true; + this.restService.postResource(apiURLHeader, this.k8sclusterForm.value).subscribe((result: {}) => { + this.activeModal.close(modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.k8sclusterForm.value.name + + this.translateService.instant('PAGE.K8S.CREATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Nets file process @private */ + public netsFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'json').then((fileContent: string): void => { + const getNetsJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.k8sclusterForm.get('nets').setValue(JSON.stringify(getNetsJson)); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('JSONFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputNetsLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputNets.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputNetsLabel.nativeElement.innerText = files[0].name; + this.fileInputNets.nativeElement.value = null; + } + + /** credentials file process @private */ + public credentialsFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => { + const getCredentialsJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.k8sclusterForm.get('credentials').setValue(JSON.stringify(getCredentialsJson)); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputCredentialsLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputCredentials.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputCredentialsLabel.nativeElement.innerText = files[0].name; + this.fileInputCredentials.nativeElement.value = null; + } + +} diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html new file mode 100644 index 0000000..8caec5e --- /dev/null +++ b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.html @@ -0,0 +1,68 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss new file mode 100644 index 0000000..fdec4ed --- /dev/null +++ b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ diff --git a/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts new file mode 100644 index 0000000..c8b96bb --- /dev/null +++ b/src/app/k8s/k8s-add-repo/K8sAddRepoComponent.ts @@ -0,0 +1,134 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file k8sAddRepoComponent.ts. + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +/** + * Creating Component + * @Component takes K8sAddRepoComponent.html as template url + */ +@Component({ + selector: 'app-k8s-add-repo', + templateUrl: './K8sAddRepoComponent.html', + styleUrls: ['./K8sAddRepoComponent.scss'] +}) +/** Exporting a class @exports K8sAddRepoComponent */ +export class K8sAddRepoComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** FormGroup instance added to the form @ html @public */ + public k8srepoForm: FormGroup; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Supported Vim type for the dropdown */ + public repoTypeSelect: {}[]; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + public ngOnInit(): void { + this.repoTypeSelect = [ + { id: 'helm-chart', name: 'Helm Chart' }, + { id: 'juju-bundle', name: 'Juju Bundle' } + ]; + /** On Initializing call the methods */ + this.k8srepoFormAction(); + } + + /** On modal initializing forms @public */ + public k8srepoFormAction(): void { + this.k8srepoForm = this.formBuilder.group({ + name: ['', [Validators.required]], + type: [null, [Validators.required]], + url: ['', [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]], + description: ['', [Validators.required]] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.k8srepoForm.controls; } + + /** On modal submit k8sAddRepoSubmit will called @public */ + public k8sAddRepoSubmit(): void { + this.submitted = true; + this.sharedService.cleanForm(this.k8srepoForm); + if (this.k8srepoForm.invalid) { + return; + } + this.isLoadingResults = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + const apiURLHeader: APIURLHEADER = { + url: environment.K8REPOS_URL + }; + this.restService.postResource(apiURLHeader, this.k8srepoForm.value).subscribe((result: {}) => { + this.activeModal.close(modalData); + this.notifierService.notify('success', this.k8srepoForm.value.name + + this.translateService.instant('PAGE.K8S.CREATEDSUCCESSFULLY')); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + }); + } + +} diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.html b/src/app/k8s/k8scluster/K8sClusterComponent.html new file mode 100644 index 0000000..ebed3e4 --- /dev/null +++ b/src/app/k8s/k8scluster/K8sClusterComponent.html @@ -0,0 +1,42 @@ + +
+
{{'PAGE.K8S.REGISTERK8CLUSTER' | translate}}
+ + + +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.scss b/src/app/k8s/k8scluster/K8sClusterComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/k8s/k8scluster/K8sClusterComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/k8s/k8scluster/K8sClusterComponent.ts b/src/app/k8s/k8scluster/K8sClusterComponent.ts new file mode 100644 index 0000000..7ab7583 --- /dev/null +++ b/src/app/k8s/k8scluster/K8sClusterComponent.ts @@ -0,0 +1,236 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file k8sclustercomponent.ts. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { K8sActionComponent } from 'K8sActionComponent'; +import { K8sAddClusterComponent } from 'K8sAddClusterComponent'; +import { K8SCLUSTERDATA, K8SCLUSTERDATADISPLAY } from 'K8sModel'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +/** + * Creating Component + * @Component takes K8sClusterComponent.html as template url + */ +@Component({ + selector: 'app-k8scluster', + templateUrl: './K8sClusterComponent.html', + styleUrls: ['./K8sClusterComponent.scss'] +}) +/** Exporting a class @exports K8sClusterComponent */ +export class K8sClusterComponent implements OnInit, OnDestroy { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Columns list of the smart table @public */ + public columnList: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.k8OperationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.k8OperationalStateStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.k8OperationalStateThirdStep; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private k8sClusterData: {}[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnList = { + name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + version: { title: this.translateService.instant('K8VERSION'), width: '10%' }, + operationalState: { + title: this.translateService.instant('OPERATIONALSTATE'), width: '15%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: K8SCLUSTERDATADISPLAY, row: K8SCLUSTERDATADISPLAY): string => { + if (row.operationalState === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.operationalState}`; + } + } + }, + created: { title: this.translateService.instant('CREATED'), width: '15%' }, + modified: { title: this.translateService.instant('MODIFIED'), width: '15%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: K8SCLUSTERDATADISPLAY, row: K8SCLUSTERDATADISPLAY): K8SCLUSTERDATADISPLAY => row, + renderComponent: K8sActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + columns: this.columnList, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'k8-cluster' }); + this.dataService.changeMessage(event.data); + } + + /** Compose new K8s Cluster Accounts @public */ + public addK8sCluster(): void { + const modalRef: NgbModalRef = this.modalService.open(K8sAddClusterComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Generate nsData object from loop and return for the datasource @public */ + public generateK8sclusterData(k8sClusterdata: K8SCLUSTERDATA): K8SCLUSTERDATADISPLAY { + return { + name: k8sClusterdata.name, + identifier: k8sClusterdata._id, + operationalState: k8sClusterdata._admin.operationalState, + version: k8sClusterdata.k8s_version, + created: this.sharedService.convertEpochTime(Number(k8sClusterdata._admin.created)), + modified: this.sharedService.convertEpochTime(Number(k8sClusterdata._admin.modified)), + pageType: 'cluster' + }; + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.K8SCLUSTER_URL).subscribe((k8sClusterDatas: K8SCLUSTERDATA[]) => { + this.k8sClusterData = []; + k8sClusterDatas.forEach((k8sClusterdata: K8SCLUSTERDATA) => { + const k8sClusterDataObj: K8SCLUSTERDATADISPLAY = this.generateK8sclusterData(k8sClusterdata); + this.k8sClusterData.push(k8sClusterDataObj); + }); + if (this.k8sClusterData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.k8sClusterData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(() => { + this.isLoadingResults = false; + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + +} diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.html b/src/app/k8s/k8srepository/K8sRepositoryComponent.html new file mode 100644 index 0000000..e546356 --- /dev/null +++ b/src/app/k8s/k8srepository/K8sRepositoryComponent.html @@ -0,0 +1,35 @@ + +
+
{{'PAGE.K8S.REGISTERK8REPO' | translate}}
+ + + +
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.scss b/src/app/k8s/k8srepository/K8sRepositoryComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/k8s/k8srepository/K8sRepositoryComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/k8s/k8srepository/K8sRepositoryComponent.ts b/src/app/k8s/k8srepository/K8sRepositoryComponent.ts new file mode 100644 index 0000000..1b6c9f7 --- /dev/null +++ b/src/app/k8s/k8srepository/K8sRepositoryComponent.ts @@ -0,0 +1,198 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file K8sRepositoryComponent.ts. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { K8sActionComponent } from 'K8sActionComponent'; +import { K8sAddRepoComponent } from 'K8sAddRepoComponent'; +import { K8SREPODATA, K8SREPODATADISPLAY } from 'K8sModel'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +/** + * Creating Component + * @Component takes K8sRepositoryComponent.html as template url + */ +@Component({ + selector: 'app-k8srepository', + templateUrl: './K8sRepositoryComponent.html', + styleUrls: ['./K8sRepositoryComponent.scss'] +}) +/** Exporting a class @exports K8sRepositoryComponent */ +export class K8sRepositoryComponent implements OnInit, OnDestroy { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Columns list of the smart table @public */ + public columnList: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private k8sRepoData: {}[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnList = { + name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + url: { title: this.translateService.instant('URL'), width: '15%' }, + type: { title: this.translateService.instant('TYPE'), width: '10%' }, + created: { title: this.translateService.instant('CREATED'), width: '15%' }, + modified: { title: this.translateService.instant('MODIFIED'), width: '15%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: K8SREPODATADISPLAY, row: K8SREPODATADISPLAY): K8SREPODATADISPLAY => row, + renderComponent: K8sActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + columns: this.columnList, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'k8-repo' }); + this.dataService.changeMessage(event.data); + } + + /** Compose new K8s Repo Accounts @public */ + public addK8sRepo(): void { + const modalRef: NgbModalRef = this.modalService.open(K8sAddRepoComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Generate nsData object from loop and return for the datasource @public */ + // tslint:disable-next-line: typedef + public generateK8sRepoData(k8sRepodata: K8SREPODATA): K8SREPODATADISPLAY { + return { + name: k8sRepodata.name, + identifier: k8sRepodata._id, + url: k8sRepodata.url, + type: k8sRepodata.type, + created: this.sharedService.convertEpochTime(Number(k8sRepodata._admin.created)), + modified: this.sharedService.convertEpochTime(Number(k8sRepodata._admin.modified)), + pageType: 'repo' + }; + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.K8REPOS_URL).subscribe((k8sRepoDatas: K8SREPODATA[]) => { + this.k8sRepoData = []; + k8sRepoDatas.forEach((k8sRepodata: K8SREPODATA) => { + const k8sRepoDataObj: K8SREPODATADISPLAY = this.generateK8sRepoData(k8sRepodata); + this.k8sRepoData.push(k8sRepoDataObj); + }); + if (this.k8sRepoData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.k8sRepoData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(() => { + this.isLoadingResults = false; + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + +} diff --git a/src/app/layouts/LayoutComponent.html b/src/app/layouts/LayoutComponent.html new file mode 100644 index 0000000..96f1302 --- /dev/null +++ b/src/app/layouts/LayoutComponent.html @@ -0,0 +1,37 @@ + + +
+
+ +
+ +
+
+
+ +
+
+
+
+
+ +
\ No newline at end of file diff --git a/src/app/layouts/LayoutComponent.scss b/src/app/layouts/LayoutComponent.scss new file mode 100644 index 0000000..649387a --- /dev/null +++ b/src/app/layouts/LayoutComponent.scss @@ -0,0 +1,36 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import "../../assets/scss/mixins/mixin"; +@import "../../assets/scss/variable"; +#main-wrapper { + @include wh-value(100%, null); + .layout-wrapper { + @include flexbox(flex, null, null, null, stretch, null); + .content-section { + @include wh-value(100%, null); + @include transition(all, 0.3s, null, null); + overflow-x: auto; + } + } + .goto-top { + @include position_value(fixed, null, 30px, 10px, null); + @include font(null, 20px, null); + outline: none; + @include wh-value(40px, 40px); + } +} \ No newline at end of file diff --git a/src/app/layouts/LayoutComponent.ts b/src/app/layouts/LayoutComponent.ts new file mode 100644 index 0000000..b99221a --- /dev/null +++ b/src/app/layouts/LayoutComponent.ts @@ -0,0 +1,44 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file NS Instance Component + */ +import { Component } from '@angular/core'; +import { SharedService } from 'SharedService'; +/** + * Creating component + * @Component takes LayoutComponent.html as template url + */ +@Component({ + selector: 'app-layout', + templateUrl: './LayoutComponent.html', + styleUrls: ['./LayoutComponent.scss'] +}) +/** Exporting a class @exports LayoutComponent */ +export class LayoutComponent { + /** Contains all methods related to shared @private */ + public sharedService: SharedService; + + constructor(sharedService: SharedService) { + this.sharedService = sharedService; + } + /** method to handle go to top event @public */ + public gotoTop(): void { + window.scroll({ behavior: 'smooth', top: 0, left: 0 }); + } +} diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.html b/src/app/layouts/breadcrumb/BreadcrumbComponent.html new file mode 100644 index 0000000..9d028b3 --- /dev/null +++ b/src/app/layouts/breadcrumb/BreadcrumbComponent.html @@ -0,0 +1,27 @@ + + \ No newline at end of file diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.scss b/src/app/layouts/breadcrumb/BreadcrumbComponent.scss new file mode 100644 index 0000000..7ed3da6 --- /dev/null +++ b/src/app/layouts/breadcrumb/BreadcrumbComponent.scss @@ -0,0 +1,81 @@ +/* +Copyright 2020 TATA ELXSI + +Licensed under the Apache License, Version 2.0 (the 'License'); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + +Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import "../../../assets/scss/mixins/mixin"; +@import "../../../assets/scss/variable"; +.breadcrumb-holder { + .breadcrumb-custom { + @include box-shadow(0, 2px, 5px, 0, rgba(0, 0, 0, 0.25)); + @include roundedCorners(5); + @include background(null, $white, null, null, null); + @include margin-value(0, 0, 0, 0); + @include flexbox(inline-block, null, null, null, null, null); + overflow: hidden; + .breadcrumb-item-custom { + @include flexbox(block, null, null, null, null, null); + @include line-height(35px); + @include font(null, 12px, null); + @include padding-value(0, 10, 0, 30); + @include position_value(relative, null, null, null, null); + float: left; + cursor: pointer; + &:hover { + @include background(null, $secondary, null, null, null); + a { + color: $white; + } + &::after { + @include background(null, $secondary, null, null, null); + } + } + a { + color: $primary; + } + &:first-child { + padding-left: 20px; + @include roundedTopLeftRadius(5); + @include roundedBottomLeftRadius(5); + &::before { + @include position_value(null, null, null, null, 14px); + } + } + &:last-child { + @include roundedTopRightRadius(5); + @include roundedBottomRightRadius(5); + padding-right: 20px; + &::after { + content: none; + } + } + &::after { + content: ""; + @include position_value(absolute, 0, -18px, null, null); + @include wh-value(36px, 36px); + @include background(null, $white, null, null, null); + @include box-shadow(2px, -2px, 0, 1px, $breadcrumb-after-color); + transform: scale(0.707) rotate(45deg); + z-index: 1; + @include roundedTopRightRadius(5); + @include roundedBottomLeftRadius(50); + } + &.active { + @include background(null, $primary, null, null, null); + color: $white; + } + } + } +} \ No newline at end of file diff --git a/src/app/layouts/breadcrumb/BreadcrumbComponent.ts b/src/app/layouts/breadcrumb/BreadcrumbComponent.ts new file mode 100644 index 0000000..ccb9588 --- /dev/null +++ b/src/app/layouts/breadcrumb/BreadcrumbComponent.ts @@ -0,0 +1,140 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Bread Crumb component. + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { ActivatedRoute, NavigationEnd, Router, RouterEvent, UrlSegment } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { BREADCRUMBITEM } from 'CommonModel'; +import { filter, startWith } from 'rxjs/operators'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes BreadcrumbComponent.html as template url + */ +@Component({ + selector: 'app-breadcrumb', + templateUrl: './BreadcrumbComponent.html', + styleUrls: ['./BreadcrumbComponent.scss'] +}) + +/** Exporting a class @exports BreadcrumbComponent */ +export class BreadcrumbComponent implements OnInit { + /** To inject breadCrumb @public */ + public static readonly ROUTE_DATA_BREADCRUMB: string = 'breadcrumb'; + + /** To inject services @public */ + public injector: Injector; + + /** To inject breadCrumb Default icon and url @public */ + public readonly home: {} = { icon: 'pi pi-th-large', url: '/' }; + + /** To inject breadCrumb Menus @public */ + public menuItems: BREADCRUMBITEM[]; + + /** Service holds the router information @private */ + private router: Router; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + + /** handle translate service @private */ + private translateService: TranslateService; + + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.translateService = this.injector.get(TranslateService); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.router.events + .pipe(filter((event: RouterEvent) => event instanceof NavigationEnd), startWith(undefined)) + .subscribe(() => this.menuItems = this.createBreadcrumbs(this.activatedRoute.root)); + } + + /** Generate breadcrumbs from data given the module routes @private */ + private createBreadcrumbs(route: ActivatedRoute, url: string = '', breadcrumbs: BREADCRUMBITEM[] = []): + BREADCRUMBITEM[] { + const children: ActivatedRoute[] = route.children; + if (children.length === 0) { + return breadcrumbs; + } + for (const child of children) { + const routeURL: string = child.snapshot.url.map((segment: UrlSegment) => segment.path).join('/'); + if (routeURL !== '') { + url += `/${routeURL}`; + } + let menuLIst: BREADCRUMBITEM[] = child.snapshot.data[BreadcrumbComponent.ROUTE_DATA_BREADCRUMB]; + if (!isNullOrUndefined(menuLIst)) { + menuLIst = JSON.parse(JSON.stringify(menuLIst)); + menuLIst.forEach((item: BREADCRUMBITEM) => { + if (!isNullOrUndefined(item.title)) { + item.title = item.title.replace('{type}', this.checkTitle(item, child.snapshot.params.type)); + item.title = item.title.replace('{id}', child.snapshot.params.id); + item.title = item.title.replace('{project}', localStorage.getItem('project')); + } + if (!isNullOrUndefined(item.url)) { + item.url = item.url.replace('{type}', child.snapshot.params.type); + item.url = item.url.replace('{id}', child.snapshot.params.id); + } + breadcrumbs.push(item); + }); + } + return this.createBreadcrumbs(child, url, breadcrumbs); + } + } + /** Check and update title based on type of operations @private */ + private checkTitle(breadcrumbItem: BREADCRUMBITEM, opertionType: string): string { + if (!isNullOrUndefined(breadcrumbItem.url)) { + if (breadcrumbItem.url.indexOf('packages') !== -1) { + return this.matchPackageTitle(opertionType); + } + if (breadcrumbItem.url.indexOf('instances') !== -1) { + return this.matchInstanceTitle(opertionType); + } + return breadcrumbItem.title; + } + } + /** check and update package title based on package type @private */ + private matchPackageTitle(opertionType: string): string { + if (opertionType === 'ns') { + return this.translateService.instant('NSPACKAGES'); + } else if (opertionType === 'vnf') { + return this.translateService.instant('VNFPACKAGES'); + } else { + return this.translateService.instant('PAGE.DASHBOARD.NETSLICETEMPLATE'); + } + } + /** check and update package title based on instance type @private */ + private matchInstanceTitle(opertionType: string): string { + if (opertionType === 'ns') { + return this.translateService.instant('NSINSTANCES'); + } else if (opertionType === 'vnf') { + return this.translateService.instant('VNFINSTANCES'); + } else if (opertionType === 'pdu') { + return this.translateService.instant('PDUINSTANCES'); + } else { + return this.translateService.instant('PAGE.DASHBOARD.NETSLICEINSTANCE'); + } + } + +} diff --git a/src/app/layouts/header/HeaderComponent.html b/src/app/layouts/header/HeaderComponent.html new file mode 100644 index 0000000..a9ff5ac --- /dev/null +++ b/src/app/layouts/header/HeaderComponent.html @@ -0,0 +1,71 @@ + +Here is a newer {{'APPVERSION' | translate}} {{PACKAGEVERSION}} + of OSM! + + \ No newline at end of file diff --git a/src/app/layouts/header/HeaderComponent.scss b/src/app/layouts/header/HeaderComponent.scss new file mode 100644 index 0000000..86200b7 --- /dev/null +++ b/src/app/layouts/header/HeaderComponent.scss @@ -0,0 +1,51 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; + +.navbar{ + @include box-shadow(0px, 0px, 12px, 0px, rgba($black,0.14)); + @include border(all, 0, solid, $gray-80); + .osm-logo{ + cursor: pointer; + } + .custom-dropdown-menu { + .dropdown-item{ + &.project-item{ + @include flexbox(flex, space-between, row, null, center, null); + } + &:active, &:hover, &.active{ + @include background(null, $theme-bg-color, null, null, null); + color: $primary; + } + &.activeProject{ + cursor: default; + } + } + .custom-divider{ + @include wh-value(null, 0); + @include border(top, 2, solid, $primary); + overflow: hidden; + } + } + .osm-version{ + @include background(null, $theme-bg-color, null, null, null); + color: $primary; + cursor: default; + } +} \ No newline at end of file diff --git a/src/app/layouts/header/HeaderComponent.ts b/src/app/layouts/header/HeaderComponent.ts new file mode 100644 index 0000000..4d7f3b1 --- /dev/null +++ b/src/app/layouts/header/HeaderComponent.ts @@ -0,0 +1,106 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Header Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { AuthenticationService } from 'AuthenticationService'; +import { environment } from 'environment'; +import { ProjectService } from 'ProjectService'; +import { Observable } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { ProjectRoleMappings, UserDetail } from 'UserModel'; +import { UserSettingsComponent } from 'UserSettingsComponent'; + +/** + * Creating component + * @Component takes HeaderComponent.html as template url + */ +@Component({ + selector: 'app-header', + templateUrl: './HeaderComponent.html', + styleUrls: ['./HeaderComponent.scss'] +}) +/** Exporting a class @exports HeaderComponent */ +export class HeaderComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Variables holds all the projects @public */ + public projectList$: Observable<{}[]>; + + /** Observable holds logined value @public */ + public username$: Observable; + + /** Variables holds admin is logged or not @public */ + public isAdmin: boolean; + + /** Variables holds the selected project @public */ + public selectedProject: Observable; + + /** project @public */ + public getSelectedProject: string; + + /** Version holds packages version @public */ + public PACKAGEVERSION: string; + + /** Contains all methods related to shared @public */ + public sharedService: SharedService; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + /** Holds all project details @private */ + private projectService: ProjectService; + + /** Utilizes modal service for any modal operations @private */ + private modalService: NgbModal; + + constructor(injector: Injector) { + this.injector = injector; + this.authService = this.injector.get(AuthenticationService); + this.modalService = this.injector.get(NgbModal); + this.projectService = this.injector.get(ProjectService); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.isAdmin = (localStorage.getItem('isAdmin') === 'true') ? true : false; + this.selectedProject = this.authService.ProjectName; + this.authService.ProjectName.subscribe((projectNameFinal: string) => { + this.getSelectedProject = projectNameFinal; + }); + this.username$ = this.authService.username; + this.projectService.setHeaderProjects(); + this.projectList$ = this.projectService.projectList; + this.PACKAGEVERSION = environment.packageVersion; + } + + /** Logout function @public */ + public logout(): void { + this.authService.logout(); + } + + /** Implementation of model for UserSettings options.@public */ + public userSettings(): void { + this.modalService.open(UserSettingsComponent, { backdrop: 'static' }); + } +} diff --git a/src/app/layouts/sidebar/SidebarComponent.html b/src/app/layouts/sidebar/SidebarComponent.html new file mode 100644 index 0000000..1fa4f82 --- /dev/null +++ b/src/app/layouts/sidebar/SidebarComponent.html @@ -0,0 +1,52 @@ + + \ No newline at end of file diff --git a/src/app/layouts/sidebar/SidebarComponent.scss b/src/app/layouts/sidebar/SidebarComponent.scss new file mode 100644 index 0000000..7b5f92e --- /dev/null +++ b/src/app/layouts/sidebar/SidebarComponent.scss @@ -0,0 +1,225 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import "../../../assets/scss/mixins/mixin"; +@import "../../../assets/scss/variable"; +$active-margin-left: -230; +$minimize-left: 45px; +.sidebar-mini { + @include transition(all, 0.3s, ease-in-out, 0s); + @include position_value(relative, null, null, null, null); + z-index: 10; + .custom-menu { + @include flexbox(inline-block, null, null, null, null, null); + @include position_value(absolute, 25px, 4px, null, null); + @include margin-value(0, -20, 0, 0); + .btn { + @include wh-value(55px, 55px); + @include roundedCornersPercentage(50%); + @include position_value(relative, null, null, null, null); + @include background(null, transparent, null, null, null); + @include border(all, 0, solid, transparent); + i { + @include margin-value(0, -40, 0, 0); + @include font(null, 14px, null); + } + &.btn-primary { + &:after { + content: ""; + @include position_value(absolute, 0, 0, 0, 0); + @include background(null, $secondary, null, null, null); + @include roundedCorners(10); + @include rotate(45); + z-index: -1; + } + } + &:hover, + &:focus, + &:active { + @include background(null, transparent !important, null, null, null); + } + } + } + nav { + @include wh-value(200px, null); + @include transition(width, 0.2s, ease-in-out, 0s); + ul { + @include padding-value(0, 0, 0, 0); + @include margin-value(0, 0, 0, 0); + @include wh-value(100%, null); + @include background(null, $theme-bg-color, null, null, null); + li { + @include position_value(relative, null, null, null, null); + @include background(null, $secondary, null, null, null); + @include line-height(14px); + list-style-type: none; + cursor: pointer; + color: $white; + &.round-edge-top-3 { + @include roundedTopRightRadius(3); + @include roundedTopLeftRadius(3); + } + &.round-edge-bottom-3 { + @include roundedBottomLeftRadius(3); + @include roundedBottomRightRadius(3); + } + &.border-bottom-none { + @include border(bottom, 0, !important, null); + } + &.header-menu { + @include background(null, $theme-bg-color, null, null, null); + @include padding-value(10, 20, 0, 4); + @include font(null, null, bold); + cursor: default; + .heading { + @include border(bottom, 2, solid, $primary); + @include font(null, 12px, null); + @include line-height(16px); + @include flexbox(block, null, null, null, null, null); + cursor: default; + color: $primary; + } + } + a { + &.individual { + @include padding-value(12, 5, 12, 15); + color: $white; + } + i { + @include wh-value(30px, null); + } + &.parentlink::after { + content: "\f105"; + @include font("Font Awesome 5 Free", null, 900); + @include position_value(absolute, 14px, 15px, null, null); + @include transition(all, 0.3s, ease, 0s); + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + } + } + .sidebar-submenu { + opacity: 0; + @include transition(opacity, 0.4s, ease-in-out, 0s); + li { + @include background(null, $secondary, null, null, null); + @include wh-value(null, 0); + @include transition(height, 200ms, ease-in, 0s); + overflow: hidden; + &:last-child { + @include roundedBottomLeftRadius(4); + @include roundedBottomRightRadius(4); + } + .link { + color: $gray-500; + } + &:hover, + &.active { + .link { + color: $white; + } + } + } + } + &.menu-open { + @include background(null, $primary, null, null, null); + a { + &::after { + @include rotate(90); + } + } + .sidebar-submenu { + opacity: 1; + li { + @include wh-value(null, 45px); + } + } + } + &.parentactive { + @include background(null, $primary, null, null, null); + .parentlink { + color: $white; + } + } + .parentlink, + .link { + @include padding-value(12, 5, 12, 15); + @include flexbox(flex, null, null, null, null, null); + } + } + } + } + &.sidebar-collapse { + @include background(null, transparent, null, null, null); + nav { + transform: translate(0, 0); + @include wh-value($minimize-left, null); + ul { + &.scrollable-menu { + li { + a { + span { + @include position_value(null, 0, null, null, null); + @include padding-value(12, 5, 12, 20); + } + &.individual { + span { + @include roundedBottomRightRadius(4); + } + } + &.parentlink, + &.individual { + span { + @include background(null, $primary, null, null, null); + @include roundedTopRightRadius(4); + } + } + } + &:hover { + .sidebar-submenu { + li { + @include wh-value(null, 45px); + } + } + .sidebar-submenu, + a span { + @include flexbox(block !important, null, null, null, null, null); + @include position_value(absolute, null, null, null, $minimize-left); + @include wh-value(220px, null); + opacity: 1; + } + } + &.header-menu, + .sidebar-submenu { + @include flexbox(none !important, null, null, null, null, null); + transform: translateZ(0); + } + } + } + li { + a::after, + span { + @include flexbox(none !important, null, null, null, null, null); + transform: translateZ(0); + } + } + } + } + } + &.sidebar-open { + @include margin-value(0, 0, 0, $active-margin-left); + } +} \ No newline at end of file diff --git a/src/app/layouts/sidebar/SidebarComponent.ts b/src/app/layouts/sidebar/SidebarComponent.ts new file mode 100644 index 0000000..9cae634 --- /dev/null +++ b/src/app/layouts/sidebar/SidebarComponent.ts @@ -0,0 +1,148 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ + +/** + * @file Sidebar Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { DeviceCheckService } from 'DeviceCheckService'; +import { MENU_ITEMS, MENUITEMS } from 'src/models/MenuModel'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes SidebarComponent.html as template url + */ +@Component({ + selector: 'app-sidebar', + templateUrl: './SidebarComponent.html', + styleUrls: ['./SidebarComponent.scss'] +}) +/** Exporting a class @exports SidebarComponent */ +export class SidebarComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** submenu router endpoints @public */ + public routerEndpoint: string; + + /** submenu router endpoints @public */ + public getMenus: MENUITEMS[]; + + /** selected Menu @public */ + public selectedItem: string; + + /** get the classlist @public */ + public elementCheck: HTMLCollection; + + /** Apply active class for Desktop @public */ + public classAppliedForDesktop: boolean = false; + + /** Apply active class for mobile @public */ + public classAppliedForMobile: boolean = false; + + /** Device Check service @public */ + public deviceCheckService: DeviceCheckService; + + /** Check for the mobile @public */ + public isMobile$: boolean; + + constructor(injector: Injector) { + this.injector = injector; + this.deviceCheckService = this.injector.get(DeviceCheckService); + this.getMenus = MENU_ITEMS; + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.deviceCheckService.checkDeviceType(); + this.deviceCheckService.isMobile.subscribe((checkIsMobile: boolean) => { + this.isMobile$ = checkIsMobile; + this.getDeviceType(); + }); + } + /** method to open sideBarOpen in all the views */ + public sideBarOpenClose(): void { + if (this.isMobile$) { + this.classAppliedForMobile = !this.classAppliedForMobile; + } else { + this.classAppliedForDesktop = !this.classAppliedForDesktop; + } + this.addClassMainWrapper(); + } + /** Add class for mobile/Desktop in main-wrapper @public */ + public addClassMainWrapper(): void { + const elementMain: HTMLElement = document.querySelector('#main-wrapper'); + if (!isNullOrUndefined(elementMain)) { + if (this.isMobile$) { + elementMain.classList.toggle('sidebar-mobile'); + } else { + elementMain.classList.toggle('sidebar-desktop'); + } + } + } + /** Return the Device type @public */ + public getDeviceType(): void { + if (this.isMobile$) { + this.classAppliedForMobile = true; + this.classAppliedForDesktop = false; + } else { + this.classAppliedForMobile = false; + this.classAppliedForDesktop = false; + } + this.addClassMainWrapper(); + } + /** Set the SideBar Menus click function @public */ + public handleMenuFunction(index: number, method: string, className: string, childExists: boolean): void { + this.selectedItem = method; + if (!isNullOrUndefined(method)) { + this.parentactiveClassAddRemove(index, method, className, childExists); + } + } + /** Removing the parentactive class which is already present and add it to current @public */ + public parentactiveClassAddRemove(index: number, method: string, className: string, childExists: boolean): void { + const element: HTMLElement = document.querySelector('#' + method + '' + index); + const checkOpenedelement: boolean = element.classList.contains(className); + if (!checkOpenedelement) { + this.elementCheck = document.getElementsByClassName(className); + if (this.elementCheck.length > 0) { + this.removeClasses(className); + } + } + if (method !== 'nosubmenu') { + element.classList.toggle(className); + } + if (this.isMobile$ && !childExists) { + this.checkAndCloseSideBar(childExists); + } + } + /** Hide / Show Menus based on the clicking in the menus @public */ + public checkAndCloseSideBar(childExists: boolean): void { + event.stopPropagation(); + if (this.isMobile$ && !childExists) { + this.sideBarOpenClose(); + } + } + /** remove existing Class @public */ + public removeClasses(className: string): void { + this.elementCheck[0].classList.remove(className); + if (this.elementCheck[0]) { + this.removeClasses(className); + } + } +} diff --git a/src/app/login/LoginComponent.html b/src/app/login/LoginComponent.html new file mode 100644 index 0000000..296d51b --- /dev/null +++ b/src/app/login/LoginComponent.html @@ -0,0 +1,57 @@ + + + + diff --git a/src/app/login/LoginComponent.scss b/src/app/login/LoginComponent.scss new file mode 100644 index 0000000..28ac159 --- /dev/null +++ b/src/app/login/LoginComponent.scss @@ -0,0 +1,156 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import "../../assets/scss/mixins/mixin"; +@import "../../assets/scss/variable"; + +.login-container { + @include wh-value(100%, 100vh); + @include flexbox(flex, center, null, null, center, null); + @include background(url("../../assets/images/login_background.jpg"), null, cover, no-repeat, center); + background-attachment: fixed; + flex-wrap: wrap; + .wrap-login { + @include background( + linear-gradient( + to left bottom, + #00c0ef, + #00b3f9, + #3ea3fd, + #7190f8, + #9c78e8, + #a86cdd, + #b25fd1, + #bb51c3, + #b151c4, + #a652c6, + #9b53c6, + #9053c7 + ), + null, + null, + null, + null + ); + @include roundedCorners(15); + @include flexbox(flex, space-between, null, null, null, null); + @include position_value(relative, null, null, null, null); + @include box-shadow(0px, 3px, 10px, 0px, rgba($black, 0.5)); + @include padding-value(20, 30, 20, 30); + flex-wrap: wrap; + color: $white; + overflow: visible; + .login-logo { + @include flexbox(flex, center, null, null, center, null); + @include position_value(absolute, -80px, null, null, 95px); + @include box-shadow(1px, 2px, 0px, 0px, $cerise-pink); + @include margin-value(0, 0, 10, 0); + @include wh-value(160px, 150px); + @include background(null, $white, null, null, null); + @include roundedCornersPercentage(50%); + img { + @include wh-value(130px, auto); + @include position_value(null, 50px, null, null, null); + } + } + .login-form { + @include wh-value(290px, null); + @include padding-value(70, 0, 0, 0); + text-align: center; + .wrap-input { + @include position_value(relative, null, null, null, null); + @include wh-value(100%, null); + @include margin-value(0, 0, 10, 0); + z-index: 1; + .input-control { + @include font(null, 15px, null); + @include line-height(1.5); + @include wh-value(100%, 42px); + @include padding-value(0, 30, 0, 65); + @include flexbox(block, null, null, null, null, null); + @include roundedCorners(25); + @include border(all, 0, solid, $gray-80); + @include background(null, $white, null, null, null); + &:focus + .input-icon { + color: $cerise-pink; + @include padding-value(0, 0, 0, 25); + } + } + .input-icon { + @include font(null, 13px, null); + @include flexbox(flex, null, null, null, center, null); + @include position_value(absolute, null, null, 0, 0); + @include wh-value(100%, 100%); + @include padding-value(0, 0, 0, 35); + @include roundedCorners(25); + @include transition(all, 0.5s, null, null); + pointer-events: none; + color: $gray-600; + } + } + .submit-btn { + @include background(null, $white, null, null, null); + @include roundedCornersPercentage(50%); + @include border(all, 0, solid, $gray-80); + @include transition(all, 0.3s, null, null); + @include box-shadow(1px, 5px, 5px, 0px, rgba($black, 0.3), inset); + cursor: pointer; + @include font(null, 25px, null); + @include wh-value(60px, 60px); + @include margin-value(0, 0, 10, 0); + @include padding-value(0, 0, 0, 0); + color: $cerise-pink; + &:hover { + @include box-shadow(1px, 5px, 10px, 0px, rgba($black, 0.3)); + } + .fa { + @include transition(all, 0.4s, null, null); + @include flexbox(block, null, null, null, null, null); + @include padding-value(18, 18, 18, 18); + &:hover { + transform: scale(1.2); + } + } + } + .input-validation-msg { + @include roundedCorners(25); + @include background(null, $cerise-pink, null, null, null); + @include margin-value(0, 0, 10, 0); + @include padding-value(1, 0, 1, 15); + @include font(null, 11px, null); + color: $white; + text-align: left; + } + } + } +} +.login-footer { + @include flexbox(flex, space-between, null, null, center, null); + @include position_value(fixed, null, null, 0px, null); + @include background(null, $purple, null, null, null); + @include wh-value(100%, 40px); + @include padding-value(0, 10, 0, 10); + color: $white; + opacity: 0.9; + a { + @include font(null, null, bold); + color: $white; + &:hover { + text-decoration: underline; + } + } +} \ No newline at end of file diff --git a/src/app/login/LoginComponent.ts b/src/app/login/LoginComponent.ts new file mode 100644 index 0000000..2f4f67e --- /dev/null +++ b/src/app/login/LoginComponent.ts @@ -0,0 +1,131 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ + +/** + * @file Page for Login component + */ +import { HttpErrorResponse } from '@angular/common/http'; +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { AuthenticationService } from 'AuthenticationService'; +import { RestService } from 'RestService'; +import { Observable } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes LoginComponent.html as template url + */ +@Component({ + selector: 'app-login', + templateUrl: './LoginComponent.html', + styleUrls: ['./LoginComponent.scss'] +}) +/** Exporting a class @exports LoginComponent */ +export class LoginComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** contains loginform group information @public */ + public loginForm: FormGroup; + + /** submitted set to boolean state @public */ + public submitted: boolean = false; + + /** contains return URL link @public */ + public returnUrl: string; + + /** Observable Hold the value of subscription @public */ + public isLoggedIn$: Observable; + + /** contains access token information @public */ + public accessToken: string; + + /** Utilizes rest service for any CRUD operations @public */ + public restService: RestService; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Contains all methods related to shared @public */ + public sharedService: SharedService; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + /** contians form builder module @private */ + private formBuilder: FormBuilder; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates instance of login component + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.authService = this.injector.get(AuthenticationService); + this.formBuilder = this.injector.get(FormBuilder); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.isLoggedIn$ = this.authService.isLoggedIn; + if (this.isLoggedIn$) { + this.router.navigate(['/']).catch(() => { + // Catch Navigation Error + }); + } + this.loginForm = this.formBuilder.group({ + userName: ['', [Validators.required]], + password: ['', [Validators.required]] + }); + this.returnUrl = isNullOrUndefined(localStorage.getItem('returnUrl')) ? '/' : localStorage.getItem('returnUrl'); + } + + /** + * called on form submit @private onSubmit + */ + public onSubmit(): void { + this.submitted = true; + if (this.loginForm.invalid) { + return; + } + this.isLoadingResults = true; + this.sharedService.cleanForm(this.loginForm); + this.authService.login(this.loginForm.value.userName, this.loginForm.value.password).subscribe( + (data: {}) => { + this.isLoadingResults = false; + this.router.navigate([this.returnUrl]).catch(() => { + // Catch Navigation Error + }); + localStorage.removeItem('returnUrl'); + }, (err: HttpErrorResponse) => { + this.isLoadingResults = false; + this.restService.handleError(err, 'post'); + }); + } +} diff --git a/src/app/packages/PackagesComponent.html b/src/app/packages/PackagesComponent.html new file mode 100644 index 0000000..06b8876 --- /dev/null +++ b/src/app/packages/PackagesComponent.html @@ -0,0 +1,18 @@ + + diff --git a/src/app/packages/PackagesComponent.scss b/src/app/packages/PackagesComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/packages/PackagesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/PackagesComponent.ts b/src/app/packages/PackagesComponent.ts new file mode 100644 index 0000000..eb9991d --- /dev/null +++ b/src/app/packages/PackagesComponent.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Packages-Component.ts. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; +/** + * Creating Component + * @Component takes PackagesComponent.html as template url + */ +@Component({ + selector: 'app-packages', + templateUrl: './PackagesComponent.html', + styleUrls: ['./PackagesComponent.scss'] +}) +/** Exporting a class @exports PackagesComponent */ +export class PackagesComponent{ + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/packages') { + this.router.navigate(['/packages/ns']).catch(); + } + } +} diff --git a/src/app/packages/PackagesModule.ts b/src/app/packages/PackagesModule.ts new file mode 100644 index 0000000..e6c6628 --- /dev/null +++ b/src/app/packages/PackagesModule.ts @@ -0,0 +1,127 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Packages Module. + */ +import { CommonModule } from '@angular/common'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { ReactiveFormsModule } from '@angular/forms'; +import { FormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { CodemirrorModule } from '@ctrl/ngx-codemirror'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { ClonePackageComponent } from 'ClonePackage'; +import { DataService } from 'DataService'; +import { DragDirective } from 'DragDirective'; +import { EditPackagesComponent } from 'EditPackagesComponent'; +import { LoaderModule } from 'LoaderModule'; +import { NetsliceTemplateComponent } from 'NetsliceTemplate'; +import { SidebarModule } from 'ng-sidebar'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { NSComposerComponent } from 'NSComposer'; +import { NSPackagesComponent } from 'NSPackages'; +import { PackagesComponent } from 'Packages'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { ShowContentComponent } from 'ShowContent'; +import { VNFComposerComponent } from 'VNFComposer'; +import { VNFPackagesComponent } from 'VNFPackages'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** + * configures routers + */ +const routes: Routes = [ + { + path: '', + component: PackagesComponent, + children: [ + { + path: 'ns', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'NSPACKAGES', url: null }] + }, + component: NSPackagesComponent + }, + { + path: 'vnf', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VNFPACKAGES', url: null }] + }, + component: VNFPackagesComponent + }, + { + path: 'netslice', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' } + , projectInfo, { title: 'PAGE.DASHBOARD.NETSLICETEMPLATE', url: null }] + }, + component: NetsliceTemplateComponent + }, + { + path: ':type/edit/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' } + , projectInfo, { title: '{type}', url: '/packages/{type}' }, { title: '{id}', url: null }] + }, + component: EditPackagesComponent + }, + { + path: 'ns/compose/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' } + , projectInfo, { title: 'NSPACKAGES', url: '/packages/ns' }, { title: '{id}', url: null }] + }, + component: NSComposerComponent + }, + { + path: 'vnf/compose/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VNFPACKAGES', url: '/packages/vnf' }, { title: '{id}', url: null }] + }, + component: VNFComposerComponent + } + ] + } +]; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule, Ng2SmartTableModule, + CodemirrorModule, TranslateModule, RouterModule.forChild(routes), NgbModule, NgSelectModule, + PagePerRowModule, SidebarModule.forRoot(), LoaderModule, PageReloadModule], + declarations: [PackagesComponent, NSPackagesComponent, VNFPackagesComponent, NetsliceTemplateComponent, + DragDirective, ShowContentComponent, NSComposerComponent, VNFComposerComponent, EditPackagesComponent, ClonePackageComponent], + providers: [DataService], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + entryComponents: [ShowContentComponent, ClonePackageComponent] +}) +/** Exporting a class @exports PackagesModule */ +export class PackagesModule { + /** Variables declared to avoid state-less class */ + private packagesModule: string; +} diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html new file mode 100644 index 0000000..af52927 --- /dev/null +++ b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.html @@ -0,0 +1,98 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss new file mode 100644 index 0000000..0ecd95d --- /dev/null +++ b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ \ No newline at end of file diff --git a/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts new file mode 100644 index 0000000..ed5e414 --- /dev/null +++ b/src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent.ts @@ -0,0 +1,282 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Instantiate NS Modal Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { NetworkSliceData } from 'NetworkSliceModel'; +import { NSICREATEPARAMS } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { VimAccountDetails } from 'VimAccountModel'; +/** + * Creating component + * @Component takes InstantiateNetSliceTemplateComponent.html as template url + */ +@Component({ + selector: 'app-instantiate-net-slice-template', + templateUrl: './InstantiateNetSliceTemplateComponent.html', + styleUrls: ['./InstantiateNetSliceTemplateComponent.scss'] +}) +/** Exporting a class @exports InstantiateNetSliceTemplateComponent */ +export class InstantiateNetSliceTemplateComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** FormGroup instance added to the form @ html @public */ + public netSliceInstantiateForm: FormGroup; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Variable set for twoway bindng @public */ + public vimAccountId: string; + + /** Contains all the net slice data collections */ + public netSliceSelect: NetworkSliceData; + + /** Contains all the VIM data collections */ + public vimDetailsSelect: VimAccountDetails; + + /** Variable set for twoway binding @public */ + public netsliceNstId: string; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Element ref for fileInputConfig @public */ + @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef; + + /** Element ref for fileInputConfigLabel @public */ + @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef; + + /** Element ref for fileInputSSH @public */ + @ViewChild('fileInputSSH', { static: true }) public fileInputSSH: ElementRef; + + /** Element ref for fileInputSSHLabel @public */ + @ViewChild('fileInputSSHLabel', { static: true }) public fileInputSSHLabel: ElementRef; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Utilizes data service for any communication @private */ + private dataService: DataService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains the ssh key to be hosted in dom @private */ + private copySSHKey: string; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + this.dataService = this.injector.get(DataService); + this.notifierService = this.injector.get(NotifierService); + this.router = this.injector.get(Router); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + /** Setting up initial value for NSD */ + this.netsliceNstId = ''; + this.dataService.currentMessage.subscribe((event: NetworkSliceData) => { + if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) { + this.netsliceNstId = event.identifier; + } + }); + this.netSliceInstantiateFormAction(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + /** On Initializing call the methods */ + this.getNetSliceDetails(); + this.getVIMDetails(); + } + + /** Call the netSlice details in the selection options @public */ + public getNetSliceDetails(): void { + this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL).subscribe((netSlicePackages: NetworkSliceData) => { + this.netSliceSelect = netSlicePackages; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Call the VIM details in the selection options @public */ + public getVIMDetails(): void { + this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimDetails: VimAccountDetails) => { + this.vimDetailsSelect = vimDetails; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** On modal initializing forms @public */ + public netSliceInstantiateFormAction(): void { + this.netSliceInstantiateForm = this.formBuilder.group({ + nsiName: ['', [Validators.required]], + nsiDescription: ['', [Validators.required]], + nstId: ['', [Validators.required]], + vimAccountId: ['', [Validators.required]], + ssh_keys: [null], + config: [null] + }); + } + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.netSliceInstantiateForm.controls; } + + /** On modal submit instantiateNsSubmit will called @public */ + public instantiateNSTSubmit(): void { + this.submitted = true; + this.sharedService.cleanForm(this.netSliceInstantiateForm); + if (this.netSliceInstantiateForm.invalid) { + return; + } + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + if (isNullOrUndefined(this.netSliceInstantiateForm.value.ssh_keys) || this.netSliceInstantiateForm.value.ssh_keys === '') { + delete this.netSliceInstantiateForm.value.ssh_keys; + } else { + this.copySSHKey = JSON.parse(JSON.stringify(this.netSliceInstantiateForm.value.ssh_keys)); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.netSliceInstantiateForm.get('ssh_keys').setValue(this.copySSHKey); + } + if (isNullOrUndefined(this.netSliceInstantiateForm.value.config) || this.netSliceInstantiateForm.value.config === '') { + delete this.netSliceInstantiateForm.value.config; + } else { + const validJSON: boolean = this.sharedService.checkJson(this.netSliceInstantiateForm.value.config); + if (validJSON) { + this.netSliceInstantiateForm.value.config = JSON.parse(this.netSliceInstantiateForm.value.config); + Object.keys(this.netSliceInstantiateForm.value.config).forEach((item: string) => { + this.netSliceInstantiateForm.value[item] = this.netSliceInstantiateForm.value.config[item]; + }); + delete this.netSliceInstantiateForm.value.config; + } else { + this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG')); + return; + } + } + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: environment.NETWORKSLICEINSTANCESCONTENT_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, this.netSliceInstantiateForm.value) + .subscribe((result: {}) => { + this.activeModal.close(modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.netSliceInstantiateForm.value.nsiName + + this.translateService.instant('PAGE.NETSLICE.CREATEDSUCCESSFULLY')); + this.router.navigate(['/instances/netslice']).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + if (!isNullOrUndefined(this.copySSHKey)) { + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.netSliceInstantiateForm.get('ssh_keys').setValue(this.copySSHKey); + } + this.isLoadingResults = false; + }); + } + + /** ssh file process @private */ + public sshFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'pub').then((fileContent: string): void => { + const getSSHJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.netSliceInstantiateForm.get('ssh_keys').setValue(getSSHJson); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('PUBFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputSSHLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputSSH.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputSSHLabel.nativeElement.innerText = files[0].name; + this.fileInputSSH.nativeElement.value = null; + } + + /** Config file process @private */ + public configFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => { + const getConfigJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.netSliceInstantiateForm.get('config').setValue(JSON.stringify(getConfigJson)); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputConfig.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputConfigLabel.nativeElement.innerText = files[0].name; + this.fileInputConfig.nativeElement.value = null; + } + +} diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.html b/src/app/packages/instantiate-ns/InstantiateNsComponent.html new file mode 100644 index 0000000..dabd469 --- /dev/null +++ b/src/app/packages/instantiate-ns/InstantiateNsComponent.html @@ -0,0 +1,103 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.scss b/src/app/packages/instantiate-ns/InstantiateNsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/packages/instantiate-ns/InstantiateNsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/instantiate-ns/InstantiateNsComponent.ts b/src/app/packages/instantiate-ns/InstantiateNsComponent.ts new file mode 100644 index 0000000..515a24b --- /dev/null +++ b/src/app/packages/instantiate-ns/InstantiateNsComponent.ts @@ -0,0 +1,268 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Instantiate NS Modal Component. + */ +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { NSCREATEPARAMS, NSData, NSDDetails } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { VimAccountDetails } from 'VimAccountModel'; + +/** + * Creating component + * @Component takes InstantiateNsComponent.html as template url + */ +@Component({ + selector: 'app-instantiate-ns', + templateUrl: './InstantiateNsComponent.html', + styleUrls: ['./InstantiateNsComponent.scss'] +}) +/** Exporting a class @exports InstantiateNsComponent */ +export class InstantiateNsComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Contains all the nsd data collections */ + public nsdSelect: NSDDetails; + + /** FormGroup instance added to the form @ html @public */ + public instantiateForm: FormGroup; + + /** Contains all vim account collections */ + public vimAccountSelect: VimAccountDetails; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Variable set for twoway binding @public */ + public nsdId: string; + + /** Variable set for twoway bindng @public */ + public vimAccountId: string; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Element ref for fileInputConfig @public */ + @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef; + + /** Element ref for fileInputConfigLabel @public */ + @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef; + + /** Element ref for fileInputSSH @public */ + @ViewChild('fileInputSSH', { static: true }) public fileInputSSH: ElementRef; + + /** Element ref for fileInputSSHLabel @public */ + @ViewChild('fileInputSSHLabel', { static: true }) public fileInputSSHLabel: ElementRef; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Utilizes rest service for any CRUD operations @private */ + private restService: RestService; + + /** Utilizes data service for any communication @private */ + private dataService: DataService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains the ssh key to be hosted in dom @private */ + private copySSHKey: string; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + this.dataService = this.injector.get(DataService); + this.notifierService = this.injector.get(NotifierService); + this.router = this.injector.get(Router); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + public ngOnInit(): void { + /** Setting up initial value for NSD */ + this.dataService.currentMessage.subscribe((event: NSData) => { + if (event.identifier !== undefined || event.identifier !== '' || event.identifier !== null) { + this.nsdId = event.identifier; + } + }); + /** On Initializing call the methods */ + this.instantiateFormAction(); + this.getDetailsnsd(); + this.getDetailsvimAccount(); + } + + /** On modal initializing forms @public */ + public instantiateFormAction(): void { + this.instantiateForm = this.formBuilder.group({ + nsName: ['', [Validators.required]], + nsDescription: ['', [Validators.required]], + nsdId: ['', [Validators.required]], + vimAccountId: ['', [Validators.required]], + ssh_keys: [null], + config: [null] + }); + } + + /** Convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.instantiateForm.controls; } + + /** Call the nsd details in the selection options @public */ + public getDetailsnsd(): void { + this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL).subscribe((nsPackages: NSDDetails) => { + this.nsdSelect = nsPackages; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** Call the vimAccount details in the selection options @public */ + public getDetailsvimAccount(): void { + this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccounts: VimAccountDetails) => { + this.vimAccountSelect = vimAccounts; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + + /** On modal submit instantiateNsSubmit will called @public */ + public instantiateNsSubmit(): void { + this.submitted = true; + this.sharedService.cleanForm(this.instantiateForm); + if (this.instantiateForm.invalid) { + return; + } + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + if (isNullOrUndefined(this.instantiateForm.value.ssh_keys) || this.instantiateForm.value.ssh_keys === '') { + delete this.instantiateForm.value.ssh_keys; + } else { + this.copySSHKey = JSON.parse(JSON.stringify(this.instantiateForm.value.ssh_keys)); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.instantiateForm.get('ssh_keys').setValue([this.copySSHKey]); + } + if (isNullOrUndefined(this.instantiateForm.value.config) || this.instantiateForm.value.config === '') { + delete this.instantiateForm.value.config; + } else { + const validJSON: boolean = this.sharedService.checkJson(this.instantiateForm.value.config); + if (validJSON) { + this.instantiateForm.value.config = JSON.parse(this.instantiateForm.value.config); + Object.keys(this.instantiateForm.value.config).forEach((item: string) => { + this.instantiateForm.value[item] = this.instantiateForm.value.config[item]; + }); + delete this.instantiateForm.value.config; + } else { + this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG')); + return; + } + } + const apiURLHeader: APIURLHEADER = { + url: environment.NSINSTANCESCONTENT_URL + }; + this.isLoadingResults = true; + this.restService.postResource(apiURLHeader, this.instantiateForm.value).subscribe((result: {}) => { + this.activeModal.close(modalData); + this.notifierService.notify('success', this.instantiateForm.value.nsName + + this.translateService.instant('PAGE.NSINSTANCE.CREATEDSUCCESSFULLY')); + this.router.navigate(['/instances/ns']).catch(); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + if (!isNullOrUndefined(this.copySSHKey)) { + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.instantiateForm.get('ssh_keys').setValue(this.copySSHKey); + } + }); + } + + /** ssh file process @private */ + public sshFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'pub').then((fileContent: string): void => { + const getSSHJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.instantiateForm.get('ssh_keys').setValue(getSSHJson); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('PUBFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputSSHLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputSSH.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputSSHLabel.nativeElement.innerText = files[0].name; + this.fileInputSSH.nativeElement.value = null; + } + + /** Config file process @private */ + public configFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => { + const getConfigJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.instantiateForm.get('config').setValue(JSON.stringify(getConfigJson)); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputConfig.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputConfigLabel.nativeElement.innerText = files[0].name; + this.fileInputConfig.nativeElement.value = null; + } +} diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.html b/src/app/packages/netslice-template/NetsliceTemplateComponent.html new file mode 100644 index 0000000..6d41e11 --- /dev/null +++ b/src/app/packages/netslice-template/NetsliceTemplateComponent.html @@ -0,0 +1,38 @@ + +
+
{{'PAGE.DASHBOARD.NETSLICETEMPLATE' | translate}}
+
+
+
+ +
+
+ {{'DROPFILES' | translate}}
+
+
+
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.scss b/src/app/packages/netslice-template/NetsliceTemplateComponent.scss new file mode 100644 index 0000000..2c07d1b --- /dev/null +++ b/src/app/packages/netslice-template/NetsliceTemplateComponent.scss @@ -0,0 +1,20 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +.ng2-smart-th.identifier{ + width:40% !important; +} \ No newline at end of file diff --git a/src/app/packages/netslice-template/NetsliceTemplateComponent.ts b/src/app/packages/netslice-template/NetsliceTemplateComponent.ts new file mode 100644 index 0000000..5360518 --- /dev/null +++ b/src/app/packages/netslice-template/NetsliceTemplateComponent.ts @@ -0,0 +1,250 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Netslice-Template. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, ViewChild } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { NetslicePackagesActionComponent } from 'NetslicePackagesAction'; +import { NetworkSliceData, NetworkSliceModel } from 'NetworkSliceModel'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes NetsliceTemplateComponent.html as template url + */ +@Component({ + selector: 'app-netslice-template', + templateUrl: './NetsliceTemplateComponent.html', + styleUrls: ['./NetsliceTemplateComponent.scss'] +}) +/** Exporting a class @exports NetsliceTemplateComponent */ +export class NetsliceTemplateComponent { + /** To inject services @public */ + public injector: Injector; + + /** Values for map config @public */ + public selectedRows: object[] = []; + + /** To consume REST API calls @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** handle translate @public */ + public translateService: TranslateService; + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Values for map config @public */ + public selectList: object[] = []; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Element ref for fileInput @public */ + @ViewChild('fileInput', { static: true }) public fileInput: ElementRef; + + /** To consume REST API calls @private */ + private dataService: DataService; + + /** To consume REST API calls @private */ + private restService: RestService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private networkSliceData: NetworkSliceData[] = []; + + /** variables holds file information @private */ + private fileData: string | ArrayBuffer; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/x-yaml', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '50%' }, + usageState: { title: this.translateService.instant('USAGESTATE'), width: '20%' }, + Actions: { + name: 'Actions', width: '10%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: NetworkSliceData, row: NetworkSliceData): NetworkSliceData => row, + renderComponent: NetslicePackagesActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @private */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @private */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'network-slice' }); + this.dataService.changeMessage(event.data); + } + + /** Drag and drop feature and fetchind the details of files @private */ + public filesDropped(files: FileList): void { + if (files && files.length === 1) { + this.isLoadingResults = true; + this.sharedService.getFileString(files, 'yaml').then((fileContent: String | ArrayBuffer): void => { + const apiURLHeader: APIURLHEADER = { + url: environment.NETWORKSLICETEMPLATECONTENT_URL, + httpOptions: { headers: this.headers } + }; + this.saveFileData(apiURLHeader, fileContent); + }).catch((err: string): void => { + this.isLoadingResults = false; + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + } + + /** Post the droped files and reload the page @public */ + public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void { + this.fileInput.nativeElement.value = null; + this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => { + this.notifierService.notify('success', this.translateService.instant('PAGE.NETSLICE.TEMPLATECREATEDSUCCESSFULLY')); + this.generateData(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Generate nsData object from loop and return for the datasource @public */ + public generateNetworkSliceData(networkSlicePackageData: NetworkSliceModel): NetworkSliceData { + return { + name: networkSlicePackageData.name, + identifier: networkSlicePackageData._id, + usageState: networkSlicePackageData._admin.usageState + }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL).subscribe((networkSliceList: NetworkSliceModel[]) => { + this.networkSliceData = []; + networkSliceList.forEach((networkSlicePackageData: NetworkSliceModel) => { + const networkSliceDataObj: NetworkSliceData = this.generateNetworkSliceData(networkSlicePackageData); + this.networkSliceData.push(networkSliceDataObj); + }); + if (this.networkSliceData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.networkSliceData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(() => { + this.isLoadingResults = false; + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/packages/ns-packages/NSPackagesComponent.html b/src/app/packages/ns-packages/NSPackagesComponent.html new file mode 100644 index 0000000..5b67268 --- /dev/null +++ b/src/app/packages/ns-packages/NSPackagesComponent.html @@ -0,0 +1,44 @@ + +
+
NS {{'PACKAGES' | translate}}
+ + + +
+
+
+ +
+
+ {{'DROPFILES' | translate}}
+
+
+
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/packages/ns-packages/NSPackagesComponent.scss b/src/app/packages/ns-packages/NSPackagesComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/packages/ns-packages/NSPackagesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/ns-packages/NSPackagesComponent.ts b/src/app/packages/ns-packages/NSPackagesComponent.ts new file mode 100644 index 0000000..46366e0 --- /dev/null +++ b/src/app/packages/ns-packages/NSPackagesComponent.ts @@ -0,0 +1,258 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file NS-Packages component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA } from 'CommonModel'; +import { ComposePackages } from 'ComposePackages'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { NSData, NSDDetails } from 'NSDModel'; +import { NsPackagesActionComponent } from 'NsPackagesAction'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes NSPackagesComponent.html as template url + */ +@Component({ + selector: 'app-ns-packages', + templateUrl: './NSPackagesComponent.html', + styleUrls: ['./NSPackagesComponent.scss'] +}) + +/** Exporting a class @exports NSPackagesComponent */ +export class NSPackagesComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Formation of appropriate Data for LocalDatasource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** handle translate @public */ + public translateService: TranslateService; + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Element ref for fileInput @public */ + @ViewChild('fileInput', { static: true }) public fileInput: ElementRef; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private nsData: NSData[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** variables holds file information @private */ + private fileData: string | ArrayBuffer; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); + this.modalService = this.injector.get(NgbModal); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/gzip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + shortName: { title: this.translateService.instant('SHORTNAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' }, + vendor: { title: this.translateService.instant('VENDOR'), width: '15%' }, + version: { title: this.translateService.instant('VERSION'), width: '10%' }, + Actions: { + name: 'Actions', width: '15%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: NSData, row: NSData): NSData => row, renderComponent: NsPackagesActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'ns-package' }); + this.dataService.changeMessage(event.data); + } + + /** Drag and drop feature and fetchind the details of files @public */ + public filesDropped(files: FileList): void { + if (files && files.length === 1) { + this.isLoadingResults = true; + this.sharedService.getFileString(files, 'gz').then((fileContent: ArrayBuffer): void => { + const apiURLHeader: APIURLHEADER = { + url: environment.NSDESCRIPTORSCONTENT_URL, + httpOptions: { headers: this.headers } + }; + this.saveFileData(apiURLHeader, fileContent); + }).catch((err: string): void => { + this.isLoadingResults = false; + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('GZFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + } + + /** Post the droped files and reload the page @public */ + public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void { + this.fileInput.nativeElement.value = null; + this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => { + this.notifierService.notify('success', this.translateService.instant('PAGE.NSPACKAGE.CREATEDSUCCESSFULLY')); + this.generateData(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Generate nsData object from loop and return for the datasource @public */ + public generateNSData(nsdpackagedata: NSDDetails): NSData { + return { + shortName: nsdpackagedata['short-name'], + identifier: nsdpackagedata._id, + description: nsdpackagedata.description, + vendor: nsdpackagedata.vendor, + version: nsdpackagedata.version + }; + } + + /** Fetching the data from server to Load in the smarttable @public */ + public generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL).subscribe((nsdPackageData: NSDDetails[]) => { + this.nsData = []; + nsdPackageData.forEach((nsdpackagedata: NSDDetails) => { + const nsDataObj: NSData = this.generateNSData(nsdpackagedata); + this.nsData.push(nsDataObj); + }); + if (this.nsData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.nsData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(() => { + this.isLoadingResults = false; + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + /** Handle compose new ns package method @public */ + public composeNSPackage(): void { + this.modalService.open(ComposePackages, { backdrop: 'static' }).componentInstance.params = { page: 'ns-package' }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } +} diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.html b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.html new file mode 100644 index 0000000..4e78c16 --- /dev/null +++ b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.html @@ -0,0 +1,264 @@ + + + + + + + + +
+ +
+
+
+
+
+
+
+
+ + {{'PAGE.TOPOLOGY.SELECTELEMENT' | translate}} + +
    +
  • + +  {{'PAGE.TOPOLOGY.VL' | translate}} + +
  • +
+
+
+
+
+
+
+ + {{'PAGE.TOPOLOGY.VNFD' | translate}} + +
    +
  • + +  {{ list['short-name'] }} + +
  • +
+
+
+
+
+
+
+
+
+ + + +
+
+
+ + +
{{'PAGE.TOPOLOGY.VNF' | translate}}
+ + +
{{'PAGE.TOPOLOGY.VL' | translate}}
+ + +
{{'PAGE.TOPOLOGY.CP' | translate}}
+
+
+
+
+ + +
+
+
+
+
+ \ No newline at end of file diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss new file mode 100644 index 0000000..d750ccc --- /dev/null +++ b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts new file mode 100644 index 0000000..082496e --- /dev/null +++ b/src/app/packages/ns-packages/ns-composer/NSComposerComponent.ts @@ -0,0 +1,1089 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file NS Compose Component + */ +// tslint:disable: no-increment-decrement +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, CONSTANTNUMBER, ERRORDATA, MODALCLOSERESPONSEDATA, MODALCLOSERESPONSEWITHCP } from 'CommonModel'; +import { ConfirmationTopologyComponent } from 'ConfirmationTopology'; +import * as d3 from 'd3'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import * as jsyaml from 'js-yaml'; +import { COMPOSERNODES, CONSTITUENTVNFD, GRAPHDETAILS, NSDDetails, Tick, TickPath, VLD, VNFDCONNECTIONPOINTREF } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { VNFData, VNFDDetails } from 'VNFDModel'; + +/** + * Creating component + * @Component takes NSComposerComponent.html as template url + */ +@Component({ + selector: 'app-ns-composer', + templateUrl: './NSComposerComponent.html', + styleUrls: ['./NSComposerComponent.scss'], + encapsulation: ViewEncapsulation.None +}) +/** Exporting a class @exports NSComposerComponent */ +export class NSComposerComponent { + /** To inject services @public */ + public injector: Injector; + /** View child contains graphContainer ref @public */ + @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef; + /** dataService to pass the data from one component to another @public */ + public dataService: DataService; + /** Contains VNFD Informations @public */ + public vnfdPackageDetails: VNFData = { identifier: '', shortName: '', vendor: '', description: '', version: '', id: '', name: '' }; + /** Contains VL Details @public */ + public vlDetails: VLD = { + name: '', + 'mgmt-network': true, + 'vim-network-name': '', + type: '', + id: '' + }; + /** Contains the information of the type of modification @public */ + public putType: string; + /** Conatins mousedown action @public */ + public mousedownNode: COMPOSERNODES = null; + /** Conatins mouseup action @public */ + public mouseupNode: COMPOSERNODES = null; + /** Conatins mousedownLink action @public */ + public mousedownLink: COMPOSERNODES = null; + /** Conatins current Selection node action @public */ + public currentSelectedNode: COMPOSERNODES = null; + /** Conatins current Selection node action @public */ + public currentSelectedLink: COMPOSERNODES = null; + /** Need to show the NSD Details @public */ + public isShowNSDDetails: boolean = true; + /** Contains the node information of VL @public */ + public vlNodes: {}[] = []; + /** Need to show the VL Details @public */ + public isShowVLDetails: boolean = false; + /** Contains the node information of VNF @public */ + public vnfNodes: {}[] = []; + /** contains the VNF Details @public */ + public vnfData: CONSTITUENTVNFD; + /** Need to show the VNF Details @public */ + public isShowVNFDetails: boolean = false; + /** Contains the node information of CP @public */ + public cpNodes: {}[] = []; + /** Need to show the CP Details */ + public cpData: VNFDCONNECTIONPOINTREF; + /** Need to show the VNF Details @public */ + public isShowCPDetails: boolean = false; + /** random number count @public */ + public randomNumberLength: number; + /** Contains the vnfd information @public */ + public vnfList: VNFDDetails[] = []; + /** Add the activeclass for the selected @public */ + public activeClass: string = 'active'; + /** Add the fixed class for the freeze @public */ + public fixedClass: string = 'fixed'; + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + /** Get VNF selected node @public */ + public getVNFSelectedData: VNFDDetails[]; + /** Assign the forcesimulation active @public */ + public forceSimulationActive: boolean = false; + /** Assign pinned class for the button when freezed @public */ + public classApplied: boolean = false; + /** Contains sidebar open status @public */ + public sideBarOpened: boolean = false; + /** Contains SVG attributes @private */ + // tslint:disable-next-line:no-any + private svg: any; + /** Contains the Drag line */ + // tslint:disable-next-line: no-any + private dragLine: any; + /** Contains VL node @private */ + // tslint:disable-next-line:no-any + private vlNode: any; + /** Contains VNFD node @private */ + // tslint:disable-next-line:no-any + private vnfdnode: any; + /** Contains CP node @private */ + // tslint:disable-next-line:no-any + private cpnode: any; + /** Rendered nodes represent VL @private */ + // tslint:disable-next-line:no-any + private gvlNode: any; + /** Rendered nodes represent VL @private */ + // tslint:disable-next-line:no-any + private gvnfdNode: any; + /** Rendered nodes represent VL @private */ + // tslint:disable-next-line:no-any + private gcpNode: any; + /** Contains forced node animations @private */ + // tslint:disable-next-line:no-any + private force: any; + /** Contains all the selected node @private */ + private selectedNode: COMPOSERNODES[] = []; + /** variables used for CP @private */ + private iConnectionPointRef: number = 0; + /** Contains the connected point @private */ + private connectionPoint: string; + /** Contains all the NSD information @private */ + private nsd: string; + /** Contains all the VNFD information @private */ + private vnfd: string; + /** Contains id of the node @private */ + private identifier: string; + /** Variables used for cp @private */ + private jConnectionPointRef: number = 0; + /** Contains copy of NSD information @private */ + private nsdCopy: string; + /** Contains the VNFD copy @private */ + private vnfdCopy: string; + /** Contains name of the node @private */ + private name: string; + /** Contains member vnf index value of the node @private */ + private memberVnfIndexValue: number = 0; + /** Contains path information of the node */ + // tslint:disable-next-line:no-any + private path: any; + /** Contains the node information @private */ + private nodes: COMPOSERNODES[] = []; + /** Contains the link information of nodes @private */ + private links: {}[] = []; + /** Contains the NS information @private */ + private nsData: NSDDetails; + /** Instance of the rest service @private */ + private restService: RestService; + /** Service holds the router information @private */ + private router: Router; + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + /** Controls the header form @private */ + private headers: HttpHeaders; + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + /** Contains lastkeypressed instance @private */ + private lastKeyDown: number = -1; + /** Instance of the modal service @private */ + private modalService: NgbModal; + /** Setting the Value of connection point refrence of the CP @private */ + private setVnfdConnectionPointRef: string; + /** Setting the Value of VL name for confirmation @private */ + private vlName: string; + /** Setting the Value of VNFD name for confirmation @private */ + private setVnfdName: string; + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + /** Contains selected node VLD objects @private */ + private selectedVLDResult: VLD; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.router = this.injector.get(Router); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.identifier = this.activatedRoute.snapshot.paramMap.get('id'); + this.generateData(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/zip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + /** Events handles at drag on D3 region @public */ + // tslint:disable-next-line:no-any + public drag(ev: any): void { + if (ev.target.id === 'vl') { + ev.dataTransfer.setData('text', ev.target.id); + } else { + ev.dataTransfer.setData('text', ev.target.attributes['data-id'].value); + } + } + /** On clicking redirect to NS edit page @public */ + public onEdit(): void { + this.router.navigate(['/packages/ns/edit/', this.identifier]).catch(() => { + // Catch Navigation Error + }); + } + /** Events handles drop at D3 region @public */ + public drop(ev: DragEvent): void { + event.preventDefault(); + this.name = ev.dataTransfer.getData('text'); + if (this.name === 'vl') { + this.svg.selectAll('*').remove(); + this.vldropComposer(); + } else { + this.svg.selectAll('*').remove(); + this.vnfd = ev.dataTransfer.getData('text'); + this.vnfdropComposer(); + } + } + /** Drop VL Composer Data @public */ + public vldropComposer(): void { + this.randomNumberLength = CONSTANTNUMBER.randomNumber; + const generateId: string = 'ns_vl_' + this.randomString( + this.randomNumberLength, + '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ' + ); + if (this.nsData.vld !== undefined) { + this.nsData.vld.push({ + 'vim-network-name': 'PUBLIC', + name: generateId, + 'mgmt-network': true, + type: 'ELAN', + id: generateId + }); + } else { + Object.assign(this.nsData, { + vld: [{ + 'vim-network-name': 'PUBLIC', + name: generateId, + 'mgmt-network': true, + type: 'ELAN', + id: generateId + }] + }); + } + this.putType = 'nsdadd'; + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + /** Drop VNFD Composer Data @public */ + public vnfdropComposer(): void { + if (this.nsData['constituent-vnfd'] !== undefined) { + this.nsData['constituent-vnfd'].push({ + 'vnfd-id-ref': this.vnfd, + 'member-vnf-index': ++this.memberVnfIndexValue + }); + } else { + Object.assign(this.nsData, { + 'constituent-vnfd': [{ + 'vnfd-id-ref': this.vnfd, + 'member-vnf-index': ++this.memberVnfIndexValue + }] + }); + } + this.putType = 'vnfdadd'; + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + /** Events handles allow drop on D3 region @public */ + public allowDrop(ev: DragEvent): void { + ev.preventDefault(); + } + /** Save NSD Information @public */ + public saveNSD(): void { + if (this.vnfdPackageDetails.shortName !== undefined) { + this.nsData['short-name'] = this.vnfdPackageDetails.shortName; + } + if (this.vnfdPackageDetails.vendor !== undefined) { + this.nsData.vendor = this.vnfdPackageDetails.vendor; + } + if (this.vnfdPackageDetails.description !== undefined) { + this.nsData.description = this.vnfdPackageDetails.description; + } + if (this.vnfdPackageDetails.version !== undefined) { + this.nsData.version = this.vnfdPackageDetails.version; + } + if (this.vnfdPackageDetails.id !== undefined) { + this.nsData.id = this.vnfdPackageDetails.id; + } + if (this.vnfdPackageDetails.name !== undefined) { + this.nsData.name = this.vnfdPackageDetails.name; + } + this.putType = 'nsdUpdate'; + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + /** Save Virtual Link @public */ + public saveVL(vlid: string): void { + this.nsData.vld.forEach((result: VLD) => { + if (result.id === vlid) { + result.name = this.vlDetails.name; + result['mgmt-network'] = !isNullOrUndefined(this.vlDetails['mgmt-network']) ? this.vlDetails['mgmt-network'] : true; + result['vim-network-name'] = !isNullOrUndefined(this.vlDetails['vim-network-name']) ? this.vlDetails['vim-network-name'] : ''; + result.type = this.vlDetails.type; + result.id = this.vlDetails.id; + } + }); + this.putType = 'vlUpdate'; + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + /** Add the new Data @public */ + public addData(apiURL: string, identifier: string, data: NSDDetails, putType: string): void { + this.isLoadingResults = true; + let successMessage: string = ''; + if (putType === 'nsdadd') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNSD'; + } else if (putType === 'vnfdadd') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDVNFD'; + } else if (putType === 'cpAdded') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.ADDNS'; + } else if (putType === 'nsdUpdate') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY'; + } else if (putType === 'vlUpdate') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.UPDATEDSUCCESSFULLY'; + } else if (putType === 'nsddelete') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENSD'; + } else if (putType === 'vnfddelete') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETEVNFD'; + } else if (putType === 'nsdelete') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETENS'; + } else if (putType === 'linkdelete') { + successMessage = 'PAGE.NSPACKAGE.NSCOMPOSE.DELETELINK'; + } + /** Below hide for conflicts with light weight UI */ + const apiURLHeader: APIURLHEADER = { + url: apiURL + '/' + identifier + '/nsd_content', + httpOptions: { headers: this.headers } + }; + const nsData: {} = {}; + nsData['nsd:nsd-catalog'] = {}; + nsData['nsd:nsd-catalog'].nsd = []; + nsData['nsd:nsd-catalog'].nsd.push(data); + const descriptorInfo: string = jsyaml.dump(nsData, {sortKeys: true}); + this.sharedService.targzFile({ packageType: 'nsd', id: this.identifier, descriptor: descriptorInfo }) + .then((content: ArrayBuffer): void => { + this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => { + this.generateData(); + this.notifierService.notify('success', this.translateService.instant(successMessage)); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.generateData(); + this.restService.handleError(error, 'put'); + this.isLoadingResults = false; + }); + }).catch((): void => { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + this.isLoadingResults = false; + }); + } + /** Show Info @public */ + public showInfo(): void { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Info'; + modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO'); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + // empty + } + }).catch(); + } + /** Event to freeze the animation @public */ + public onFreeze(): void { + this.classApplied = !this.classApplied; + const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass); + d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive); + if (alreadyFixedIsActive) { + this.force.stop(); + } + this.forceSimulationActive = alreadyFixedIsActive; + this.nodes.forEach((d: COMPOSERNODES) => { + d.fx = (alreadyFixedIsActive) ? null : d.x; + d.fy = (alreadyFixedIsActive) ? null : d.y; + }); + if (alreadyFixedIsActive) { + this.force.restart(); + } + } + /** Events handles when dragended @public */ + public toggleSidebar(): void { + this.sideBarOpened = !this.sideBarOpened; + this.deselectAllNodes(); + this.showRightSideInfo(true, false, false, false); + } + /** Prepare information for node creation of VNFD @private */ + private generateData(): void { + this.generateVNFData(); + this.generateDataNSDTopology(); + this.sideBarOpened = false; + } + /** Prepare the information of the VNFD @private */ + private generateVNFData(): void { + this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFDDetails[]) => { + this.vnfList = vnfdPackageData; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + /** Prepare information for node creation of NSD Topology @private */ + private generateDataNSDTopology(): void { + this.nodes = []; + this.links = []; + this.iConnectionPointRef = 0; + this.jConnectionPointRef = 0; + this.restService.getResource(environment.NSDESCRIPTORSCONTENT_URL + '/' + this.identifier).subscribe((nsData: NSDDetails) => { + delete nsData._admin; + delete nsData._id; + this.nsData = nsData; + this.vnfdPackageDetails.shortName = nsData['short-name']; + this.vnfdPackageDetails.vendor = nsData.vendor; + this.vnfdPackageDetails.description = nsData.description; + this.vnfdPackageDetails.version = nsData.version; + this.vnfdPackageDetails.id = nsData.id; + this.vnfdPackageDetails.name = nsData.name; + if (nsData.vld !== undefined) { + /** Details of the VL */ + this.nsDataVLD(nsData); + } + if (nsData['constituent-vnfd'] !== undefined) { + /** Details of the VNFD */ + this.nsDataConstituentVNFD(nsData); + } + if (nsData.vld !== undefined) { + this.nsDataVLDLinkCreation(nsData); + } + this.separateAndCreatenode(); + }, (error: ERRORDATA) => { + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + this.isLoadingResults = false; + this.isShowNSDDetails = false; + }); + } + /** nsData-vld undefined Call this function @private */ + private nsDataVLD(nsData: NSDDetails): void { + nsData.vld.forEach((res: VLD) => { + this.nodes.push({ id: res.id, reflexive: false, type: 'vld', name: res.id, selectorId: res.id }); + this.nsd = res.id; + if (res['vnfd-connection-point-ref'] !== undefined) { + res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => { + this.nodes.push( + { + id: this.nsd + ++this.iConnectionPointRef + ':' + result['vnfd-connection-point-ref'], + reflexive: false, + type: 'ns', + name: result['vnfd-connection-point-ref'], + nodeIndex: result['member-vnf-index-ref'], + selectorId: result['vnfd-connection-point-ref'] + '_' + result['member-vnf-index-ref'] + '-osm-' + this.nsd + }); + }); + } + }); + } + /** nsData constituent-vnfd undefined Call this function @private */ + private nsDataConstituentVNFD(nsData: NSDDetails): void { + nsData['constituent-vnfd'].forEach((res: CONSTITUENTVNFD) => { + this.nodes.push( + { + id: res['vnfd-id-ref'] + ':' + res['member-vnf-index'], + reflexive: false, + type: 'vnfd', + name: res['vnfd-id-ref'], + nodeIndex: res['member-vnf-index'], + selectorId: res['vnfd-id-ref'] + '_' + res['member-vnf-index'] + }); + this.vnfd = res['vnfd-id-ref']; + this.memberVnfIndexValue = res['member-vnf-index']; + }); + } + + /** nsData-vld undefined Call this function @private */ + private nsDataVLDLinkCreation(nsData: NSDDetails): void { + nsData.vld.forEach((res: VLD) => { + this.nsdCopy = res.id; + if (res['vnfd-connection-point-ref'] !== undefined) { + this.nsDataVNFDConnectionPointRefrence(res); + } + }); + } + /** nsData-vnfd-connection-point-ref undefined Call this function @private */ + private nsDataVNFDConnectionPointRefrence(res: VLD): void { + res['vnfd-connection-point-ref'].forEach((result: VNFDCONNECTIONPOINTREF) => { + this.connectionPoint = this.nsdCopy + ++this.jConnectionPointRef + ':' + result['vnfd-connection-point-ref']; + this.vnfdCopy = result['vnfd-id-ref'] + ':' + result['member-vnf-index-ref']; + const connectionPointPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.connectionPoint); + const nsdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.nsdCopy); + const vnfdPos: number = this.nodes.map((e: COMPOSERNODES) => { return e.id; }).indexOf(this.vnfdCopy); + this.links.push( + { + source: this.nodes[connectionPointPos], + target: this.nodes[nsdPos] + }, + { + source: this.nodes[connectionPointPos], + target: this.nodes[vnfdPos] + }); + }); + } + /** Generate random string @private */ + private randomString(length: number, chars: string): string { + let result: string = ''; + for (let randomStringRef: number = length; randomStringRef > 0; --randomStringRef) { + result += chars[Math.floor(Math.random() * chars.length)]; + } + return result; + } + /** Separate and create node @private */ + private separateAndCreatenode(): void { + this.seprateNodes(this.nodes); + this.createnode(this.nodes); + this.isLoadingResults = false; + } + /** Get the default Configuration of containers @private */ + private getGraphContainerAttr(): GRAPHDETAILS { + return { + width: 700, + height: 400, + nodeHeight: 50, + nodeWidth: 35, + textX: -35, + textY: 30, + radius: 5, + distance: 50, + strength: -500, + forcex: 2, + forcey: 2, + sourcePaddingYes: 17, + sourcePaddingNo: 12, + targetPaddingYes: 4, + targetPaddingNo: 3, + alphaTarget: 0.3, + imageX: -25, + imageY: -25, + shiftKeyCode: 17 + }; + } + /** Separate the nodes along with its tyep @private */ + private seprateNodes(node: COMPOSERNODES[]): void { + this.vlNodes = []; this.vnfNodes = []; this.cpNodes = []; + node.forEach((nodeList: COMPOSERNODES) => { + if (nodeList.type === 'vld') { + this.vlNodes.push(nodeList); + } else if (nodeList.type === 'vnfd') { + this.vnfNodes.push(nodeList); + } else if (nodeList.type === 'ns') { + this.cpNodes.push(nodeList); + } + }); + } + /** Node is created and render at D3 region @private */ + private createnode(node: COMPOSERNODES[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + d3.selectAll('svg#graphContainer > *').remove(); + d3.select(window).on('keydown', () => { this.keyDown(); }); + d3.select(window).on('keyup', () => { this.keyUp(); }); + this.svg = d3.select('#graphContainer') + .attr('oncontextmenu', 'return false;') + .attr('width', graphContainerAttr.width) + .attr('height', graphContainerAttr.height) + .on('mousemove', () => { this.mousemove(); }); + this.force = d3.forceSimulation() + .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength)) + .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance)) + .force('center', d3.forceCenter(graphContainerAttr.width / graphContainerAttr.forcex, + graphContainerAttr.height / graphContainerAttr.forcey)) + .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex)) + .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey)) + .on('tick', () => { this.tick(); }); + this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0'); + this.path = this.svg.append('svg:g').selectAll('path'); + this.vlNode = this.svg.append('svg:g').selectAll('vlnode'); + this.vnfdnode = this.svg.append('svg:g').selectAll('vnfdnode'); + this.cpnode = this.svg.append('svg:g').selectAll('cpnode'); + // app starts here + this.restart(node); + } + /** update force layout (called automatically each iteration) @private */ + private tick(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + // draw directed edges with proper padding from node centers + this.path.attr('class', 'link').attr('d', (d: Tick) => { + const deltaX: number = d.target.x - d.source.x; + const deltaY: number = d.target.y - d.source.y; + const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + const normX: number = deltaX / dist; + const normY: number = deltaY / dist; + const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo; + const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo; + const sourceX: number = d.source.x + (sourcePadding * normX); + const sourceY: number = d.source.y + (sourcePadding * normY); + const targetX: number = d.target.x - (targetPadding * normX); + const targetY: number = d.target.y - (targetPadding * normY); + return `M${sourceX},${sourceY}L${targetX},${targetY}`; + }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); }); + this.vlNode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + this.vnfdnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + this.cpnode.attr('transform', (t: TickPath) => `translate(${t.x},${t.y})`); + } + /** Update graph (called when needed) at D3 region @private */ + private restart(node: COMPOSERNODES[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.path = this.path.data(this.links); + this.vlNode = this.vlNode.data(this.vlNodes, (d: COMPOSERNODES) => d.id); + this.vnfdnode = this.vnfdnode.data(this.vnfNodes, (d: COMPOSERNODES) => d.id); + this.cpnode = this.cpnode.data(this.cpNodes, (d: COMPOSERNODES) => d.id); + this.resetAndCreateNodes(); + this.force.nodes(node).force('link').links(this.links); + this.force.alphaTarget(graphContainerAttr.alphaTarget).restart(); + } + /** Rest and create nodes @private */ + private resetAndCreateNodes(): void { + this.path.exit().remove(); + this.vlNode.exit().remove(); + this.vnfdnode.exit().remove(); + this.cpnode.exit().remove(); + this.getPathNodes(); + this.getVLNodes(); + this.getVNFDNodes(); + this.getCPNodes(); + this.path.merge(this.path); + this.vlNode = this.gvlNode.merge(this.vlNode); + this.vnfdnode = this.gvnfdNode.merge(this.vnfdnode); + this.cpnode = this.gcpNode.merge(this.cpnode); + } + /** setting the Path @private */ + private getPathNodes(): void { + this.path = this.path.enter().append('svg:path'); + } + /** Setting all the VL nodes @private */ + private getVLNodes(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gvlNode = this.vlNode.enter().append('svg:g'); + this.gvlNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gvlNode.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: COMPOSERNODES) => { return d.selectorId; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/VL.svg') + .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); }) + .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); }) + .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vlNode, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gvlNode.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.id); + } + /** Setting all the VNFD nodes @private */ + private getVNFDNodes(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gvnfdNode = this.vnfdnode.enter().append('svg:g'); + this.gvnfdNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gvnfdNode.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: COMPOSERNODES) => { return d.selectorId; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/VNFD.svg') + .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); }) + .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); }) + .on('click', (d: COMPOSERNODES) => { this.singleClick(this.vnfdnode, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gvnfdNode.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.id); + } + /** Setting all the CP nodes @private */ + private getCPNodes(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gcpNode = this.cpnode.enter().append('svg:g'); + this.gcpNode.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gcpNode.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: COMPOSERNODES) => { return d.selectorId; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/CP.svg') + .on('mousedown', (d: COMPOSERNODES) => { this.mouseDown(d); }) + .on('mouseup', (d: COMPOSERNODES) => { this.mouseUp(d); }) + .on('click', (d: COMPOSERNODES) => { this.singleClick(this.cpnode, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: COMPOSERNODES) => { this.getDeleteConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gcpNode.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: COMPOSERNODES) => d.id); + } + /** Events handles when mousemove it will capture the selected node data @private */ + private mousemove(): void { + if (!this.mousedownNode) { return; } + this.dragLine.attr('d', + `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`); + } + /** Get confirmation Before Deleting the Link in Topology @private */ + private getAddConfirmation(mouseData: COMPOSERNODES, getNsData: NSDDetails, addType: string, getVLDIndex: number): void { + let findVNFName: string = ''; + let findVLDID: string = ''; + if (mouseData.type === 'vld') { + findVNFName = this.mouseupNode.name; + findVLDID = this.mousedownNode.id; + } else { + findVNFName = this.mousedownNode.name; + findVLDID = this.mouseupNode.id; + } + getNsData.vld.forEach((result: VLD) => { + if (result.id === findVLDID) { + this.vlName = result.name; + this.getVNFSelectedData = this.vnfList.filter((vnfList: VNFDDetails) => vnfList.id === findVNFName); + this.setVnfdConnectionPointRef = this.getVNFSelectedData[0]['mgmt-interface'].cp; + this.setVnfdName = this.getVNFSelectedData[0].name; + this.selectedVLDResult = result; + } + }); + if (this.vlName !== undefined && this.setVnfdName !== undefined && this.setVnfdConnectionPointRef !== undefined) { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Add'; + modalRef.componentInstance.cpDetails = this.getVNFSelectedData[0]['connection-point']; + this.translateService.get('PAGE.TOPOLOGY.ADDINGCP', { + vlname: '' + this.vlName + '', + vnfdname: '' + this.setVnfdName + '', + cpname: '' + this.setVnfdConnectionPointRef + '' + }).subscribe((res: string) => { + modalRef.componentInstance.topologyname = res; + }); + modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.CONNECTIONPOINT'); + modalRef.result.then((result: MODALCLOSERESPONSEWITHCP) => { + if (result) { + this.nsData = getNsData; + this.generateCPForVNF(this.selectedVLDResult, result.connection_point, getVLDIndex); + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, getNsData, addType); + } else { + this.deselectPath(); + } + }).catch(); + } else { + this.deselectPath(); + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + } + + /** Generate connection point for vnf using vld @private */ + private generateCPForVNF(result: VLD, cp: string, getVLDIndex: number): void { + if (result['vnfd-connection-point-ref'] !== undefined) { + result['vnfd-connection-point-ref'].push({ + 'member-vnf-index-ref': getVLDIndex, + 'vnfd-connection-point-ref': cp, + 'vnfd-id-ref': this.getVNFSelectedData[0].name + }); + } else { + Object.assign(result, { + 'vnfd-connection-point-ref': [{ + 'member-vnf-index-ref': getVLDIndex, + 'vnfd-connection-point-ref': cp, + 'vnfd-id-ref': this.getVNFSelectedData[0].name + }] + }); + } + } + + /** Events handles when mousedown click it will capture the selected node data @private */ + private mouseDown(d: COMPOSERNODES): void { + event.preventDefault(); + if (d3.event.ctrlKey) { return; } + if (d3.event.shiftKey) { + if (d.type === 'vnfd') { + this.selectedNode.push(d); + } + this.mousedownNode = d; + this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode; + this.currentSelectedLink = null; + this.dragLine.style('marker-end', 'url(#end-arrow)').classed('hidden', false) + .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`); + } + } + /** Event handles when mouseup event occures @private */ + private mouseUp(d: COMPOSERNODES): void { + if (!this.mousedownNode) { return; } + this.dragLine.classed('hidden', true).style('marker-end', ''); + this.mouseupNode = d; + if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vnfd') { + const getOldVLDIndex: string[] = this.mouseupNode.id.split(':'); + const setOldVLDindex: number = +getOldVLDIndex[1]; + this.putType = 'cpAdded'; + this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex); + } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vld') { + const getOldVLDIndex: string[] = this.mousedownNode.id.split(':'); + const setOldVLDindex: number = +getOldVLDIndex[1]; + this.putType = 'cpAdded'; + this.getAddConfirmation(this.mousedownNode, this.nsData, this.putType, setOldVLDindex); + } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'ns') { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP')); + } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'ns') { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNFCP')); + } else if (this.mousedownNode.type === 'vld' && this.mouseupNode.type === 'vld') { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVL')); + } else if (this.mousedownNode.type === 'vnfd' && this.mouseupNode.type === 'vnfd') { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVNF')); + } else if (this.mousedownNode.type === 'ns' && this.mouseupNode.type === 'ns') { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKCP')); + } else { + this.deselectPath(); + this.notifierService.notify('warning', this.translateService.instant('PAGE.NSPACKAGE.NSCOMPOSE.CANNOTLINKVLVNF')); + } + this.resetMouseVars(); + // select new link + this.currentSelectedLink = d; + this.currentSelectedNode = null; + } + /** Mosue Drag Line false if it is not satisfied @private */ + private deselectPath(): void { + this.dragLine.classed('hidden', true).style('marker-end', '').attr('d', 'M0,0L0,0'); + } + /** reset Mouse varaibles @private */ + private resetMouseVars(): void { + this.mousedownNode = null; + this.mouseupNode = null; + this.mousedownLink = null; + } + /** De-select all the selected nodes @private */ + private deselectAllNodes(): void { + this.vlNode.select('image').classed(this.activeClass, false); + this.vnfdnode.select('image').classed(this.activeClass, false); + this.cpnode.select('image').classed(this.activeClass, false); + } + /** Show the right-side information @private */ + private showRightSideInfo(nsdDetails: boolean, vldDetails: boolean, vnfDeails: boolean, cpDetails: boolean): void { + this.isShowNSDDetails = nsdDetails; + this.isShowVLDetails = vldDetails; + this.isShowVNFDetails = vnfDeails; + this.isShowCPDetails = cpDetails; + } + /** Events handles when Shift Click to perform create cp @private */ + // tslint:disable-next-line: no-any + private singleClick(nodeSelected: any, d: COMPOSERNODES): void { + this.selectNodeExclusive(nodeSelected, d); + } + /** Selected nodes @private */ + // tslint:disable-next-line: no-any + private selectNodeExclusive(nodeSeleced: any, d: COMPOSERNODES): void { + const alreadyIsActive: boolean = nodeSeleced.select('#' + d.selectorId).classed(this.activeClass); + this.deselectAllNodes(); + nodeSeleced.select('#' + d.selectorId).classed(this.activeClass, !alreadyIsActive); + if (d.type === 'vld' && !alreadyIsActive) { + this.nsData.vld.forEach((result: VLD) => { + if (result.id === d.id) { + this.showRightSideInfo(false, true, false, false); + this.vlDetails = result; + } + }); + } else if (d.type === 'vnfd' && !alreadyIsActive) { + this.nsData['constituent-vnfd'].forEach((result: CONSTITUENTVNFD) => { + if (result['member-vnf-index'] === d.nodeIndex && result['vnfd-id-ref'] === d.name) { + this.showRightSideInfo(false, false, true, false); + this.vnfData = result; + } + }); + } else if (d.type === 'ns' && !alreadyIsActive) { + this.nsData.vld.forEach((result: VLD) => { + if (result['vnfd-connection-point-ref'] !== undefined) { + result['vnfd-connection-point-ref'].forEach((resultCP: VNFDCONNECTIONPOINTREF) => { + if (resultCP['member-vnf-index-ref'] === d.nodeIndex && resultCP['vnfd-connection-point-ref'] === d.name) { + this.cpData = resultCP; + this.vlDetails = result; + this.showRightSideInfo(false, false, false, true); + } + }); + } + }); + } else { + this.showRightSideInfo(true, false, false, false); + } + } + /** Get confirmation Before Deleting the Link in Topology @private */ + private getDeleteLinkConfirmation(d: Tick): void { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Delete'; + modalRef.componentInstance.topologyname = this.translateService.instant('PAGE.TOPOLOGY.LINK'); + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.LINK'; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.doubleClickLink(d); + } + }).catch(); + } + /** Events handles when Double Click to Delete the link @private */ + private doubleClickLink(d: Tick): void { + let getID: string = ''; + if (d.target.type === 'vld') { + getID = d.target.id; + } else if (d.source.type === 'vld') { + getID = d.source.id; + } + this.nodes.forEach((res: COMPOSERNODES) => { + if (res.id === getID) { + if (this.nsData.vld !== undefined) { + this.nsData.vld.forEach((vldresult: VLD) => { + if (vldresult.id === getID) { + delete vldresult['vnfd-connection-point-ref']; + } + }); + } + } + }); + this.putType = 'linkdelete'; + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + /** Get confirmation Before Deleting the Node in Topology @private */ + private getDeleteConfirmation(d: COMPOSERNODES): void { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Delete'; + modalRef.componentInstance.topologyname = d.name; + if (d.type === 'vld') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VIRTUALLINK'; + } else if (d.type === 'vnfd') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VNF'; + } else if (d.type === 'ns') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT'; + } + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.doubleClick(d); + } + }).catch(); + } + /** Events handles when Double Click to Delete @private */ + private doubleClick(d: COMPOSERNODES): void { + const deletedNode: COMPOSERNODES = d; + this.nodes.forEach((res: COMPOSERNODES) => { + if (res.id === d.id) { + if (deletedNode.type === 'vld') { + const pos: number = this.nsData.vld.map((e: VLD) => { return e.id; }).indexOf(d.id); + this.nsData.vld.splice(pos, 1); + this.putType = 'nsddelete'; + } else if (deletedNode.type === 'vnfd') { + const constituentVNFD: string[] = []; + if (this.nsData['constituent-vnfd'] !== undefined) { + this.nsData['constituent-vnfd'].forEach((ref: CONSTITUENTVNFD) => { + constituentVNFD.push(ref['vnfd-id-ref'] + ':' + ref['member-vnf-index']); + }); + } + const pos: number = constituentVNFD.map((e: string) => { return e; }).indexOf(d.id); + this.nsData['constituent-vnfd'].splice(pos, 1); + const getCP: string[] = d.id.split(':'); + const memberVnfIndexRef: number = +getCP[1]; + const vnfdIDRef: string = getCP[0]; + if (this.nsData.vld !== undefined) { + this.nsData.vld.forEach((resf: VLD) => { + if (resf['vnfd-connection-point-ref'] !== undefined) { + resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => { + if (+connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef && connectionPoint['vnfd-id-ref'] === vnfdIDRef) { + resf['vnfd-connection-point-ref'].splice(index, 1); + } + }); + } + }); + } + this.putType = 'vnfddelete'; + } else if (deletedNode.type === 'ns') { + const getCP: string[] = d.selectorId.split('-osm-'); + const memberVnfIndexRef: number = d.nodeIndex; + const vnfdIDRef: string = getCP[getCP.length - 1]; + if (this.nsData.vld !== undefined) { + this.nsData.vld.forEach((resf: VLD) => { + if (resf['vnfd-connection-point-ref'] !== undefined && resf.id === vnfdIDRef) { + resf['vnfd-connection-point-ref'].forEach((connectionPoint: VNFDCONNECTIONPOINTREF, index: number) => { + if (connectionPoint['member-vnf-index-ref'] === memberVnfIndexRef) { + resf['vnfd-connection-point-ref'].splice(index, 1); + } + }); + } + }); + } + this.putType = 'nsdelete'; + } + this.addData(environment.NSDESCRIPTORS_URL, this.identifier, this.nsData, this.putType); + } + }); + } + /** Key press event @private */ + private keyDown(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + if (this.lastKeyDown !== -1) { return; } + this.lastKeyDown = d3.event.keyCode; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gvlNode.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.gvnfdNode.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.gcpNode.call(d3.drag() + .on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended) + ); + this.svg.classed('ctrl', true); + } + } + /** Key realse event @private */ + private keyUp(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.lastKeyDown = -1; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gvlNode.on('.drag', null); + this.gvnfdNode.on('.drag', null); + this.gcpNode.on('.drag', null); + this.svg.classed('ctrl', false); + } + } + /** Events handles when dragstarted @private */ + private dragstarted(d: COMPOSERNODES): void { + d.fx = d.x; + d.fy = d.y; + } + /** Events handles when dragged @private */ + private dragged(d: COMPOSERNODES): void { + d.fx = d.x = d3.event.x; + d.fy = d.y = d3.event.y; + } + /** Events handles when dragended @private */ + private dragended(d: COMPOSERNODES): void { + if (this.forceSimulationActive) { + d.fx = null; + d.fy = null; + } else { + d.fx = d.x; + d.fy = d.y; + this.forceSimulationActive = false; + } + } + /** Events handles when node double click @private */ + private onNodedblClickToggleSidebar(): void { + this.sideBarOpened = false; + } + /** Events handles when node single click @private */ + private onNodeClickToggleSidebar(): void { + this.sideBarOpened = true; + } +} diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html new file mode 100644 index 0000000..2aa8f12 --- /dev/null +++ b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.html @@ -0,0 +1,312 @@ + + + + + + + + +
+ +
+
+
+
+
+
+
+
+ + {{'PAGE.TOPOLOGY.SELECTELEMENT' | translate}} + +
    +
  • + +  {{'PAGE.TOPOLOGY.VDU' | translate}} + +
  • +
  • + +  {{'PAGE.TOPOLOGY.CP' | translate}} + +
  • +
  • + +  {{'PAGE.TOPOLOGY.INTVL' | translate}} + +
  • +
+
+
+
+
+
+
+
+
+ + + +
+
+
+ + +
{{'PAGE.TOPOLOGY.VDU' | translate}}
+ + +
{{'PAGE.TOPOLOGY.CP' | translate}}
+ + +
{{'PAGE.TOPOLOGY.INTVL' | translate}}
+ + +
{{'PAGE.TOPOLOGY.INTCP' | translate}}
+
+
+
+
+ + +
+
+
+
+
+ \ No newline at end of file diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss new file mode 100644 index 0000000..4473c67 --- /dev/null +++ b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts new file mode 100644 index 0000000..21aad71 --- /dev/null +++ b/src/app/packages/ns-packages/vnf-composer/VNFComposerComponent.ts @@ -0,0 +1,1020 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file VNFComposerComponent + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, ViewChild, ViewEncapsulation } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { ConfirmationTopologyComponent } from 'ConfirmationTopology'; +import * as d3 from 'd3'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import * as jsyaml from 'js-yaml'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { + COMPOSERNODES, CONNECTIONPOINT, GRAPHDETAILS, InternalVLD, Tick, TickPath, + VDU, VDUInternalConnectionPoint, VLDInternalConnectionPoint, VNFDInterface, VNFDNODE +} from 'VNFDModel'; + +/** + * Creating component + * @Component takes VNFComposerComponent.html as template url + */ +@Component({ + templateUrl: './VNFComposerComponent.html', + styleUrls: ['./VNFComposerComponent.scss'], + encapsulation: ViewEncapsulation.None +}) +/** Exporting a class @exports VNFComposerComponent */ +export class VNFComposerComponent { + /** To inject services @public */ + public injector: Injector; + /** View child contains graphContainer ref @public */ + @ViewChild('graphContainer', { static: true }) public graphContainer: ElementRef; + /** dataService to pass the data from one component to another @public */ + public dataService: DataService; + /** random number count @public */ + public randomNumberLength: number; + /** Contains the vnfd information @public */ + public vnfList: string[] = []; + /** Contains node type @public */ + public nodeTypeRef: string; + /** Contains VNFD Information @public */ + public vnfdInfo: VNFDNODE = { shortName: '', description: '', version: '', id: '', name: '' }; + /** Contains right panel box information @public */ + public showRightSideInfo: string = ''; + /** Add the fixed class for the freeze @public */ + public fixedClass: string = 'fixed'; + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + /** Assign the forcesimulation active @public */ + public forceSimulationActive: boolean = false; + /** Assign pinned class for the button when freezed @public */ + public classApplied: boolean = false; + /** Contains sidebar open status @public */ + public sideBarOpened: boolean = false; + + /** Contains SVG attributes @private */ + // tslint:disable-next-line:no-any + private svg: any; + /** Contains forced node animations @private */ + // tslint:disable-next-line:no-any + private force: any; + /** Contains the Drag line */ + // tslint:disable-next-line: no-any + private dragLine: any; + /** Contains id of the node @private */ + private identifier: string; + /** Contains path information of the node */ + // tslint:disable-next-line:no-any + private path: any; + /** Contains node network @private */ + // tslint:disable-next-line:no-any + private network: any; + /** Contains node network @private */ + // tslint:disable-next-line:no-any + private virutualDeploymentUnit: any; + /** Contains node connectionPoint @private */ + // tslint:disable-next-line:no-any + private connectionPoint: any; + /** Contains node intConnectionPoint @private */ + // tslint:disable-next-line:no-any + private intConnectionPoint: any; + /** Contains the node information @private */ + private nodes: VNFDNODE[] = []; + /** Contains the link information of nodes @private */ + private links: {}[] = []; + /** Instance of the rest service @private */ + private restService: RestService; + /** Service holds the router information @private */ + private router: Router; + /** Service contails all the shared service information @private */ + private sharedService: SharedService; + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + /** Controls the header form @private */ + private headers: HttpHeaders; + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + /** Rendered nodes represent network @private */ + // tslint:disable-next-line:no-any + private gNetwork: any; + /** Rendered nodes represent VDU @private */ + // tslint:disable-next-line:no-any + private gVirutualDeploymentUnit: any; + /** Rendered nodes represent connection point @private */ + // tslint:disable-next-line:no-any + private gConnectionPoint: any; + /** Rendered nodes represent internal connection point @private */ + // tslint:disable-next-line:no-any + private gIntConnectionPoint: any; + /** Contains all the information about VNF Details @private */ + private vnfdPackageDetails: VNFDNODE; + /** Conatins mousedown action @private */ + private mousedownNode: COMPOSERNODES = null; + /** Conatins mouseup action @private */ + private mouseupNode: COMPOSERNODES = null; + /** Conatins current Selection node action @private */ + private currentSelectedNode: COMPOSERNODES = null; + /** Add the activeNode for the selected @private */ + private activeNode: string = 'active'; + /** Contains lastkeypressed instance @private */ + private lastKeyDown: number = -1; + /** Contains VDU Information @private */ + private vduInfo: VDU; + /** Contains Internal VL Information @private */ + private intvlInfo: InternalVLD; + /** Contains Connection Point Information @private */ + private cpInfo: CONNECTIONPOINT; + /** Contains Internal Connection Point Information @private */ + private intcpInfo: VLDInternalConnectionPoint; + /** Instance of the modal service @private */ + private modalService: NgbModal; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.router = this.injector.get(Router); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + } + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.identifier = this.activatedRoute.snapshot.paramMap.get('id'); + this.generateData(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/zip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** Prepare information for node creation of VNFD @public */ + public generateData(): void { + this.nodes = []; this.links = []; this.vnfdPackageDetails = null; + this.showRightSideInfo = 'vnfdInfo'; + const httpOptions: GETAPIURLHEADER = { + headers: new HttpHeaders({ + 'Content-Type': 'application/zip', + Accept: 'text/plain', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }), + responseType: 'text' + }; + this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.identifier + '/vnfd', httpOptions) + .subscribe((vnfdPackageDetails: VNFDNODE) => { + try { + const getJson: string = jsyaml.load(vnfdPackageDetails.toString(), { json: true }); + if (getJson.hasOwnProperty('vnfd-catalog')) { + this.vnfdPackageDetails = getJson['vnfd-catalog'].vnfd[0]; + } else if (getJson.hasOwnProperty('vnfd:vnfd-catalog')) { + this.vnfdPackageDetails = getJson['vnfd:vnfd-catalog'].vnfd[0]; + } else if (getJson.hasOwnProperty('vnfd')) { + // tslint:disable-next-line: no-string-literal + this.vnfdPackageDetails = getJson['vnfd'][0]; + } + this.generateCPPoint(this.vnfdPackageDetails); + this.generateVDU(this.vnfdPackageDetails); + this.generateInternalVLD(this.vnfdPackageDetails); + this.generateInternalCP(this.vnfdPackageDetails); + this.generateIntVLCPLinks(this.vnfdPackageDetails); + this.generateVDUCPLinks(this.vnfdPackageDetails); + this.createNode(this.nodes); + this.vnfdInfo.shortName = this.vnfdPackageDetails['short-name']; + this.vnfdInfo.description = this.vnfdPackageDetails.description; + this.vnfdInfo.version = this.vnfdPackageDetails.version; + this.vnfdInfo.id = this.vnfdPackageDetails.id; + this.vnfdInfo.name = this.vnfdPackageDetails.name; + } catch (e) { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error; + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + this.isLoadingResults = false; + this.showRightSideInfo = ''; + }); + } + /** Events handles at drag on D3 region @public */ + // tslint:disable-next-line:no-any + public drag(ev: any): void { + ev.dataTransfer.setData('text', ev.target.id); + } + /** Events handles drop at D3 region @public */ + public drop(ev: DragEvent): void { + ev.preventDefault(); + this.nodeTypeRef = ev.dataTransfer.getData('text'); + if (this.nodeTypeRef === 'vdu') { + this.svg.selectAll('*').remove(); + this.vduDropCompose(); + } else if (this.nodeTypeRef === 'cp') { + this.svg.selectAll('*').remove(); + this.cpDropCompose(); + } else if (this.nodeTypeRef === 'intvl') { + this.svg.selectAll('*').remove(); + this.intvlDropCompose(); + } + } + /** Events handles allow drop on D3 region @public */ + public allowDrop(ev: DragEvent): void { + ev.preventDefault(); + } + /** Generate and list CP points @public */ + public generateCPPoint(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails['connection-point'] !== undefined) { + vnfdPackageDetails['connection-point'].forEach((cp: CONNECTIONPOINT) => { + this.nodes.push({ id: cp.name, nodeTypeRef: 'cp', name: cp.name, type: cp.type }); + }); + } + } + /** Generate and list VDU @public */ + public generateVDU(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails.vdu !== undefined) { + vnfdPackageDetails.vdu.forEach((vdu: VDU) => { + this.nodes.push({ + id: vdu.name, nodeTypeRef: 'vdu', 'cloud-init-file': vdu['cloud-init-file'], count: vdu.count, description: vdu.description, + vduID: vdu.id, name: vdu.name, interface: vdu.interface, 'vm-flavor': vdu['vm-flavor'] + }); + }); + } + } + /** Generate and list Internal VLD @public */ + public generateInternalVLD(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails['internal-vld'] !== undefined) { + vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => { + this.nodes.push({ + id: internalVLD.name, nodeTypeRef: 'intvl', intVLID: internalVLD.id, + 'internal-connection-point': internalVLD['internal-connection-point'], + 'ip-profile-ref': internalVLD['ip-profile-ref'], name: internalVLD.name, 'short-name': internalVLD['short-name'], + type: internalVLD.type + }); + }); + } + } + /** Generate and list Internal CP @public */ + public generateInternalCP(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails.vdu !== undefined) { + vnfdPackageDetails.vdu.forEach((intCP: VDUInternalConnectionPoint) => { + if (intCP['internal-connection-point'] !== undefined) { + intCP['internal-connection-point'].forEach((internalCP: VDUInternalConnectionPoint) => { + this.nodes.push({ + id: internalCP.name, nodeTypeRef: 'intcp', name: internalCP.name, + 'short-name': internalCP['short-name'], type: internalCP.type + }); + }); + } + }); + } + } + /** Generate VDU External and Internal CP Links @public */ + public generateVDUCPLinks(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails.vdu !== undefined) { + vnfdPackageDetails.vdu.forEach((vdu: VDU) => { + const vduLink: string = vdu.name; + if (vdu.interface !== undefined) { + vdu.interface.forEach((interfaceDetails: VNFDInterface) => { + if (interfaceDetails['external-connection-point-ref'] !== undefined) { + this.links.push({ source: vduLink, target: interfaceDetails['external-connection-point-ref'] }); + } + if (interfaceDetails['internal-connection-point-ref'] !== undefined) { + this.links.push({ source: vduLink, target: interfaceDetails['internal-connection-point-ref'] }); + } + }); + } + }); + } + } + /** Generate Network/VLD/Internal VirtualLink, CP Links @public */ + public generateIntVLCPLinks(vnfdPackageDetails: VNFDNODE): void { + if (vnfdPackageDetails['internal-vld'] !== undefined) { + vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => { + const vldName: string = internalVLD.name; + if (internalVLD['internal-connection-point'] !== undefined) { + internalVLD['internal-connection-point'].forEach((intCP: VLDInternalConnectionPoint) => { + this.links.push({ source: vldName, target: intCP['id-ref'] }); + }); + } + }); + } + } + /** VNFD details can be saved on users inputs @public */ + public saveVNFD(): void { + this.vnfdPackageDetails['short-name'] = this.vnfdInfo.shortName; + this.vnfdPackageDetails.description = this.vnfdInfo.description; + this.vnfdPackageDetails.version = this.vnfdInfo.version; + this.vnfdPackageDetails.id = this.vnfdInfo.id; + this.vnfdPackageDetails.name = this.vnfdInfo.name; + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + delete this.vnfdPackageDetails.shortName; + } + /** VDU details can be saved on users inputs @public */ + public saveVDU(vduID: string): void { + this.vnfdPackageDetails.vdu.forEach((ref: VDU) => { + if (ref.id === vduID) { + ref.count = this.vduInfo.count; + ref.description = this.vduInfo.description; + ref.image = this.vduInfo.image; + ref.id = this.vduInfo.id; + ref.name = this.vduInfo.name; + } + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** IntVL details can be saved on users inputs @public */ + public saveIntVL(intVLID: string): void { + this.vnfdPackageDetails['internal-vld'].forEach((ref: InternalVLD) => { + if (ref.id === intVLID) { + ref['short-name'] = this.intvlInfo.shortName; + ref.name = this.intvlInfo.name; + ref.type = this.intvlInfo.type; + ref['ip-profile-ref'] = !isNullOrUndefined(this.intvlInfo.ipProfileRef) ? this.intvlInfo.ipProfileRef : ''; + ref.id = this.intvlInfo.id; + delete ref.shortName; + delete ref.ipProfileRef; + } + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** IntVL details can be saved on users inputs @public */ + public saveCP(cpName: string): void { + this.vnfdPackageDetails['connection-point'].forEach((ref: CONNECTIONPOINT) => { + if (ref.name === cpName) { + if (!isNullOrUndefined(this.cpInfo.type)) { + ref.type = this.cpInfo.type; + } + ref.name = this.cpInfo.name; + } + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** Edit topology @public */ + public onEdit(): void { + this.router.navigate(['/packages/vnf/edit/', this.identifier]).catch(); + } + /** Show Info @public */ + public showInfo(): void { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Info'; + modalRef.componentInstance.topologytitle = this.translateService.instant('PAGE.TOPOLOGY.INFO'); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + // empty + } + }).catch(); + } + /** Event to freeze the animation @public */ + public onFreeze(): void { + this.classApplied = !this.classApplied; + const alreadyFixedIsActive: boolean = d3.select('svg#graphContainer').classed(this.fixedClass); + d3.select('svg#graphContainer').classed(this.fixedClass, !alreadyFixedIsActive); + if (alreadyFixedIsActive) { + this.force.stop(); + } + this.forceSimulationActive = alreadyFixedIsActive; + this.nodes.forEach((d: COMPOSERNODES) => { + d.fx = (alreadyFixedIsActive) ? null : d.x; + d.fy = (alreadyFixedIsActive) ? null : d.y; + }); + if (alreadyFixedIsActive) { + this.force.restart(); + } + } + /** Events handles when dragended @public */ + public toggleSidebar(): void { + this.sideBarOpened = !this.sideBarOpened; + this.deselectAllNodes(); + this.showRightSideInfo = 'vnfdInfo'; + } + /** Get the default Configuration of containers @private */ + private getGraphContainerAttr(): GRAPHDETAILS { + return { + width: 700, + height: 400, + nodeHeight: 50, + nodeWidth: 35, + textX: -35, + textY: 30, + radius: 5, + distance: 50, + strength: -500, + forcex: 2, + forcey: 2, + sourcePaddingYes: 17, + sourcePaddingNo: 12, + targetPaddingYes: 4, + targetPaddingNo: 3, + alphaTarget: 0.3, + imageX: -25, + imageY: -25, + shiftKeyCode: 17 + }; + } + /** Node is created and render at D3 region @private */ + private createNode(nodes: VNFDNODE[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + d3.selectAll('svg#graphContainer > *').remove(); + d3.select(window).on('keydown', () => { this.keyDown(); }); + d3.select(window).on('keyup', () => { this.keyUp(); }); + this.svg = d3.select('#graphContainer').attr('oncontextmenu', 'return false;').attr('width', graphContainerAttr.width) + .attr('height', graphContainerAttr.height).on('mousemove', () => { this.mousemove(); }); + this.force = d3.forceSimulation() + .force('link', d3.forceLink().id((d: TickPath) => d.id).distance(graphContainerAttr.distance)) + .force('charge', d3.forceManyBody().strength(graphContainerAttr.strength)) + .force('x', d3.forceX(graphContainerAttr.width / graphContainerAttr.forcex)) + .force('y', d3.forceY(graphContainerAttr.height / graphContainerAttr.forcey)) + .on('tick', () => { this.tick(); }); + this.path = this.svg.append('svg:g').selectAll('path'); + this.dragLine = this.svg.append('svg:path').attr('class', 'link dragline hidden').attr('d', 'M0,0L0,0'); + this.network = this.svg.append('svg:g').selectAll('network'); + this.virutualDeploymentUnit = this.svg.append('svg:g').selectAll('virutualDeploymentUnit'); + this.connectionPoint = this.svg.append('svg:g').selectAll('connectionPoint'); + this.intConnectionPoint = this.svg.append('svg:g').selectAll('intConnectionPoint'); + this.restart(nodes); + } + /** Update force layout (called automatically each iteration) @private */ + private tick(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.path.attr('d', (d: Tick) => { + const deltaX: number = d.target.x - d.source.x; const deltaY: number = d.target.y - d.source.y; + const dist: number = Math.sqrt(deltaX * deltaX + deltaY * deltaY); + const normX: number = deltaX / dist; const normY: number = deltaY / dist; + const sourcePadding: number = d.left ? graphContainerAttr.sourcePaddingYes : graphContainerAttr.sourcePaddingNo; + const targetPadding: number = d.right ? graphContainerAttr.targetPaddingYes : graphContainerAttr.targetPaddingNo; + const sourceX: number = d.source.x + (sourcePadding * normX); const sourceY: number = d.source.y + (sourcePadding * normY); + const targetX: number = d.target.x - (targetPadding * normX); const targetY: number = d.target.y - (targetPadding * normY); + return `M${sourceX},${sourceY}L${targetX},${targetY}`; + }).on('dblclick', (d: Tick) => { this.getDeleteLinkConfirmation(d); }); + this.network.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`); + this.virutualDeploymentUnit.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`); + this.connectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`); + this.intConnectionPoint.attr('transform', (d: TickPath) => `translate(${d.x},${d.y})`); + } + /** Update graph (called when needed) @private */ + private restart(nodes: VNFDNODE[]): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.path = this.path.data(this.links); + const cpNodes: {}[] = []; const vduNodes: {}[] = []; const vlNodes: {}[] = []; const intcpNodes: {}[] = []; //Nodes are known by id + nodes.forEach((nodeList: VNFDNODE) => { + if (nodeList.nodeTypeRef === 'cp') { cpNodes.push(nodeList); } + else if (nodeList.nodeTypeRef === 'vdu') { vduNodes.push(nodeList); } + else if (nodeList.nodeTypeRef === 'intvl') { vlNodes.push(nodeList); } + else if (nodeList.nodeTypeRef === 'intcp') { intcpNodes.push(nodeList); } + }); + this.network = this.network.data(vlNodes, (d: { id: number }) => d.id); + this.virutualDeploymentUnit = this.virutualDeploymentUnit.data(vduNodes, (d: { id: number }) => d.id); + this.connectionPoint = this.connectionPoint.data(cpNodes, (d: { id: number }) => d.id); + this.intConnectionPoint = this.intConnectionPoint.data(intcpNodes, (d: { id: number }) => d.id); + this.resetAndCreateNodes(); + this.force.nodes(nodes).force('link').links(this.links); //Set the graph in motion + this.force.alphaTarget(graphContainerAttr.alphaTarget).restart(); + } + /** Rest and create nodes @private */ + private resetAndCreateNodes(): void { + this.path.exit().remove(); + this.network.exit().remove(); + this.virutualDeploymentUnit.exit().remove(); + this.connectionPoint.exit().remove(); + this.intConnectionPoint.exit().remove(); + this.getPathNodes(); + this.getgNetwork(); + this.getgVirutualDeploymentUnit(); + this.getgConnectionPoint(); + this.getgIntConnectionPoint(); + this.network = this.gNetwork.merge(this.network); + this.virutualDeploymentUnit = this.gVirutualDeploymentUnit.merge(this.virutualDeploymentUnit); + this.connectionPoint = this.gConnectionPoint.merge(this.connectionPoint); + this.intConnectionPoint = this.gIntConnectionPoint.merge(this.intConnectionPoint); + this.path.merge(this.path); + } + /** Setting the Path @private */ + private getPathNodes(): void { + this.path = this.path.enter().append('svg:path').attr('class', 'link'); + } + /** Settings all the network attributes of nodes @private */ + private getgNetwork(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gNetwork = this.network.enter().append('svg:g'); + this.gNetwork.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gNetwork.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: VNFDNODE) => { return d.id; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/INTVL.svg') + .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); }) + .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); }) + .on('click', (d: VNFDNODE) => { this.singleClick(this.network, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gNetwork.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: { id: number }) => d.id); + } + /** Settings all the connection point attributes of nodes @private */ + private getgVirutualDeploymentUnit(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gVirutualDeploymentUnit = this.virutualDeploymentUnit.enter().append('svg:g'); + this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gVirutualDeploymentUnit.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: VNFDNODE) => { return d.id; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/VDU.svg') + .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); }) + .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); }) + .on('click', (d: VNFDNODE) => { this.singleClick(this.virutualDeploymentUnit, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gVirutualDeploymentUnit.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: { id: string }) => d.id); + } + /** Settings all the connection point attributes of nodes @private */ + private getgConnectionPoint(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gConnectionPoint = this.connectionPoint.enter().append('svg:g'); + this.gVirutualDeploymentUnit.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gConnectionPoint.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: VNFDNODE) => { return d.id; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/CP-VNF.svg') + .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); }) + .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); }) + .on('click', (d: VNFDNODE) => { this.singleClick(this.connectionPoint, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gConnectionPoint.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: { id: string }) => d.id); + } + /** Settings all the internal connection point attributes of nodes @private */ + private getgIntConnectionPoint(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.gIntConnectionPoint = this.intConnectionPoint.enter().append('svg:g'); + this.gIntConnectionPoint.append('svg:circle').attr('r', graphContainerAttr.radius).style('fill', '#eeeeee'); + this.gIntConnectionPoint.append('svg:image') + .style('opacity', 1) + .attr('x', graphContainerAttr.imageX) + .attr('y', graphContainerAttr.imageY) + .attr('id', (d: VNFDNODE) => { return d.id; }) + .attr('class', 'node').attr('width', graphContainerAttr.nodeWidth).attr('height', graphContainerAttr.nodeHeight) + .attr('xlink:href', 'assets/images/INTCP.svg') + .on('mousedown', (d: VNFDNODE) => { this.mouseDown(d); }) + .on('mouseup', (d: VNFDNODE) => { this.mouseUp(d); }) + .on('click', (d: VNFDNODE) => { this.singleClick(this.intConnectionPoint, d); this.onNodeClickToggleSidebar(); }) + .on('dblclick', (d: VNFDNODE) => { this.getDeleteNodeConfirmation(d); this.onNodedblClickToggleSidebar(); }); + this.gIntConnectionPoint.append('svg:text') + .attr('class', 'node_text') + .attr('y', graphContainerAttr.textY) + .text((d: { id: string }) => d.id); + } + /** Drop VDU Composer Data @private */ + private vduDropCompose(): void { + const randomID: string = this.sharedService.randomString(); + const vduNode: VNFDNODE[] = [{ + nodeTypeRef: 'vdu', id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu', + interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {} + }]; + const nodeCopy: VNFDNODE[] = this.nodes; + Array.prototype.push.apply(vduNode, nodeCopy); + this.nodes = vduNode; + if (this.vnfdPackageDetails.vdu === undefined) { this.vnfdPackageDetails.vdu = []; } + this.vnfdPackageDetails.vdu.push({ + id: 'vdu_' + randomID, count: 1, description: '', name: 'vdu_' + randomID, image: 'ubuntu', + interface: [], 'internal-connection-point': [], 'monitoring-param': [], 'vm-flavor': {} + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** Drop CP Composer Data @private */ + private cpDropCompose(): void { + const randomID: string = this.sharedService.randomString(); + const cpNode: VNFDNODE[] = [{ nodeTypeRef: 'cp', id: 'cp_' + randomID, name: 'cp_' + randomID }]; + const nodeCopy: VNFDNODE[] = this.nodes; + Array.prototype.push.apply(cpNode, nodeCopy); + this.nodes = cpNode; + if (this.vnfdPackageDetails['connection-point'] === undefined) { + this.vnfdPackageDetails['connection-point'] = []; + } + this.vnfdPackageDetails['connection-point'].push({ + id: 'cp_' + randomID, name: 'cp_' + randomID, type: 'VPORT' + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** Drop IntVL Composer Data @private */ + private intvlDropCompose(): void { + const randomID: string = this.sharedService.randomString(); + const intvlNode: VNFDNODE[] = [{ + nodeTypeRef: 'intvl', id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID, 'ip-profile-ref': '', + type: 'ELAN' + }]; + const nodeCopy: VNFDNODE[] = this.nodes; + Array.prototype.push.apply(intvlNode, nodeCopy); + this.nodes = intvlNode; + if (this.vnfdPackageDetails['internal-vld'] === undefined) { this.vnfdPackageDetails['internal-vld'] = []; } + this.vnfdPackageDetails['internal-vld'].push({ + id: 'vnf_vl_' + randomID, name: 'vnf_vl_' + randomID, 'short-name': 'vnf_vl_' + randomID, + 'ip-profile-ref': '', type: 'ELAN', 'internal-connection-point': [] + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + /** Add the Add Nodes Data @private */ + private addNodes(apiURL: string, identifier: string, data: VNFDNODE): void { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: apiURL + '/' + identifier + '/package_content', + httpOptions: { headers: this.headers } + }; + const vnfData: {} = {}; + vnfData['vnfd:vnfd-catalog'] = {}; + vnfData['vnfd:vnfd-catalog'].vnfd = []; + vnfData['vnfd:vnfd-catalog'].vnfd.push(data); + const descriptorInfo: string = jsyaml.dump(vnfData, { sortKeys: true }); + this.sharedService.targzFile({ packageType: 'vnfd', id: this.identifier, descriptor: descriptorInfo }) + .then((content: ArrayBuffer): void => { + this.restService.putResource(apiURLHeader, content).subscribe((res: {}) => { + this.generateData(); + this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.UPDATEDSUCCESSFULLY')); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.generateData(); + this.restService.handleError(error, 'put'); + this.isLoadingResults = false; + }); + }).catch((): void => { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + this.isLoadingResults = false; + }); + } + /** Events handles when mousedown click it will capture the selected node data @private */ + private mouseDown(d: VNFDNODE): void { + event.preventDefault(); + if (d3.event.ctrlKey) { return; } + if (d3.event.shiftKey) { + this.mousedownNode = d; + this.currentSelectedNode = (this.mousedownNode === this.currentSelectedNode) ? null : this.mousedownNode; + this.dragLine.classed('hidden', false) + .attr('d', `M${this.mousedownNode.x},${this.mousedownNode.y}L${this.mousedownNode.x},${this.mousedownNode.y}`); + } + } + /** Event handles when mouseup event occures @private */ + private mouseUp(d: VNFDNODE): void { + if (!this.mousedownNode) { return; } + this.dragLine.classed('hidden', true); + this.mouseupNode = d; + if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intcp') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDINTCP')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'vdu') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVDUANDVDU')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'vdu') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDVDU')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intvl') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDVNFVL')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'intvl' && this.mouseupNode.nodeTypeRef === 'cp') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKVNFVLANDCP')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'intcp' && this.mouseupNode.nodeTypeRef === 'cp') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKINTCPANDCP')); + this.deselectPath(); + } + else if (this.mousedownNode.nodeTypeRef === 'cp' && this.mouseupNode.nodeTypeRef === 'intcp') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.CANNOTLINKCPANDINTCP')); + this.deselectPath(); + } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'cp') { + this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => { + if (vduDetails.id === this.mousedownNode.id) { + if (vduDetails.interface === undefined) { vduDetails.interface = []; } + vduDetails.interface.push({ + 'external-connection-point-ref': this.mouseupNode.id, 'mgmt-interface': true, + name: 'eth_' + this.sharedService.randomString(), + 'virtual-interface': { type: 'VIRTIO' }, + type: 'EXTERNAL' + }); + if (vduDetails['internal-connection-point'] === undefined) { + vduDetails['internal-connection-point'] = []; + } + if (vduDetails['monitoring-param'] === undefined) { + vduDetails['monitoring-param'] = []; + } + if (vduDetails['vm-flavor'] === undefined) { + vduDetails['vm-flavor'] = {}; + } + } + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + this.deselectPath(); + } else if (this.mousedownNode.nodeTypeRef === 'vdu' && this.mouseupNode.nodeTypeRef === 'intvl') { + const setIntCP: string = 'intcp_' + this.sharedService.randomString(); + this.vnfdPackageDetails['internal-vld'].forEach((vldInternal: InternalVLD) => { + if (vldInternal.id === this.mouseupNode.id) { + if (vldInternal['internal-connection-point'] === undefined) { vldInternal['internal-connection-point'] = []; } + vldInternal['internal-connection-point'].push({ 'id-ref': setIntCP }); + } + }); + this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => { + if (vduDetails.id === this.mousedownNode.id) { + if (vduDetails.interface === undefined) { + vduDetails.interface = []; + } + vduDetails.interface.push({ + 'internal-connection-point-ref': setIntCP, name: 'int_' + setIntCP, type: 'INTERNAL', 'virtual-interface': { type: 'VIRTIO' } + }); + if (vduDetails['internal-connection-point'] === undefined) { + vduDetails['internal-connection-point'] = []; + } + vduDetails['internal-connection-point'].push({ + id: setIntCP, name: setIntCP, 'short-name': setIntCP, type: 'VPORT' + }); + } + }); + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + this.deselectPath(); + } + else { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION')); + this.deselectPath(); + } + this.resetMouseActions(); + this.currentSelectedNode = null; + } + /** Events handles when mousemove it will capture the selected node data @private */ + private mousemove(): void { + if (!this.mousedownNode) { return; } + this.dragLine.attr('d', + `M${this.mousedownNode.x},${this.mousedownNode.y}L${d3.mouse(d3.event.currentTarget)[0]},${d3.mouse(d3.event.currentTarget)[1]}`); + } + /** reset Mouse varaibles @private */ + private resetMouseActions(): void { + this.mousedownNode = null; + this.mouseupNode = null; + } + /** Key press event @private */ + private keyDown(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + if (this.lastKeyDown !== -1) { return; } + this.lastKeyDown = d3.event.keyCode; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gNetwork.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)); + this.gVirutualDeploymentUnit.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)); + this.gConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)); + this.gIntConnectionPoint.call(d3.drag().on('start', this.dragstarted).on('drag', this.dragged).on('end', this.dragended)); + this.svg.classed('ctrl', true); + } + } + /** Key realse event @private */ + private keyUp(): void { + const graphContainerAttr: GRAPHDETAILS = this.getGraphContainerAttr(); + this.lastKeyDown = -1; + if (d3.event.keyCode === graphContainerAttr.shiftKeyCode) { + this.gNetwork.on('.drag', null); + this.gVirutualDeploymentUnit.on('.drag', null); + this.gConnectionPoint.on('.drag', null); + this.gIntConnectionPoint.on('.drag', null); + this.svg.classed('ctrl', false); + } + } + /** Mosue Drag Line false if it is not satisfied @private */ + private deselectPath(): void { + this.dragLine.classed('hidden', true).attr('d', 'M0,0L0,0'); + } + /** Events handles when Shift Click to perform create cp @private */ + // tslint:disable-next-line: no-any + private singleClick(nodeSelected: any, d: VNFDNODE): void { + this.selectedNode(nodeSelected, d); + } + /** Get confirmation Before Deleting the Node in Topology @private */ + private getDeleteNodeConfirmation(d: VNFDNODE): void { + const modalRef: NgbModalRef = this.modalService.open(ConfirmationTopologyComponent, { backdrop: 'static' }); + modalRef.componentInstance.topologyType = 'Delete'; + modalRef.componentInstance.topologyname = d.name; + if (d.nodeTypeRef === 'vdu') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.VDU'; + } else if (d.nodeTypeRef === 'intvl') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTVL'; + } else if (d.nodeTypeRef === 'cp') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.CONNECTIONPOINT'; + } else if (d.nodeTypeRef === 'intcp') { + modalRef.componentInstance.topologytitle = 'PAGE.TOPOLOGY.INTCP'; + } + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.deleteNode(d); + } + }).catch(); + } + /** Delete nodes @private */ + private deleteNode(d: VNFDNODE): void { + const deletedNode: VNFDNODE = d; + this.nodes.forEach((node: VNFDNODE) => { + if (node.id === d.id) { + if (deletedNode.nodeTypeRef === 'cp') { + if (this.vnfdPackageDetails.vdu !== undefined) { + this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => { + if (vduDetails.interface !== undefined) { + const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['external-connection-point-ref']; }) + .indexOf(d.id); + if (interfacePos >= 0) { + vduDetails.interface.splice(interfacePos, 1); + } + } + }); + } + const cpPos: number = this.vnfdPackageDetails['connection-point'].map((e: CONNECTIONPOINT) => { return e.name; }) + .indexOf(d.id); + if (cpPos >= 0) { + this.vnfdPackageDetails['connection-point'].splice(cpPos, 1); + } + } else if (deletedNode.nodeTypeRef === 'intcp') { + this.vnfdPackageDetails.vdu.forEach((vduDetails: VDU) => { + // Delete Interface + const interfacePos: number = vduDetails.interface.map((e: VNFDInterface) => { return e['internal-connection-point-ref']; }) + .indexOf(d.id); + if (interfacePos >= 0) { + vduDetails.interface.splice(interfacePos, 1); + } + // Delete Internal CP + const interCPPos: number = vduDetails['internal-connection-point'] + .map((e: VDUInternalConnectionPoint) => { return e.id; }) + .indexOf(d.id); + if (interCPPos >= 0) { + vduDetails['internal-connection-point'].splice(interCPPos, 1); + } + }); + if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) { + this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => { + const interfacePos: number = internalVLD['internal-connection-point'] + .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(d.id); + if (interfacePos >= 0) { + internalVLD['internal-connection-point'].splice(interfacePos, 1); + } + }); + } + } else if (deletedNode.nodeTypeRef === 'intvl') { + const intvlPos: number = this.vnfdPackageDetails['internal-vld'] + .map((e: InternalVLD) => { return e.name; }).indexOf(d.id); + if (intvlPos >= 0) { + this.vnfdPackageDetails['internal-vld'].splice(intvlPos, 1); + } + } else if (deletedNode.nodeTypeRef === 'vdu') { + const internalCPList: string[] = []; + if (deletedNode.interface !== undefined && deletedNode.interface.length > 0) { + deletedNode.interface.forEach((interfaceNode: InternalVLD) => { + if (interfaceNode['internal-connection-point-ref'] !== undefined) { + internalCPList.push(interfaceNode['internal-connection-point-ref']); + } + }); + } + internalCPList.forEach((list: string) => { + if (this.vnfdPackageDetails['internal-vld'] !== undefined && this.vnfdPackageDetails['internal-vld'].length > 0) { + this.vnfdPackageDetails['internal-vld'].forEach((internalVLD: InternalVLD) => { + const interfacePos: number = internalVLD['internal-connection-point'] + .map((e: VLDInternalConnectionPoint) => { return e['id-ref']; }).indexOf(list); + if (interfacePos >= 0) { + internalVLD['internal-connection-point'].splice(interfacePos, 1); + } + }); + } + }); + const vduPos: number = this.vnfdPackageDetails.vdu.map((e: VDU) => { return e.id; }).indexOf(d.id); + if (vduPos >= 0) { + this.vnfdPackageDetails.vdu.splice(vduPos, 1); + } + } else { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.INVALIDSELECTION')); + } + this.addNodes(environment.VNFPACKAGES_URL, this.identifier, this.vnfdPackageDetails); + } + }); + } + /** Get confirmation before deleting the ink in Topology @private */ + private getDeleteLinkConfirmation(d: Tick): void { + this.notifierService.notify('warning', this.translateService.instant('PAGE.VNFPACKAGE.VNFCOMPOSE.YOUCANNOTDELETELINK')); + } + /** Selected nodes @private */ + // tslint:disable-next-line: no-any + private selectedNode(nodeSeleced: any, d: VNFDNODE): void { + const alreadyIsActive: boolean = nodeSeleced.select('#' + d.id).classed(this.activeNode); + this.deselectAllNodes(); + nodeSeleced.select('#' + d.id).classed(this.activeNode, !alreadyIsActive); + if (d.nodeTypeRef === 'vdu' && !alreadyIsActive) { + this.vnfdPackageDetails.vdu.forEach((res: VDU) => { + if (res.name === d.id) { + this.showRightSideInfo = 'vduInfo'; + this.vduInfo = res; + } + }); + } else if (d.nodeTypeRef === 'intvl' && !alreadyIsActive) { + this.vnfdPackageDetails['internal-vld'].forEach((res: InternalVLD) => { + if (res.name === d.id) { + this.showRightSideInfo = 'intvlInfo'; + this.intvlInfo = res; + this.intvlInfo.shortName = res['short-name']; + this.intvlInfo.ipProfileRef = res['ip-profile-ref']; + } + }); + } else if (d.nodeTypeRef === 'cp' && !alreadyIsActive) { + this.vnfdPackageDetails['connection-point'].forEach((res: CONNECTIONPOINT) => { + if (res.name === d.id) { + this.showRightSideInfo = 'cpInfo'; + this.cpInfo = res; + } + }); + } + else if (d.nodeTypeRef === 'intcp' && !alreadyIsActive) { + this.intcpInfo = d; + this.showRightSideInfo = 'intcpInfo'; + this.intcpInfo.shortName = d['short-name']; + } else { + this.showRightSideInfo = 'vnfdInfo'; + } + } + /** De-select all the selected nodes @private */ + private deselectAllNodes(): void { + this.network.select('image').classed(this.activeNode, false); + this.virutualDeploymentUnit.select('image').classed(this.activeNode, false); + this.connectionPoint.select('image').classed(this.activeNode, false); + this.intConnectionPoint.select('image').classed(this.activeNode, false); + } + /** Events handles when dragstarted @private */ + private dragstarted(d: COMPOSERNODES): void { + d.fx = d.x; + d.fy = d.y; + } + /** Events handles when dragged @private */ + private dragged(d: COMPOSERNODES): void { + d.fx = d.x = d3.event.x; + d.fy = d.y = d3.event.y; + } + /** Events handles when dragended @private */ + private dragended(d: COMPOSERNODES): void { + if (this.forceSimulationActive) { + d.fx = null; + d.fy = null; + } else { + d.fx = d.x; + d.fy = d.y; + this.forceSimulationActive = false; + } + } + /** Events handles when node double click @private */ + private onNodedblClickToggleSidebar(): void { + this.sideBarOpened = false; + } + /** Events handles when node single click @private */ + private onNodeClickToggleSidebar(): void { + this.sideBarOpened = true; + } +} diff --git a/src/app/packages/show-content/ShowContentComponent.html b/src/app/packages/show-content/ShowContentComponent.html new file mode 100644 index 0000000..dbb0935 --- /dev/null +++ b/src/app/packages/show-content/ShowContentComponent.html @@ -0,0 +1,44 @@ + + + + \ No newline at end of file diff --git a/src/app/packages/show-content/ShowContentComponent.scss b/src/app/packages/show-content/ShowContentComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/packages/show-content/ShowContentComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/show-content/ShowContentComponent.ts b/src/app/packages/show-content/ShowContentComponent.ts new file mode 100644 index 0000000..e2431e8 --- /dev/null +++ b/src/app/packages/show-content/ShowContentComponent.ts @@ -0,0 +1,82 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Show content modal + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { ERRORDATA, URLPARAMS } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; + +/** Shows json data in the information modal */ +const defaults: {} = { 'text/json': '' }; + +/** + * Creating component + * @Component takes ShowContentComponent.html as template url + */ +@Component({ + selector: 'app-show-content', + templateUrl: './ShowContentComponent.html', + styleUrls: ['./ShowContentComponent.scss'] +}) +/** Exporting a class @exports ShowContentComponent */ +export class ShowContentComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Contains files information @public */ + public contents: {}[]; + + /** Input contains component objects @public */ + @Input() public params: URLPARAMS; + + /** Instance of the rest service @private */ + private restService: RestService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate @public + */ + public ngOnInit(): void { + if (this.params.page === 'nsd') { + this.restService.getResource(environment.NSDESCRIPTORS_URL + '/' + this.params.id + '/artifacts/artifactPath') + .subscribe((nsd: {}[]) => { + this.contents = nsd; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } else if (this.params.page === 'vnfd') { + this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.params.id + '/artifacts/artifactPath') + .subscribe((vnfd: {}[]) => { + this.contents = vnfd; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + }); + } + } +} diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.html b/src/app/packages/vnf-packages/VNFPackagesComponent.html new file mode 100644 index 0000000..2d7298d --- /dev/null +++ b/src/app/packages/vnf-packages/VNFPackagesComponent.html @@ -0,0 +1,44 @@ + +
+
VNF {{'PACKAGES' | translate}}
+ + + +
+
+
+ +
+
+ {{'DROPFILES' | translate}}
+
+
+
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.scss b/src/app/packages/vnf-packages/VNFPackagesComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/packages/vnf-packages/VNFPackagesComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/packages/vnf-packages/VNFPackagesComponent.ts b/src/app/packages/vnf-packages/VNFPackagesComponent.ts new file mode 100644 index 0000000..13707e1 --- /dev/null +++ b/src/app/packages/vnf-packages/VNFPackagesComponent.ts @@ -0,0 +1,275 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file VNF Package details Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA } from 'CommonModel'; +import { ComposePackages } from 'ComposePackages'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { VNFData, VNFDDetails } from 'VNFDModel'; +import { VNFPackagesActionComponent } from 'VNFPackagesAction'; + +/** + * Creating component + * @Component takes VNFPackagesComponent.html as template url + */ +@Component({ + selector: 'app-vnf-packages', + templateUrl: './VNFPackagesComponent.html', + styleUrls: ['./VNFPackagesComponent.scss'] +}) +/** Exporting a class @exports VNFPackagesComponent */ +export class VNFPackagesComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** handle translate @public */ + public translateService: TranslateService; + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Element ref for fileInput @public */ + @ViewChild('fileInput', { static: true }) public fileInput: ElementRef; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private vnfData: VNFData[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** variables contains file information */ + private fileData: string | ArrayBuffer; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.notifierService = this.injector.get(NotifierService); + this.modalService = this.injector.get(NgbModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.headers = new HttpHeaders({ + 'Content-Type': 'application/gzip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + shortName: { title: this.translateService.instant('SHORTNAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + type: { + title: this.translateService.instant('TYPE'), + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: 'vnfd', title: 'VNF' }, + { value: 'pnfd', title: 'PNF' }, + { value: 'hnfd', title: 'HNF' } + ] + } + }, + width: '10%' + }, + description: { title: this.translateService.instant('DESCRIPTION'), width: '20%' }, + vendor: { title: this.translateService.instant('VENDOR'), width: '10%' }, + version: { title: this.translateService.instant('VERSION'), width: '10%' }, + Actions: { + name: 'Action', width: '15%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: VNFData, row: VNFData): VNFData => row, renderComponent: VNFPackagesActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** OnUserRowSelect Function @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'vnf-package' }); + this.dataService.changeMessage(event.data); + } + + /** Drag and drop feature and fetchind the details of files @public */ + public filesDropped(files: FileList): void { + if (files && files.length === 1) { + this.isLoadingResults = true; + this.sharedService.getFileString(files, 'gz').then((fileContent: ArrayBuffer): void => { + const apiURLHeader: APIURLHEADER = { + url: environment.VNFPACKAGESCONTENT_URL, + httpOptions: { headers: this.headers } + }; + this.saveFileData(apiURLHeader, fileContent); + }).catch((err: string): void => { + this.isLoadingResults = false; + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('GZFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + } + + /** Post the droped files and reload the page @public */ + public saveFileData(urlHeader: APIURLHEADER, fileData: {}): void { + this.fileInput.nativeElement.value = null; + this.restService.postResource(urlHeader, fileData).subscribe((result: {}) => { + this.notifierService.notify('success', this.translateService.instant('PAGE.VNFPACKAGE.CREATEDSUCCESSFULLY')); + this.generateData(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Generate nsData object from loop and return for the datasource @public */ + public generatevnfdData(vnfdpackagedata: VNFDDetails): VNFData { + return { + shortName: vnfdpackagedata['short-name'], + identifier: vnfdpackagedata._id, + type: vnfdpackagedata._admin.type, + description: vnfdpackagedata.description, + vendor: vnfdpackagedata.vendor, + version: vnfdpackagedata.version + }; + } + /** Handle compose new ns package method @public */ + public composeVNFPackage(): void { + this.modalService.open(ComposePackages, { backdrop: 'static' }).componentInstance.params = { page: 'vnf-package' }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.VNFPACKAGESCONTENT_URL).subscribe((vnfdPackageData: VNFDDetails[]) => { + this.vnfData = []; + vnfdPackageData.forEach((vnfdpackagedata: VNFDDetails) => { + const vnfDataObj: VNFData = this.generatevnfdData(vnfdpackagedata); + this.vnfData.push(vnfDataObj); + }); + if (this.vnfData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.vnfData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(() => { + this.isLoadingResults = false; + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/page-not-found/PageNotFoundComponent.html b/src/app/page-not-found/PageNotFoundComponent.html new file mode 100644 index 0000000..f546e3d --- /dev/null +++ b/src/app/page-not-found/PageNotFoundComponent.html @@ -0,0 +1,27 @@ + +
+ +

{{'PAGENOTFOUND.OOPS' | translate}}

+ + {{'PAGENOTFOUND.CONTENT' | translate}} + + + {{'PAGENOTFOUND.MEAN' | translate}} {{'PAGE.DASHBOARD.DASHBOARD' | translate}} + +
\ No newline at end of file diff --git a/src/app/page-not-found/PageNotFoundComponent.scss b/src/app/page-not-found/PageNotFoundComponent.scss new file mode 100644 index 0000000..0e81f2b --- /dev/null +++ b/src/app/page-not-found/PageNotFoundComponent.scss @@ -0,0 +1,29 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import "../../assets/scss/mixins/mixin"; +@import "../../assets/scss/variable"; +.page-not-found { + @include padding-percentage-value(10rem, 10rem, 10rem, 10rem); + .four-not-four { + @include font(null, 5rem, bold); + } + a:hover { + color: $primary; + text-decoration: underline; + } +} \ No newline at end of file diff --git a/src/app/page-not-found/PageNotFoundComponent.ts b/src/app/page-not-found/PageNotFoundComponent.ts new file mode 100644 index 0000000..ef515ec --- /dev/null +++ b/src/app/page-not-found/PageNotFoundComponent.ts @@ -0,0 +1,42 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Page not found component + */ +import { Component, OnInit } from '@angular/core'; + +/** + * Creating component + * @Component takes PageNotFoundComponent.html as template url + */ +@Component({ + selector: 'app-page-not-found', + templateUrl: './PageNotFoundComponent.html', + styleUrls: ['./PageNotFoundComponent.scss'] +}) +/** Exporting a class @exports PageNotFoundComponent */ +export class PageNotFoundComponent implements OnInit { + constructor() { + //donothing + } + + public ngOnInit(): void { + //donothing + } + +} diff --git a/src/app/projects/ProjectsComponent.html b/src/app/projects/ProjectsComponent.html new file mode 100644 index 0000000..ec15861 --- /dev/null +++ b/src/app/projects/ProjectsComponent.html @@ -0,0 +1,35 @@ + +
+
{{'PAGE.DASHBOARD.PROJECTS' | translate}}
+ + + +
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/projects/ProjectsComponent.scss b/src/app/projects/ProjectsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/projects/ProjectsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/projects/ProjectsComponent.ts b/src/app/projects/ProjectsComponent.ts new file mode 100644 index 0000000..7524994 --- /dev/null +++ b/src/app/projects/ProjectsComponent.ts @@ -0,0 +1,203 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Project details Component. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate'; +import { ProjectLinkComponent } from 'ProjectLinkComponent'; +import { ProjectData, ProjectDetails } from 'ProjectModel'; +import { ProjectsActionComponent } from 'ProjectsAction'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes ProjectsComponent.html as template url + */ +@Component({ + selector: 'app-projects', + templateUrl: './ProjectsComponent.html', + styleUrls: ['./ProjectsComponent.scss'] +}) +/** Exporting a class @exports ProjectsComponent */ +export class ProjectsComponent implements OnInit, OnDestroy { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Formation of appropriate Data for LocalDatasource @private */ + private projectData: ProjectData[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + this.translateService = this.injector.get(TranslateService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + projectName: { + title: this.translateService.instant('NAME'), width: '55%', sortDirection: 'asc', type: 'custom', + valuePrepareFunction: (cell: ProjectData, row: ProjectData): ProjectData => row, + renderComponent: ProjectLinkComponent + }, + modificationDate: { title: this.translateService.instant('MODIFIED'), width: '20%' }, + creationDate: { title: this.translateService.instant('CREATED'), width: '20%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: ProjectData, row: ProjectData): ProjectData => row, + renderComponent: ProjectsActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Modal service to initiate the project add @private */ + public projectAdd(): void { + const modalRef: NgbModalRef = this.modalService.open(ProjectCreateUpdateComponent, { backdrop: 'static' }); + modalRef.componentInstance.projectType = 'Add'; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.generateData(); + } + }).catch(); + } + + /** smart table listing manipulation @private */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** convert UserRowSelect Function @private */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'projects' }); + this.dataService.changeMessage(event.data); + } + + /** Generate Projects object from loop and return for the datasource @public */ + public generateProjectData(projectData: ProjectDetails): ProjectData { + return { + projectName: projectData.name, + modificationDate: this.sharedService.convertEpochTime(projectData._admin.modified), + creationDate: this.sharedService.convertEpochTime(projectData._admin.created), + id: projectData._id, + project: projectData._id + }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectDetails[]) => { + this.projectData = []; + projectsData.forEach((projectData: ProjectDetails) => { + const projectDataObj: ProjectData = this.generateProjectData(projectData); + this.projectData.push(projectDataObj); + }); + this.dataSource.load(this.projectData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/projects/ProjectsModule.ts b/src/app/projects/ProjectsModule.ts new file mode 100644 index 0000000..16147b9 --- /dev/null +++ b/src/app/projects/ProjectsModule.ts @@ -0,0 +1,86 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file SDN Controller module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataService } from 'DataService'; +import { LoaderModule } from 'LoaderModule'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate'; +import { ProjectsComponent } from 'ProjectsComponent'; + +/** + * configures routers + */ +const routes: Routes = [ + { + path: '', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: null }] + }, + component: ProjectsComponent + } +]; + +/** + * Creating @NgModule component for Modules + */ +// tslint:disable-next-line: no-stateless-class +@NgModule({ + imports: [ + FormsModule, + CommonModule, + HttpClientModule, + Ng2SmartTableModule, + FlexLayoutModule, + TranslateModule, + RouterModule.forChild(routes), + NgbModule, + PagePerRowModule, + ReactiveFormsModule, + LoaderModule, + PageReloadModule, + NgSelectModule + ], + declarations: [ + ProjectsComponent, + ProjectCreateUpdateComponent + ], + providers: [ + DataService + ], + entryComponents: [ + ProjectCreateUpdateComponent + ] +}) +/** Exporting a class @exports ProjectsModule */ +export class ProjectsModule { + // empty module +} diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.html b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.html new file mode 100644 index 0000000..c327119 --- /dev/null +++ b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.html @@ -0,0 +1,51 @@ + +
+ + + +
+ diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts new file mode 100644 index 0000000..ea0bb8a --- /dev/null +++ b/src/app/projects/project-create-update/ProjectCreateUpdateComponent.ts @@ -0,0 +1,233 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Project Add Modal + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { ProjectData, ProjectDetails } from 'ProjectModel'; +import { ProjectService } from 'ProjectService'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes ProjectCreateUpdateComponent.html as template url + */ +@Component({ + selector: 'app-project-create-update', + templateUrl: './ProjectCreateUpdateComponent.html', + styleUrls: ['./ProjectCreateUpdateComponent.scss'] +}) +/** Exporting a class @exports ProjectCreateUpdateComponent */ +export class ProjectCreateUpdateComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Instance of the rest service @public */ + public restService: RestService; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Contains the recently created project details @public */ + public recentProject: ProjectDetails; + + /** Contains project name @public */ + public projectName: string; + + /** Contains project create or edit @public */ + public getProjectType: string; + + /** To inject input type services @public */ + @Input() public projectType: string; + + /** FormGroup user Edit Account added to the form @ html @public */ + public projectForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Holds list of domains @public */ + public domains: {}[] = []; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** DataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Contains project name ref @private */ + private projectRef: string; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** ModalData instance of modal @private */ + private modalData: MODALCLOSERESPONSEDATA; + + /** Holds all project details @private */ + private projectService: ProjectService; + + constructor(injector: Injector) { + this.injector = injector; + this.formBuilder = this.injector.get(FormBuilder); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.dataService = this.injector.get(DataService); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + this.projectService = this.injector.get(ProjectService); + /** Initializing Form Action */ + this.projectForm = this.formBuilder.group({ + project_name: ['', Validators.required], + domain_name: [null] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.projectForm.controls; } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.getProjectType = this.projectType; + if (this.getProjectType === 'Edit') { + this.dataService.currentMessage.subscribe((data: ProjectData) => { + if (data.projectName !== undefined || data.projectName !== '' || data.projectName !== null) { + this.projectName = data.projectName; + this.projectRef = data.id; + } + }); + } else { + this.getProjects(); + } + } + + /** Get the last project name @public */ + public getProjects(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.PROJECTS_URL).subscribe((projects: ProjectDetails[]) => { + this.recentProject = projects.slice(-1).pop(); + this.getDomainName(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** On modal submit users acction will called @public */ + public projectAction(userType: string): void { + this.submitted = true; + this.modalData = { + message: 'Done' + }; + this.sharedService.cleanForm(this.projectForm); + if (!this.projectForm.invalid) { + if (userType === 'Add') { + this.createProject(); + } else if (userType === 'Edit') { + this.editProject(); + } + } + } + + /** Create project @public */ + public createProject(): void { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: environment.PROJECTS_URL + }; + const projectPayload: {} = { + name: this.projectForm.value.project_name, + domain_name: !isNullOrUndefined(this.projectForm.value.domain_name) ? this.projectForm.value.domain_name : undefined + }; + this.restService.postResource(apiURLHeader, projectPayload).subscribe(() => { + this.activeModal.close(this.modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('PAGE.PROJECT.CREATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + /** Edit project @public */ + public editProject(): void { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: environment.PROJECTS_URL + '/' + this.projectRef + }; + this.restService.patchResource(apiURLHeader, { name: this.projectForm.value.project_name }).subscribe(() => { + this.activeModal.close(this.modalData); + this.isLoadingResults = false; + this.projectService.setHeaderProjects(); + this.notifierService.notify('success', this.translateService.instant('PAGE.PROJECT.UPDATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'patch'); + this.isLoadingResults = false; + }); + } + /** Get domain name @private */ + private getDomainName(): void { + this.restService.getResource(environment.DOMAIN_URL).subscribe((domains: { project_domain_name: string, user_domain_name: string }) => { + let domainNames: string[] = []; + if (!isNullOrUndefined(domains.project_domain_name)) { + domainNames = domainNames.concat(domains.project_domain_name.split(',')); + } + if (!isNullOrUndefined(domains.user_domain_name)) { + domainNames = domainNames.concat(domains.user_domain_name.split(',')); + } + domainNames = Array.from(new Set(domainNames)); + this.checkDomainNames(domainNames); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** Check the domain names and create modal for domain select @private */ + private checkDomainNames(domainNames: string[]): void { + if (domainNames.length > 0) { + domainNames.forEach((domainName: string) => { + if (!domainName.endsWith(':ro')) { + this.domains.push({ id: domainName, text: domainName }); + } + }); + } + } +} diff --git a/src/app/roles/RolesComponent.html b/src/app/roles/RolesComponent.html new file mode 100644 index 0000000..da59906 --- /dev/null +++ b/src/app/roles/RolesComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/roles/RolesComponent.scss b/src/app/roles/RolesComponent.scss new file mode 100644 index 0000000..f6cb0fe --- /dev/null +++ b/src/app/roles/RolesComponent.scss @@ -0,0 +1,18 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + diff --git a/src/app/roles/RolesComponent.ts b/src/app/roles/RolesComponent.ts new file mode 100644 index 0000000..82f20b4 --- /dev/null +++ b/src/app/roles/RolesComponent.ts @@ -0,0 +1,58 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Roles component. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; + +/** + * Creating component + * @Component takes RolesComponent.html as template url + */ +@Component({ + selector: 'app-roles', + templateUrl: './RolesComponent.html', + styleUrls: ['./RolesComponent.scss'] +}) + +/** Exporting a class @exports RolesComponent */ +export class RolesComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of router service @private */ + private router: Router; + + // creates role datails component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to role datails list */ + public redirectToList(getURL: string): void { + if (getURL === '/roles') { + this.router.navigate(['/roles/details']).catch(); + } + } + +} diff --git a/src/app/roles/RolesModule.ts b/src/app/roles/RolesModule.ts new file mode 100644 index 0000000..88e1225 --- /dev/null +++ b/src/app/roles/RolesModule.ts @@ -0,0 +1,87 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ + +/** + * @file Roles Module + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; +import { LoaderModule } from 'LoaderModule'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { RolesComponent } from 'Roles'; +import { RolesActionComponent } from 'RolesAction'; +import { RolesCreateEditComponent } from 'RolesCreateEdit'; +import { RolesDetailsComponent } from 'RolesDetails'; + +/** const values for Roles Routes */ +const routes: Routes = [ + { + path: '', + component: RolesComponent, + children: [ + { + path: 'details', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: null }] + }, + component: RolesDetailsComponent + }, + { + path: 'create', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: '/roles/details' }, + { title: 'PAGE.ROLES.CREATEROLE', url: null }] + }, + component: RolesCreateEditComponent + }, + { + path: 'edit/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'ROLES', url: '/roles/details' }, + { title: '{id}', url: null }] + }, + component: RolesCreateEditComponent + } + ] + } +]; +/** + * An NgModule is a class adorned with the @NgModule decorator function. + * @NgModule takes a metadata object that tells Angular how to compile and run module code. + */ +@NgModule({ + imports: [FormsModule, ReactiveFormsModule, CommonModule, HttpClientModule, TranslateModule, + RouterModule.forChild(routes), NgbModule, PagePerRowModule, Ng2SmartTableModule, LoaderModule, PageReloadModule], + declarations: [RolesComponent, RolesDetailsComponent, RolesActionComponent, RolesCreateEditComponent], + entryComponents: [RolesActionComponent] +}) +/** + * AppModule is the Root module for application + */ +export class RolesModule { + /** Variables declared to avoid state-less class */ + private rolesModule: string; +} diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.html b/src/app/roles/roles-create-edit/RolesCreateEditComponent.html new file mode 100644 index 0000000..7bb2a1f --- /dev/null +++ b/src/app/roles/roles-create-edit/RolesCreateEditComponent.html @@ -0,0 +1,92 @@ + +
+
+ {{ (getRoleType == 'Add' ? 'PAGE.ROLES.CREATEROLE' : 'PAGE.ROLES.EDITROLE') | translate}}
+ + + +
+
+
+ + +
+ +
+
+
+ +
+ +
+
+
+
+ + +
+
+
+ + + +
+ +
+
+ +
+
+
+
{{permission.operation}}
+
+ + + +
+
+
+
+
+
+
+
+ + +
+ \ No newline at end of file diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.scss b/src/app/roles/roles-create-edit/RolesCreateEditComponent.scss new file mode 100644 index 0000000..362973a --- /dev/null +++ b/src/app/roles/roles-create-edit/RolesCreateEditComponent.scss @@ -0,0 +1,51 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; + .custom-button{ + label { + @include padding-value(2,2,2,2); + &.active { + @include background(null, $white, null, null, null); + span{ + img { + opacity: 1; + } + } + } + input[type="radio"] { + display: none; + } + span { + display: inline-block; + @include wh-value(30px,30px); + cursor: pointer; + border-radius: 50%; + @include border(all,2,solid, $white); + @include box-shadow(0px, 1px, 3px, 0px, $dark); + @include background(null, null, null, no-repeat, center); + text-align: center; + @include line-height(25px); + img { + width:50%; + opacity: 0; + @include transition(all, 0.3, null, ease); + } + } + } +} \ No newline at end of file diff --git a/src/app/roles/roles-create-edit/RolesCreateEditComponent.ts b/src/app/roles/roles-create-edit/RolesCreateEditComponent.ts new file mode 100644 index 0000000..0419c5f --- /dev/null +++ b/src/app/roles/roles-create-edit/RolesCreateEditComponent.ts @@ -0,0 +1,335 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Roles Create and Edit Component + */ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA } from 'CommonModel'; +import { environment } from 'environment'; +import * as jsonpath from 'jsonpath'; +import { RestService } from 'RestService'; +import { Permission, PermissionGroup, RoleConfig, RoleData } from 'RolesModel'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes RolesCreateEditComponent.html as template url + */ +@Component({ + selector: 'app-roles-create-edit', + templateUrl: './RolesCreateEditComponent.html', + styleUrls: ['./RolesCreateEditComponent.scss'] +}) +/** Exporting a class @exports RolesCreateEditComponent */ +export class RolesCreateEditComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** contains role permissions from config file @public */ + public rolePermissions: {}[]; + + /** contains role form group information @public */ + public roleForm: FormGroup; + + /** Instance of the rest service @public */ + public restService: RestService; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance to check role form submitted status @public */ + public submitted: boolean = false; + + /** Contains role create or edit value @public */ + public getRoleType: string; + + /** Contains view selection value either text or preview @public */ + public viewMode: string = 'text'; + + /** Contains role id value @private */ + private roleRef: string; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** contians form builder module @private */ + private formBuilder: FormBuilder; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Varaibles to hold http client @private */ + private httpClient: HttpClient; + + /** Holds the instance of activatedRoute of router service @private */ + private activatedRoute: ActivatedRoute; + + /** Holds the instance of roter service @private */ + private router: Router; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.formBuilder = this.injector.get(FormBuilder); + this.sharedService = this.injector.get(SharedService); + this.httpClient = this.injector.get(HttpClient); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.router = this.injector.get(Router); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.roleForm = this.formBuilder.group({ + roleName: ['', [Validators.required]], + permissions: [''] + }); + this.getRolePermissions(); + } + + /** Get role permission information based on action @public */ + public getRolePermissions(): void { + this.isLoadingResults = true; + this.loadPermissions().then((response: RoleConfig) => { + this.rolePermissions = response.rolePermissions; + if (this.activatedRoute.snapshot.url[0].path === 'create') { + this.getRoleType = 'Add'; + this.isLoadingResults = false; + } else { + this.getRoleType = 'Edit'; + this.getRoleData(); + } + }).catch(() => { + // Empty Block + }); + } + + /** Check Role Create or Edit and proceed action @public */ + public roleCheck(): void { + this.submitted = true; + if (!this.roleForm.valid) { + const errorIp: Element = document.querySelector('.ng-invalid[formControlName]'); + if (errorIp) { + errorIp.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + } else { + if (this.getRoleType === 'Add') { + this.createRole(); + } else { + this.editRole(); + } + } + } + + /** Convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.roleForm.controls; } + + /** Create role @private */ + public createRole(): void { + const apiURLHeader: APIURLHEADER = { + url: environment.ROLES_URL, + httpOptions: { headers: this.headers } + }; + let permissionData: Object = {}; + this.sharedService.cleanForm(this.roleForm); + if (!this.roleForm.invalid) { + if (this.viewMode === 'preview') { + this.isLoadingResults = true; + permissionData = this.generatePermissions(); + this.roleCreateAPI(apiURLHeader, permissionData); + } else { + if (this.checkPermission()) { + this.isLoadingResults = true; + permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {}; + this.roleCreateAPI(apiURLHeader, permissionData); + } + } + } + } + + /** Method to handle role create API call @public */ + public roleCreateAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void { + const postData: {} = { + name: this.roleForm.value.roleName, + permissions: !isNullOrUndefined(permissionData) ? permissionData : {} + }; + this.restService.postResource(apiURLHeader, postData).subscribe(() => { + this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.CREATEDSUCCESSFULLY')); + this.router.navigate(['/roles/details']).catch(); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + }); + } + + /** Edit role @private */ + public editRole(): void { + const apiURLHeader: APIURLHEADER = { + url: environment.ROLES_URL + '/' + this.roleRef, + httpOptions: { headers: this.headers } + }; + let permissionData: Object = {}; + this.sharedService.cleanForm(this.roleForm); + if (!this.roleForm.invalid) { + if (this.viewMode === 'preview') { + this.isLoadingResults = true; + permissionData = this.generatePermissions(); + this.roleEditAPI(apiURLHeader, permissionData); + } else { + if (this.checkPermission()) { + this.isLoadingResults = true; + permissionData = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {}; + this.roleEditAPI(apiURLHeader, permissionData); + } + } + } + } + + /** Method to handle role edit API call */ + public roleEditAPI(apiURLHeader: APIURLHEADER, permissionData: {}): void { + const postData: {} = { + name: this.roleForm.value.roleName, + permissions: !isNullOrUndefined(permissionData) ? permissionData : {} + }; + this.restService.patchResource(apiURLHeader, postData).subscribe(() => { + this.notifierService.notify('success', this.translateService.instant('PAGE.ROLES.UPDATEDSUCCESSFULLY')); + this.router.navigate(['/roles/details']).catch(); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'patch'); + }); + } + + /** Method to handle toggle role view selection @public */ + public viewSelection(): void { + if (this.viewMode === 'text' && this.checkPermission()) { + this.loadPermissions().then((response: RoleConfig) => { + this.rolePermissions = response.rolePermissions; + const permissions: {} = this.roleForm.value.permissions !== '' ? JSON.parse(this.roleForm.value.permissions) : {}; + this.filterRoleData(permissions); + this.viewMode = 'preview'; + }).catch(() => { + // Empty Block + }); + } else { + const rolePermission: {} = this.generatePermissions(); + if (Object.keys(rolePermission).length !== 0) { + this.roleForm.patchValue({ permissions: JSON.stringify(rolePermission, null, '\t') }); + } + this.viewMode = 'text'; + } + + } + + /** Generate role permission post data @private */ + private generatePermissions(): Object { + const permissions: Object = {}; + this.rolePermissions.forEach((permissionGroup: PermissionGroup) => { + if (!isNullOrUndefined(permissionGroup)) { + permissionGroup.permissions.forEach((permission: Permission) => { + if (!isNullOrUndefined(permission.value) && permission.value !== 'NA') { + permissions[permission.operation] = permission.value; + } + }); + } + }); + return permissions; + } + + /** Validation method for check permission json string @private */ + private checkPermission(): boolean { + if (this.roleForm.value.permissions) { + if (!this.sharedService.checkJson(this.roleForm.value.permissions)) { + this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEJSONERROR')); + return false; + } else { + this.roleForm.value.permissions = this.roleForm.value.permissions.replace(/'/g, '"'); + const rolePermission: {} = JSON.parse(this.roleForm.value.permissions); + for (const key of Object.keys(rolePermission)) { + if (typeof rolePermission[key] !== 'boolean') { + this.notifierService.notify('error', this.translateService.instant('PAGE.ROLES.ROLEKEYERROR', { roleKey: key })); + return false; + } + } + } + } + return true; + } + + /** Get role data from NBI based on ID and apply filter @private */ + private getRoleData(): void { + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.roleRef = this.activatedRoute.snapshot.paramMap.get('id'); + if (!isNullOrUndefined(this.roleRef)) { + this.restService.getResource(environment.ROLES_URL + '/' + this.roleRef).subscribe((data: RoleData) => { + this.roleForm.setValue({ roleName: data.name, permissions: JSON.stringify(data.permissions, null, '\t') }); + this.filterRoleData(data.permissions); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.router.navigate(['/roles/details']).catch(); + this.restService.handleError(error, 'get'); + }); + } + } + + /** Method to filter role data @private */ + private filterRoleData(permissions: {}): void { + Object.keys(permissions).forEach((permission: string) => { + jsonpath.apply(this.rolePermissions, '$..permissions[?(@.operation == "' + permission + '")]', (response: Permission) => { + if (response.operation === permission) { + response.value = permissions[permission]; + } + return response; + }); + }); + } + + /** Method to load the role permission Json file @private */ + private async loadPermissions(): Promise { + const jsonFile: string = environment.PERMISSIONS_CONFIG_FILE + '?cb=' + new Date().getTime(); + return new Promise((resolve: Function, reject: Function): void => { + this.httpClient.get(jsonFile).subscribe((response: Response) => { + resolve(response); + }, (error: {}) => { + reject(); + }); + }); + } + +} diff --git a/src/app/roles/roles-details/RolesDetailsComponent.html b/src/app/roles/roles-details/RolesDetailsComponent.html new file mode 100644 index 0000000..28a3fe7 --- /dev/null +++ b/src/app/roles/roles-details/RolesDetailsComponent.html @@ -0,0 +1,36 @@ + +
+
{{'ROLES' | translate}}
+ + + +
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/roles/roles-details/RolesDetailsComponent.scss b/src/app/roles/roles-details/RolesDetailsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/roles/roles-details/RolesDetailsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/roles/roles-details/RolesDetailsComponent.ts b/src/app/roles/roles-details/RolesDetailsComponent.ts new file mode 100644 index 0000000..2568f5a --- /dev/null +++ b/src/app/roles/roles-details/RolesDetailsComponent.ts @@ -0,0 +1,191 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Roles Deatils component. + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { ERRORDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { RolesActionComponent } from 'RolesAction'; +import { RoleData, RoleDetails } from 'RolesModel'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes RolesComponent.html as template url + */ +@Component({ + selector: 'app-roles-details', + templateUrl: './RolesDetailsComponent.html', + styleUrls: ['./RolesDetailsComponent.scss'] +}) +export class RolesDetailsComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Formation of appropriate Data for LocalDatasource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** handle translate @public */ + public translateService: TranslateService; + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Contains role details data @private */ + private roleData: RoleData[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + /** Holds the instance of roter service @private */ + private router: Router; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.router = this.injector.get(Router); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + name: { title: this.translateService.instant('NAME'), width: '30%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '35%' }, + modified: { title: this.translateService.instant('MODIFIED'), width: '15%' }, + created: { title: this.translateService.instant('CREATED'), width: '15%' }, + Actions: { + name: 'Actions', width: '5%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: RoleData, row: RoleData): RoleData => row, + renderComponent: RolesActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + topology: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** convert UserRowSelect Function @private */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'roles' }); + this.dataService.changeMessage(event.data); + } + + /** Fetching the role data from API and Load it in the smarttable @public */ + public generateData(): void { + this.isLoadingResults = true; + this.roleData = []; + this.restService.getResource(environment.ROLES_URL).subscribe((roleList: RoleDetails[]) => { + roleList.forEach((role: RoleDetails) => { + const roleDataObj: RoleData = this.generateRoleData(role); + this.roleData.push(roleDataObj); + }); + this.dataSource.load(this.roleData).then((data: boolean) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** Generate role data object and return for the datasource @public */ + public generateRoleData(roleData: RoleDetails): RoleData { + return { + name: roleData.name, + identifier: roleData._id, + modified: this.sharedService.convertEpochTime(Number(roleData._admin.modified)), + created: this.sharedService.convertEpochTime(Number(roleData._admin.created)), + permissions: roleData.permissions + }; + } + + /** Create role click handler @public */ + public createRole(): void { + this.router.navigate(['/roles/create']).catch(() => { + // Catch Navigation Error + }); + } + + /** Lifecyle hook which get trigger on component destruction @private */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + +} diff --git a/src/app/sdn-controller/SDNControllerComponent.html b/src/app/sdn-controller/SDNControllerComponent.html new file mode 100644 index 0000000..3f96ff8 --- /dev/null +++ b/src/app/sdn-controller/SDNControllerComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/sdn-controller/SDNControllerComponent.scss b/src/app/sdn-controller/SDNControllerComponent.scss new file mode 100644 index 0000000..5a72947 --- /dev/null +++ b/src/app/sdn-controller/SDNControllerComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ diff --git a/src/app/sdn-controller/SDNControllerComponent.ts b/src/app/sdn-controller/SDNControllerComponent.ts new file mode 100644 index 0000000..661882c --- /dev/null +++ b/src/app/sdn-controller/SDNControllerComponent.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file SDN Controller Component. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; + +/** + * Creating component + * @Component takes SDNControllerComponent.html as template url + */ +@Component({ + templateUrl: './SDNControllerComponent.html', + styleUrls: ['./SDNControllerComponent.scss'] +}) +/** Exporting a class @exports SDNControllerComponent */ +export class SDNControllerComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/sdn') { + this.router.navigate(['/sdn/details']).catch(); + } + } +} diff --git a/src/app/sdn-controller/SDNControllerModule.ts b/src/app/sdn-controller/SDNControllerModule.ts new file mode 100644 index 0000000..6da4a5c --- /dev/null +++ b/src/app/sdn-controller/SDNControllerModule.ts @@ -0,0 +1,82 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file SDN Controller module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { FormsModule, ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataService } from 'DataService'; +import { LoaderModule } from 'LoaderModule'; +import { NewSDNControllerComponent } from 'NewSDNControllerComponent'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { SDNControllerComponent } from 'SDNControllerComponent'; +import { SDNControllerDetailsComponent } from 'SDNControllerDetailsComponent'; +import { SDNControllerInfoComponent } from 'SDNControllerInfoComponent'; + +/** To halndle project information */ +const projectInfo: {} = localStorage.getItem('project') !== null ? { title: localStorage.getItem('project'), url: '/' } : {}; + +/** + * configures routers + */ +const routes: Routes = [ + { + path: '', + component: SDNControllerComponent, + children: [ + { + path: 'details', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'SDNCONTROLLER', url: null }] + }, + component: SDNControllerDetailsComponent + } + ] + } +]; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule, + HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule, + PagePerRowModule, LoaderModule, PageReloadModule], + declarations: [SDNControllerComponent, SDNControllerDetailsComponent, SDNControllerInfoComponent, NewSDNControllerComponent], + providers: [DataService], + entryComponents: [SDNControllerInfoComponent, NewSDNControllerComponent], + schemas: [CUSTOM_ELEMENTS_SCHEMA] +}) +/** Exporting a class @exports SDNControllerModule */ +export class SDNControllerModule { + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + //Empty Class + } +} diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html new file mode 100644 index 0000000..7b909b1 --- /dev/null +++ b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.html @@ -0,0 +1,104 @@ + +
+ + + +
+ diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts new file mode 100644 index 0000000..75fc854 --- /dev/null +++ b/src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent.ts @@ -0,0 +1,151 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file SDN Controller Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, SDN_TYPES, TYPESECTION } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes NewSDNControllerComponent.html as template url + */ +@Component({ + templateUrl: './NewSDNControllerComponent.html', + styleUrls: ['./NewSDNControllerComponent.scss'] +}) +/** Exporting a class @exports NewSDNControllerComponent */ +export class NewSDNControllerComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Set SDN Type select to empty @public */ + public sdnTypeMod: string = null; + + /** Setting SDN types in array @public */ + public sdnType: TYPESECTION[]; + + /** New SDN controller form controls using formgroup @public */ + public sdnControllerForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.formBuilder = this.injector.get(FormBuilder); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.activeModal = this.injector.get(NgbActiveModal); + this.sharedService = this.injector.get(SharedService); + + /** Initializing Form Action */ + this.sdnControllerForm = this.formBuilder.group({ + name: ['', Validators.required], + type: ['', Validators.required], + user: ['', Validators.required], + password: ['', Validators.required], + ip: ['', Validators.pattern(this.sharedService.REGX_IP_PATTERN)], + port: ['', Validators.pattern(this.sharedService.REGX_PORT_PATTERN)], + dpid: ['', Validators.pattern(this.sharedService.REGX_DPID_PATTERN)], + version: [''] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.sdnControllerForm.controls; } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.sdnType = SDN_TYPES; + this.headers = new HttpHeaders({ + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** On modal submit sdnControllerFormSubmit will called @public */ + public sdnControllerFormSubmit(): void { + this.submitted = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + this.sharedService.cleanForm(this.sdnControllerForm); + if (!this.sdnControllerForm.invalid) { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: environment.SDNCONTROLLER_URL, + httpOptions: { headers: this.headers } + }; + if (this.sdnControllerForm.value.port) { + this.sdnControllerForm.value.port = +this.sdnControllerForm.value.port; + } + if (this.sdnControllerForm.value.version === '') { + this.sdnControllerForm.value.version = undefined; + } + this.restService.postResource(apiURLHeader, this.sdnControllerForm.value) + .subscribe((result: {}) => { + this.activeModal.close(modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('PAGE.SDNCONTROLLER.CREATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + } +} diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html new file mode 100644 index 0000000..c316942 --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.html @@ -0,0 +1,43 @@ + +
+
{{'PAGE.SDNCONTROLLER.REGISTEREDSDNCONTROLLER' | translate}}
+ + + +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss new file mode 100644 index 0000000..8c2b739 --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ diff --git a/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts new file mode 100644 index 0000000..125d0f4 --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent.ts @@ -0,0 +1,249 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file SDN Controller details Component. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, SDN_TYPES } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { NewSDNControllerComponent } from 'NewSDNControllerComponent'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SDNControllerActionComponent } from 'SDNControllerActionComponent'; +import { SDNControllerList, SDNControllerModel } from 'SDNControllerModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes SDNControllerDetailsComponent.html as template url + */ +@Component({ + templateUrl: './SDNControllerDetailsComponent.html', + styleUrls: ['./SDNControllerDetailsComponent.scss'] +}) +/** Exporting a class @exports SDNControllerDetailsComponent */ +export class SDNControllerDetailsComponent implements OnInit, OnDestroy { + /** Injector to invoke other services @public */ + public injector: Injector; + + /** Selected list array @public */ + public selectList: object[] = []; + + /** Instance component are stored in settings @public */ + public settings: {} = {}; + + /** Contains objects for menu settings @public */ + public columnList: {} = {}; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.sdnOperationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.sdnOperationalStateStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.sdnOperationalStateThirdStep; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private sdnData: {}[] = []; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + this.dataService = this.injector.get(DataService); + this.modalService = this.injector.get(NgbModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateTableColumn(); + this.generateTableSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** Generate smart table row title and filters @public */ + public generateTableSettings(): void { + this.settings = { + columns: this.columnList, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** Generate smart table row title and filters @public */ + public generateTableColumn(): void { + this.columnList = { + name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + type: { + title: this.translateService.instant('TYPE'), width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: SDN_TYPES + } + } + }, + operationalState: { + title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: SDNControllerList, row: SDNControllerList): string => { + if (row.operationalState === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.operationalState}`; + } + } + }, + ip: { title: this.translateService.instant('IP'), width: '15%' }, + port: { title: this.translateService.instant('PORT'), width: '15%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, type: 'custom', + title: this.translateService.instant('ACTIONS'), + valuePrepareFunction: (cell: SDNControllerList, row: SDNControllerList): SDNControllerList => row, + renderComponent: SDNControllerActionComponent + } + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'sdn-controller' }); + this.dataService.changeMessage(event.data); + } + + /** Generate generateSDNData object from loop and return for the datasource @public */ + public generateSDNList(sdn: SDNControllerModel): SDNControllerList { + return { + name: sdn.name, + identifier: sdn._id, + type: sdn.type, + operationalState: sdn._admin.operationalState, + ip: sdn.ip, + port: sdn.port + }; + } + + /** Compose new SDN Controller @public */ + public composeSDN(): void { + const modalRef: NgbModalRef = this.modalService.open(NewSDNControllerComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.sdnData = []; + this.restService.getResource(environment.SDNCONTROLLER_URL).subscribe((sdnDetails: {}[]) => { + sdnDetails.forEach((res: SDNControllerModel) => { + const sdnDataObj: SDNControllerList = this.generateSDNList(res); + this.sdnData.push(sdnDataObj); + }); + if (this.sdnData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.sdnData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + +} diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html new file mode 100644 index 0000000..842d101 --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.html @@ -0,0 +1,90 @@ + + + + + \ No newline at end of file diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss new file mode 100644 index 0000000..c68960c --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts new file mode 100644 index 0000000..8c23d1d --- /dev/null +++ b/src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent.ts @@ -0,0 +1,96 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Info SDN Controller Info Component + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { CONFIGCONSTANT, ERRORDATA, URLPARAMS } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SDNControllerModel } from 'SDNControllerModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes SDNControllerInfoComponent.html as template url + */ +@Component({ + templateUrl: './SDNControllerInfoComponent.html', + styleUrls: ['./SDNControllerInfoComponent.scss'] +}) +/** Exporting a class @exports SDNControllerInfoComponent */ +export class SDNControllerInfoComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Input contains component objects @public */ + @Input() public params: URLPARAMS; + + /** Contains sdn details @public */ + public sdnDetails: SDNControllerModel; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.sdnOperationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.sdnOperationalStateStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.sdnOperationalStateThirdStep; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateData(); + } + + /** Generate Data function @public */ + public generateData(): void { + this.restService.getResource(environment.SDNCONTROLLER_URL + '/' + this.params.id).subscribe((sdnDetails: SDNControllerModel) => { + this.sdnDetails = sdnDetails; + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/user-settings/UserSettingsComponent.html b/src/app/user-settings/UserSettingsComponent.html new file mode 100644 index 0000000..2f878a3 --- /dev/null +++ b/src/app/user-settings/UserSettingsComponent.html @@ -0,0 +1,44 @@ + +
+ + + +
\ No newline at end of file diff --git a/src/app/user-settings/UserSettingsComponent.scss b/src/app/user-settings/UserSettingsComponent.scss new file mode 100644 index 0000000..bdfb8f2 --- /dev/null +++ b/src/app/user-settings/UserSettingsComponent.scss @@ -0,0 +1,23 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../assets/scss/mixins/mixin'; +.user-settings{ + form label{ + @include margin-value-percentage(0.5rem, auto, auto, auto); + } +} \ No newline at end of file diff --git a/src/app/user-settings/UserSettingsComponent.ts b/src/app/user-settings/UserSettingsComponent.ts new file mode 100644 index 0000000..19b525f --- /dev/null +++ b/src/app/user-settings/UserSettingsComponent.ts @@ -0,0 +1,111 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file User Settings Modal Component. + */ + +import { Component, Injector, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes UserSettingsComponent.html as template url + */ +@Component({ + templateUrl: './UserSettingsComponent.html', + styleUrls: ['./UserSettingsComponent.scss'] +}) +/** Exporting a class @exports UserSettingsComponent */ +export class UserSettingsComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Supported language list for the dropdown */ + public languageList: {}[]; + + /** FormGroup instance added to the form @ html @public */ + public usersettingsForm: FormGroup; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Form submission Add */ + public submitted: boolean = false; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Instance for translate service @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.formBuilder = this.injector.get(FormBuilder); + this.activeModal = this.injector.get(NgbActiveModal); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.initializeSettings(); + } + + /** Initialize user's settings */ + public initializeSettings(): void { + this.languageList = this.sharedService.languageCodeList(); + /** Initializing Form Action */ + this.usersettingsForm = this.formBuilder.group({ + selectedLanguage: [null, [Validators.required]] + }); + const setLanguage: string = localStorage.getItem('languageCode'); + if (setLanguage !== null && this.validateLanguageList(setLanguage)) { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.usersettingsForm.get('selectedLanguage').setValue(setLanguage); + } else { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.usersettingsForm.get('selectedLanguage').setValue('en'); + } + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.usersettingsForm.controls; } + + /** On modal submit UserSettingsSubmit will called @public */ + public usersettingsSubmit(): void { + this.submitted = true; + if (!this.usersettingsForm.invalid) { + const selectedLanguage: string = this.usersettingsForm.value.selectedLanguage; + localStorage.setItem('languageCode', this.usersettingsForm.value.selectedLanguage); + this.translateService.use(selectedLanguage); + location.reload(); + } + } + /** Validate language code in the language list @private */ + private validateLanguageList(setLanguage: string): boolean { + return this.languageList.some((item: { code: string }) => item.code === setLanguage); + } +} diff --git a/src/app/users/UsersComponent.html b/src/app/users/UsersComponent.html new file mode 100644 index 0000000..3f96ff8 --- /dev/null +++ b/src/app/users/UsersComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/users/UsersComponent.scss b/src/app/users/UsersComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/users/UsersComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/users/UsersComponent.ts b/src/app/users/UsersComponent.ts new file mode 100644 index 0000000..178b979 --- /dev/null +++ b/src/app/users/UsersComponent.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file users details Component. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; + +/** + * Creating component + * @Component takes UsersComponent.html as template url + */ +@Component({ + templateUrl: './UsersComponent.html', + styleUrls: ['./UsersComponent.scss'] +}) +/** Exporting a class @exports UsersComponent */ +export class UsersComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/users') { + this.router.navigate(['/users/details']).catch(); + } + } +} diff --git a/src/app/users/UsersModule.ts b/src/app/users/UsersModule.ts new file mode 100644 index 0000000..2014c48 --- /dev/null +++ b/src/app/users/UsersModule.ts @@ -0,0 +1,76 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Users module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FlexLayoutModule } from '@angular/flex-layout'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { AddEditUserComponent } from 'AddEditUserComponent'; +import { DataService } from 'DataService'; +import { LoaderModule } from 'LoaderModule'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { ProjectRoleComponent } from 'ProjectRoleComponent'; +import { UserDetailsComponent } from 'UserDetailsComponent'; +import { UsersComponent } from 'UsersComponent'; + +/** const values for dashboard Routes */ +const routes: Routes = [ + { + path: '', + component: UsersComponent, + children: [ + { + path: 'details', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.USERS', url: null }] + }, + component: UserDetailsComponent + } + ] + } +]; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ReactiveFormsModule, FormsModule, CommonModule, HttpClientModule, Ng2SmartTableModule, TranslateModule, + FlexLayoutModule, NgSelectModule, NgbModule, RouterModule.forChild(routes), PagePerRowModule, LoaderModule, PageReloadModule], + declarations: [UsersComponent, UserDetailsComponent, AddEditUserComponent, ProjectRoleComponent], + providers: [DataService], + entryComponents: [AddEditUserComponent, ProjectRoleComponent] +}) +/** Exporting a class @exports UsersModule */ +export class UsersModule { + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } +} diff --git a/src/app/users/add-user/AddEditUserComponent.html b/src/app/users/add-user/AddEditUserComponent.html new file mode 100644 index 0000000..b4d9d28 --- /dev/null +++ b/src/app/users/add-user/AddEditUserComponent.html @@ -0,0 +1,89 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/users/add-user/AddEditUserComponent.scss b/src/app/users/add-user/AddEditUserComponent.scss new file mode 100644 index 0000000..05f2819 --- /dev/null +++ b/src/app/users/add-user/AddEditUserComponent.scss @@ -0,0 +1,25 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; +.input-validation-msg{ + color:$red; + text-align:left; + @include padding-value(0, 0, 0, 10); + @include font(null, 11px, null); +} \ No newline at end of file diff --git a/src/app/users/add-user/AddEditUserComponent.ts b/src/app/users/add-user/AddEditUserComponent.ts new file mode 100644 index 0000000..61540e8 --- /dev/null +++ b/src/app/users/add-user/AddEditUserComponent.ts @@ -0,0 +1,255 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Add Edit Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { AbstractControl, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { AuthenticationService } from 'AuthenticationService'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes AddEditUserComponent.html as template url + */ +@Component({ + templateUrl: './AddEditUserComponent.html', + styleUrls: ['./AddEditUserComponent.scss'] +}) +/** Exporting a class @exports AddEditUserComponent */ +export class AddEditUserComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup user Edit Account added to the form @ html @public */ + public userForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Input contains Modal dialog component Instance @public */ + @Input() public userTitle: string; + + /** Input contains Modal dialog component Instance @public */ + @Input() public userType: string; + + /** Input contains Modal dialog component Instance @public */ + @Input() public userID: string; + + /** Input contains Modal dialog component Instance @public */ + @Input() public userName: string; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Holds list of domains @public */ + public domains: {}[] = []; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** ModalData instance of modal @private */ + private modalData: MODALCLOSERESPONSEDATA; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + constructor(injector: Injector) { + this.injector = injector; + this.formBuilder = this.injector.get(FormBuilder); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + this.authService = this.injector.get(AuthenticationService); + + /** Initializing Form Action */ + this.userForm = this.formBuilder.group({ + userName: ['', Validators.required], + password: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_PASSWORD_PATTERN)]], + password2: [null, Validators.required], + domain_name: [null] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.userForm.controls; } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + if (this.userType === 'add') { + this.getDomainName(); + } else if (this.userType === 'editUserName') { + this.userForm.patchValue({ userName: this.userName }); + } + } + + /** On modal submit users acction will called @public */ + public userAction(userType: string): void { + if (userType === 'editPassword') { + this.getFormControl('userName').setValidators([]); + this.getFormControl('userName').updateValueAndValidity(); + } else if (userType === 'editUserName') { + this.getFormControl('password').setValidators([]); + this.getFormControl('password').updateValueAndValidity(); + this.getFormControl('password2').setValidators([]); + this.getFormControl('password2').updateValueAndValidity(); + } + this.submitted = true; + this.modalData = { + message: 'Done' + }; + this.sharedService.cleanForm(this.userForm); + if (!this.userForm.invalid) { + if (this.userForm.value.password !== this.userForm.value.password2) { + this.notifierService.notify('error', this.translateService.instant('PAGE.USERS.PASSWORDCONFLICT')); + return; + } + if (userType === 'add') { + this.addUser(); + } else if (userType === 'editUserName' || userType === 'editPassword') { + this.editUser(); + } + } + } + + /** Add user @public */ + public addUser(): void { + this.isLoadingResults = true; + const payLoad: {} = JSON.stringify({ + username: (this.userForm.value.userName).toLowerCase(), + password: (this.userForm.value.password), + domain_name: !isNullOrUndefined(this.userForm.value.domain_name) ? this.userForm.value.domain_name : undefined + }); + const apiURLHeader: APIURLHEADER = { + url: environment.USERS_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, payLoad).subscribe((result: {}) => { + this.activeModal.close(this.modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.CREATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + + /** Edit user @public */ + public editUser(): void { + this.isLoadingResults = true; + const payLoad: { username?: string, password?: string } = {}; + if (this.userType === 'editPassword') { + payLoad.password = (this.userForm.value.password); + } else { + payLoad.username = this.userForm.value.userName.toLowerCase(); + } + const apiURLHeader: APIURLHEADER = { + url: environment.USERS_URL + '/' + this.userID, + httpOptions: { headers: this.headers } + }; + this.restService.patchResource(apiURLHeader, payLoad).subscribe((result: {}) => { + this.checkUsername(payLoad); + this.activeModal.close(this.modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'put'); + this.isLoadingResults = false; + }); + } + /** Get domain name @private */ + private getDomainName(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.DOMAIN_URL).subscribe((domains: { project_domain_name: string, user_domain_name: string }) => { + let domainNames: string[] = []; + if (!isNullOrUndefined(domains.project_domain_name)) { + domainNames = domainNames.concat(domains.project_domain_name.split(',')); + } + if (!isNullOrUndefined(domains.user_domain_name)) { + domainNames = domainNames.concat(domains.user_domain_name.split(',')); + } + domainNames = Array.from(new Set(domainNames)); + this.checkDomainNames(domainNames); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** Check the domain names and create modal for domain select @private */ + private checkDomainNames(domainNames: string[]): void { + if (domainNames.length > 0) { + domainNames.forEach((domainName: string) => { + if (!domainName.endsWith(':ro')) { + this.domains.push({ id: domainName, text: domainName }); + } + }); + } + } + + /** Used to get the AbstractControl of controlName passed @private */ + private getFormControl(controlName: string): AbstractControl { + return this.userForm.controls[controlName]; + } + + /** Method to check loggedin username and update @private */ + private checkUsername(payLoad: { username?: string }): void { + const logUsername: string = localStorage.getItem('username'); + if (this.userType === 'editUserName' && logUsername === this.userName) { + this.authService.userName.next(payLoad.username); + localStorage.setItem('username', payLoad.username); + } + } +} diff --git a/src/app/users/project-role/ProjectRoleComponent.html b/src/app/users/project-role/ProjectRoleComponent.html new file mode 100644 index 0000000..c093f37 --- /dev/null +++ b/src/app/users/project-role/ProjectRoleComponent.html @@ -0,0 +1,60 @@ + + +
+ + +
+ \ No newline at end of file diff --git a/src/app/users/project-role/ProjectRoleComponent.scss b/src/app/users/project-role/ProjectRoleComponent.scss new file mode 100644 index 0000000..031e56e --- /dev/null +++ b/src/app/users/project-role/ProjectRoleComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/users/project-role/ProjectRoleComponent.ts b/src/app/users/project-role/ProjectRoleComponent.ts new file mode 100644 index 0000000..f5bb772 --- /dev/null +++ b/src/app/users/project-role/ProjectRoleComponent.ts @@ -0,0 +1,236 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Project Role Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { AbstractControl, FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { ProjectData } from 'ProjectModel'; +import { ProjectService } from 'ProjectService'; +import { RestService } from 'RestService'; +import { RoleData } from 'RolesModel'; +import { ProjectRoleMappings, UserDetail, UserRoleMap } from 'UserModel'; + +/** + * Creating component + * @Component takes ProjectRole.html as template url + */ +@Component({ + templateUrl: './ProjectRoleComponent.html', + styleUrls: ['./ProjectRoleComponent.scss'] +}) +/** Exporting a class @exports ProjectRoleComponent */ +export class ProjectRoleComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup user Edit Account added to the form @ html @public */ + public projectRoleForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Input contains Modal dialog component Instance @private */ + @Input() public userTitle: string; + + /** Input contains Modal dialog component Instance @private */ + @Input() public userID: string; + + /** Contains user details information @public */ + public userDetails: UserDetail; + + /** Project Role Mapping @public */ + public projectRoleMap: UserRoleMap = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Contains project information @public */ + public projects: ProjectData[] = []; + + /** Contains roles information @public */ + public roles: RoleData[] = []; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Project Role Form array @private */ + private projectRoleFormArray: FormArray; + + /** Holds all project details @private */ + private projectService: ProjectService; + + constructor(injector: Injector) { + this.injector = injector; + this.formBuilder = this.injector.get(FormBuilder); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.projectService = this.injector.get(ProjectService); + this.initializeForm(); + } + + /** Generate primitive params @public */ + get projectRoleParamsBuilder(): FormGroup { + return this.formBuilder.group({ + project_name: [null, [Validators.required]], + role_name: [null, [Validators.required]] + }); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.getProjects(); + this.generateData(); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.projectRoleForm.controls; } + + /** Initializing Form Action @public */ + public initializeForm(): void { + this.projectRoleForm = this.formBuilder.group({ + project_role_mappings: this.formBuilder.array([]) + }); + } + + /** Handle FormArray Controls @public */ + public getControls(): AbstractControl[] { + // tslint:disable-next-line:no-backbone-get-set-outside-model + return (this.projectRoleForm.get('project_role_mappings') as FormArray).controls; + } + + /** Fetching the data from server to Load in the smarttable @public */ + public generateData(): void { + if (this.userID !== '') { + this.isLoadingResults = true; + this.restService.getResource(environment.USERS_URL + '/' + this.userID).subscribe((userDetails: UserDetail) => { + this.userDetails = userDetails; + this.loadMapping(); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }); + } + } + /** Fetching the projects information @public */ + public getProjects(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.PROJECTS_URL).subscribe((projectsData: ProjectData[]) => { + this.projects = projectsData; + this.getRoles(); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }); + } + + /** Fetching the Roles information @public */ + public getRoles(): void { + this.restService.getResource(environment.ROLES_URL).subscribe((rolesData: RoleData[]) => { + this.roles = rolesData; + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }); + } + + /** Set all roles and project values to the form @public */ + public loadMapping(): void { + this.userDetails.project_role_mappings.forEach((data: ProjectRoleMappings) => { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.projectRoleFormArray = this.projectRoleForm.get('project_role_mappings') as FormArray; + this.projectRoleFormArray.push(this.projectRoleParamsBuilder); + }); + this.projectRoleForm.patchValue(this.userDetails); + } + + /** Remove project and roles from the list @public */ + public removeMapping(index: number): void { + this.projectRoleFormArray.removeAt(index); + } + + /** Submit project and roles @public */ + public addProjectRole(): void { + this.submitted = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + if (this.projectRoleForm.invalid) { return; } + const apiURLHeader: APIURLHEADER = { + url: environment.USERS_URL + '/' + this.userID + }; + this.projectRoleMap.project_role_mappings = []; + this.projectRoleForm.value.project_role_mappings.forEach((res: ProjectRoleMappings) => { + this.projectRoleMap.project_role_mappings.push({ project: res.project_name, role: res.role_name }); + }); + if (this.projectRoleMap.project_role_mappings.length !== 0) { + this.isLoadingResults = true; + this.restService.patchResource(apiURLHeader, this.projectRoleMap).subscribe((result: {}) => { + this.isLoadingResults = false; + this.activeModal.close(modalData); + this.projectService.setHeaderProjects(); + this.notifierService.notify('success', this.translateService.instant('PAGE.USERS.EDITEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'patch'); + }); + } else { + this.notifierService.notify('error', this.translateService.instant('PAGE.USERS.EDITPROJECTROLEERROR')); + } + } + + /** Add extra mapping and set empty project and roles @public */ + public addMapping(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.projectRoleFormArray = this.projectRoleForm.get('project_role_mappings') as FormArray; + this.projectRoleFormArray.push(this.projectRoleParamsBuilder); + } +} diff --git a/src/app/users/user-details/UserDetailsComponent.html b/src/app/users/user-details/UserDetailsComponent.html new file mode 100644 index 0000000..9d11186 --- /dev/null +++ b/src/app/users/user-details/UserDetailsComponent.html @@ -0,0 +1,36 @@ + +
+
{{'PAGE.DASHBOARD.USERS' | translate}}
+ + + +
+
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/users/user-details/UserDetailsComponent.scss b/src/app/users/user-details/UserDetailsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/users/user-details/UserDetailsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/users/user-details/UserDetailsComponent.ts b/src/app/users/user-details/UserDetailsComponent.ts new file mode 100644 index 0000000..a4bedd5 --- /dev/null +++ b/src/app/users/user-details/UserDetailsComponent.ts @@ -0,0 +1,214 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file users details Component. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { AddEditUserComponent } from 'AddEditUserComponent'; +import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { ProjectService } from 'ProjectService'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { UserData, UserDetail } from 'UserModel'; +import { UsersActionComponent } from 'UsersActionComponent'; + +/** + * Creating component + * @Component takes UserDetailsComponent.html as template url + */ +@Component({ + templateUrl: './UserDetailsComponent.html', + styleUrls: ['./UserDetailsComponent.scss'] +}) +/** Exporting a class @exports UserDetailsComponent */ +export class UserDetailsComponent implements OnInit, OnDestroy { + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** handle translate @public */ + public translateService: TranslateService; + + /** To inject services @public */ + public injector: Injector; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Formation of appropriate Data for LocalDatasource @private */ + private userData: {}[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Holds all project details */ + private projectService: ProjectService; + + /** holds the project information @private */ + private projectList: {}[] = []; + + /** Columns list of the smart table @public */ + private columnLists: object = {}; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + this.projectService = this.injector.get(ProjectService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.projectService.getAllProjects().subscribe((projects: {}[]) => { + this.projectList = projects; + }); + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + username: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + projects: { title: this.translateService.instant('PAGE.DASHBOARD.PROJECTS'), width: '25%' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + modified: { title: this.translateService.instant('MODIFIED'), width: '15%' }, + created: { title: this.translateService.instant('CREATED'), width: '15%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: UserData, row: UserData): UserData => row, + renderComponent: UsersActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { editButtonContent: '', confirmSave: true }, + delete: { deleteButtonContent: '', confirmDelete: true }, + columns: this.columnLists, + actions: { add: false, edit: false, delete: false, position: 'right' }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** on Navigate to Composer Page @public */ + public composeUser(): void { + const modalRef: NgbModalRef = this.modalService.open(AddEditUserComponent, { backdrop: 'static' }); + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.NEWUSER'); + modalRef.componentInstance.userType = 'add'; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** smart table listing manipulation @private */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** OnUserRowSelect function @private */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'users' }); + this.dataService.changeMessage(event.data); + } + + /** Set up user details @public */ + public setUserDetails(userData: UserDetail): void { + const userDataObj: UserData = { + username: userData.username, + modified: this.sharedService.convertEpochTime(userData._admin.modified), + created: this.sharedService.convertEpochTime(userData._admin.created), + projects: userData.projectListName, + identifier: userData._id + }; + this.userData.push(userDataObj); + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.USERS_URL).subscribe((usersData: UserDetail[]) => { + this.userData = []; + usersData.forEach((userData: UserDetail) => { + if (userData.projects.length > 0) { + userData.projectListName = userData.projects.join(', '); + } else { + userData.projectListName = ''; + } + this.setUserDetails(userData); + }); + if (this.userData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.userData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/utilities/clone-package/ClonePackageComponent.html b/src/app/utilities/clone-package/ClonePackageComponent.html new file mode 100644 index 0000000..0a75c3a --- /dev/null +++ b/src/app/utilities/clone-package/ClonePackageComponent.html @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/app/utilities/clone-package/ClonePackageComponent.scss b/src/app/utilities/clone-package/ClonePackageComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/clone-package/ClonePackageComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/clone-package/ClonePackageComponent.ts b/src/app/utilities/clone-package/ClonePackageComponent.ts new file mode 100644 index 0000000..94e0920 --- /dev/null +++ b/src/app/utilities/clone-package/ClonePackageComponent.ts @@ -0,0 +1,180 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Clone Package Model + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA, URLPARAMS } from 'CommonModel'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { NSDDetails } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes ClonePackageComponent.html as template url + */ + +@Component({ + selector: 'app-clone-package', + templateUrl: './ClonePackageComponent.html', + styleUrls: ['./ClonePackageComponent.scss'] +}) +/** Exporting a class @exports ClonePackageComponent */ +export class ClonePackageComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Input contains component objects @public */ + @Input() public params: URLPARAMS; + + /** To handle loader status for API call @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains cloned package name instance @private */ + private packageName: string = ''; + + /** Contains API end point for package creation @private */ + private endPoint: string; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.sharedService = this.injector.get(SharedService); + this.activeModal = this.injector.get(NgbActiveModal); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + } + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } + /** + * Get package information based on type + */ + public clonePackageInfo(): void { + let apiUrl: string = ''; + const httpOptions: GETAPIURLHEADER = this.getHttpoptions(); + apiUrl = this.params.page === 'nsd' ? apiUrl = environment.NSDESCRIPTORS_URL + '/' + this.params.id + '/nsd' : + apiUrl = environment.VNFPACKAGES_URL + '/' + this.params.id + '/vnfd'; + this.isLoadingResults = true; + this.restService.getResource(apiUrl, httpOptions) + .subscribe((nsData: NSDDetails[]) => { + this.modifyContent(nsData); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error; + this.restService.handleError(error, 'get'); + }); + } + /** + * Get HTTP header options + */ + private getHttpoptions(): GETAPIURLHEADER { + const apiHeaders: HttpHeaders = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'text/plain', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + return { + headers: apiHeaders, + responseType: 'text' + }; + } + /** + * Get and modify package information based on type + */ + private modifyContent(packageInfo: NSDDetails[]): void { + const packageContent: string = jsyaml.load(packageInfo.toString()); + if (this.params.page === 'nsd') { + this.packageName = 'clone_' + packageContent['nsd:nsd-catalog'].nsd[0].name; + this.endPoint = environment.NSDESCRIPTORSCONTENT_URL; + packageContent['nsd:nsd-catalog'].nsd.forEach((nsd: NSDDetails) => { + nsd.id = 'clone_' + nsd.id; + nsd.name = 'clone_' + nsd.name; + nsd['short-name'] = 'clone_' + nsd['short-name']; + }); + } else { + this.packageName = 'clone_' + packageContent['vnfd:vnfd-catalog'].vnfd[0].name; + this.endPoint = environment.VNFPACKAGESCONTENT_URL; + packageContent['vnfd:vnfd-catalog'].vnfd.forEach((vnfd: NSDDetails) => { + vnfd.id = 'clone_' + vnfd.id; + vnfd.name = 'clone_' + vnfd.name; + vnfd['short-name'] = 'clone_' + vnfd['short-name']; + }); + } + this.clonePackage(packageContent); + } + /** + * Create clone package and upload as TAR.GZ file + */ + private clonePackage(packageContent: string): void { + const descriptorInfo: string = jsyaml.dump(packageContent); + const apiHeader: HttpHeaders = new HttpHeaders({ + 'Content-Type': 'application/gzip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + this.sharedService.targzFile({ packageType: this.params.page, id: this.params.id, descriptor: descriptorInfo }) + .then((content: ArrayBuffer): void => { + const apiURLHeader: APIURLHEADER = { + url: this.endPoint, + httpOptions: { headers: apiHeader } + }; + this.restService.postResource(apiURLHeader, content).subscribe((result: { id: string }) => { + this.activeModal.close(modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('CLONESUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + }); + }).catch((): void => { + this.isLoadingResults = false; + this.notifierService.notify('error', this.translateService.instant('ERROR')); + }); + } +} diff --git a/src/app/utilities/compose-packages/ComposePackages.html b/src/app/utilities/compose-packages/ComposePackages.html new file mode 100644 index 0000000..0d66e0f --- /dev/null +++ b/src/app/utilities/compose-packages/ComposePackages.html @@ -0,0 +1,40 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/utilities/compose-packages/ComposePackages.scss b/src/app/utilities/compose-packages/ComposePackages.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/compose-packages/ComposePackages.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/compose-packages/ComposePackages.ts b/src/app/utilities/compose-packages/ComposePackages.ts new file mode 100644 index 0000000..9567b43 --- /dev/null +++ b/src/app/utilities/compose-packages/ComposePackages.ts @@ -0,0 +1,237 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Info Compose Package Model + */ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, URLPARAMS } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import * as pako from 'pako'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; + +/** This is added globally by the tar.js library */ +// tslint:disable-next-line: no-any +declare const Tar: any; + +/** + * Creating component + * @Component takes ComposePackages.html as template url + */ +@Component({ + templateUrl: './ComposePackages.html', + styleUrls: ['./ComposePackages.scss'] +}) +/** Exporting a class @exports ComposePackages */ +export class ComposePackages implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** dataService to pass the data from one component to another @public */ + public dataService: DataService; + + /** Varaibles to hold http client @public */ + public httpClient: HttpClient; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup instance added to the form @ html @public */ + public packagesForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** To handle loader status for API call @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Create URL holds the end point of any packages @private */ + private createURL: string; + + /** Input contains component objects @private */ + @Input() private params: URLPARAMS; + + /** Holds the end point @private */ + private endPoint: string; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + constructor(injector: Injector) { + this.injector = injector; + this.dataService = this.injector.get(DataService); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.notifierService = this.injector.get(NotifierService); + this.formBuilder = this.injector.get(FormBuilder); + this.router = this.injector.get(Router); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/gzip', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.initializeForm(); + } + + /** initialize Forms @public */ + public initializeForm(): void { + this.packagesForm = this.formBuilder.group({ + name: ['', [Validators.required]] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.packagesForm.controls; } + + /** Create packages @public */ + public createPackages(): void { + this.submitted = true; + this.sharedService.cleanForm(this.packagesForm); + if (!this.packagesForm.invalid) { + this.isLoadingResults = true; + if (this.params.page === 'ns-package') { + this.endPoint = environment.NSDESCRIPTORSCONTENT_URL; + } else if (this.params.page === 'vnf-package') { + this.endPoint = environment.VNFPACKAGESCONTENT_URL; + } + const descriptor: string = this.packageYaml(this.params.page); + try { + // tslint:disable-next-line: no-any + const tar: any = new Tar(); + const out: Uint8Array = tar.append(this.packagesForm.value.name + '/' + this.packagesForm.value.name + '.yaml', + descriptor, { type: '0' }); + const gzipContent: Uint8Array = pako.gzip(out); + this.createPackageApi(gzipContent.buffer); + } catch (e) { + this.isLoadingResults = false; + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + } + } + /** Create packages @public */ + private createPackageApi(packageContent: ArrayBuffer | SharedArrayBuffer): void { + const apiURLHeader: APIURLHEADER = { + url: this.endPoint, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, packageContent).subscribe((result: { id: string }) => { + this.isLoadingResults = false; + this.activeModal.close(); + this.composeNSPackages(result.id); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + }); + } + /** Compose NS Packages @private */ + private composeNSPackages(id: string): void { + let packageUrl: string; + if (this.params.page === 'ns-package') { + packageUrl = '/packages/ns/compose/'; + this.notifierService.notify('success', this.packagesForm.value.name + ' ' + + this.translateService.instant('PAGE.NSPACKAGE.CREATEDSUCCESSFULLY')); + } else if (this.params.page === 'vnf-package') { + packageUrl = '/packages/vnf/compose/'; + this.notifierService.notify('success', this.packagesForm.value.name + ' ' + + this.translateService.instant('PAGE.VNFPACKAGE.CREATEDSUCCESSFULLY')); + } + this.router.navigate([packageUrl, id]).catch(() => { + // Catch Navigation Error + }); + } + /** Deafult template for NS and VNF Packages @private */ + private packageYaml(descriptorType: string): string { + let packageYaml: {} = {}; + if (descriptorType === 'ns-package') { + packageYaml = { + 'nsd:nsd-catalog': { + nsd: [ + { + 'short-name': this.packagesForm.value.name, + vendor: 'OSM Composer', + description: this.packagesForm.value.name + ' descriptor', + vld: [], + 'constituent-vnfd': [], + version: '1.0', + id: this.packagesForm.value.name, + name: this.packagesForm.value.name + } + ] + } + }; + } else { + packageYaml = { + 'vnfd:vnfd-catalog': { + vnfd: [ + { + 'short-name': this.packagesForm.value.name, + vdu: [], + description: '', + 'mgmt-interface': { + cp: '' + }, + id: this.packagesForm.value.name, + version: '1.0', + 'internal-vld': [], + 'connection-point': [], + name: this.packagesForm.value.name + } + ] + } + }; + } + return jsyaml.dump(packageYaml); + } +} diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html new file mode 100644 index 0000000..03f5564 --- /dev/null +++ b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.html @@ -0,0 +1,81 @@ + +
+
+ + + +
+
+
+ + + +
\ No newline at end of file diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss new file mode 100644 index 0000000..1ff404c --- /dev/null +++ b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.scss @@ -0,0 +1,24 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +.help-key { + border: 1px solid #ddd; + padding: 4px; + border-radius: 3px; + background: #f6f6f6; + box-shadow: #999 1px 1px 1px; +} \ No newline at end of file diff --git a/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts new file mode 100644 index 0000000..a1a79b9 --- /dev/null +++ b/src/app/utilities/confirmation-topology/ConfirmationTopologyComponent.ts @@ -0,0 +1,102 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Delete Topology Model + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { MODALCLOSERESPONSEWITHCP } from 'CommonModel'; +/** + * Creating component + * @Component takes ConfirmationTopologyComponent.html as template url + */ +@Component({ + selector: 'app-confirmation-topology', + templateUrl: './ConfirmationTopologyComponent.html', + styleUrls: ['./ConfirmationTopologyComponent.scss'] +}) +/** Exporting a class @exports ConfirmationTopologyComponent */ +export class ConfirmationTopologyComponent implements OnInit { + /** Form valid on submit trigger @public */ + public submitted: boolean = false; + /** To inject services @public */ + public injector: Injector; + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + /** FormGroup instance added to the form @ html @public */ + public addConfirmationForm: FormGroup; + /** Input contains Modal dialog componentInstance @private */ + @Input() public topologytitle: string; + /** Input contains Modal dialog componentInstance @private */ + @Input() public topologyname: string; + /** Input contains Modal dialog componentInstance @private */ + @Input() public topologyType: string; + /** Input contains Modal dialog componentInstance @private */ + @Input() public cpDetails: {}[]; + + /** Contains connectionpoint @public */ + public connectionPointInput: string; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + constructor(injector: Injector) { + this.injector = injector; + this.activeModal = this.injector.get(NgbActiveModal); + this.translateService = this.injector.get(TranslateService); + this.formBuilder = this.injector.get(FormBuilder); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.initializeForm(); + } + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.addConfirmationForm.controls; } + + /** initialize Forms @public */ + public initializeForm(): void { + this.addConfirmationForm = this.formBuilder.group({ + cpName: [null, [Validators.required]] + }); + } + + /** add confirmation to be handled in this function @public */ + public addConfirmation(): void { + this.submitted = true; + if (this.addConfirmationForm.invalid) { return; } // Proceed, onces form is valid + const modalData: MODALCLOSERESPONSEWITHCP = { + message: 'Done', + connection_point: this.connectionPointInput + }; + this.activeModal.close(modalData); + } + /** confirmation to be handled in this function @public */ + public confirmation(): void { + const modalData: MODALCLOSERESPONSEWITHCP = { + message: 'Done' + }; + this.activeModal.close(modalData); + } + +} diff --git a/src/app/utilities/delete/DeleteComponent.html b/src/app/utilities/delete/DeleteComponent.html new file mode 100644 index 0000000..a39cb61 --- /dev/null +++ b/src/app/utilities/delete/DeleteComponent.html @@ -0,0 +1,33 @@ + + + + + \ No newline at end of file diff --git a/src/app/utilities/delete/DeleteComponent.scss b/src/app/utilities/delete/DeleteComponent.scss new file mode 100644 index 0000000..cdd37f2 --- /dev/null +++ b/src/app/utilities/delete/DeleteComponent.scss @@ -0,0 +1,20 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +.loadermessage-column { + min-height: 150px; +} \ No newline at end of file diff --git a/src/app/utilities/delete/DeleteComponent.ts b/src/app/utilities/delete/DeleteComponent.ts new file mode 100644 index 0000000..4baee64 --- /dev/null +++ b/src/app/utilities/delete/DeleteComponent.ts @@ -0,0 +1,199 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Delete Model + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { DELETEPARAMS, ERRORDATA, MODALCLOSERESPONSEDATA, URLPARAMS } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; + +/** + * Creating component + * @Component takes DeleteComponent.html as template url + */ +@Component({ + selector: 'app-delete', + templateUrl: './DeleteComponent.html', + styleUrls: ['./DeleteComponent.scss'] +}) +/** Exporting a class @exports DeleteComponent */ +export class DeleteComponent { + /** To inject services @public */ + public injector: Injector; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Instance of the modal service @public */ + public title: string; + + /** Show the Delete Ok button to trigger the terminate and delete */ + public forceDelete: boolean = false; + + /** Check the loading results @public */ + public isLoadingResults: Boolean = false; + + /** Give the message for the loading @public */ + public notifyMessage: string = 'DELETELOADERMESSAGE'; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** DataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Instance of the modal service @private */ + private id: string; + + /** Variables holds url to be delete @private */ + private deleteURL: string; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Input contains component objects @private */ + @Input() private params: URLPARAMS; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.activeModal = this.injector.get(NgbActiveModal); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.dataService.currentMessage.subscribe((data: DELETEPARAMS) => { + if (data.identifier !== undefined || data.identifier !== '' || data.identifier !== null) { + this.id = data.identifier; + } + this.createTitleandID(data); + this.createDeleteUrl(data); + }); + } + /** Generate Title and Id from data @public */ + public createTitleandID(data: DELETEPARAMS): void { + this.title = ''; + if (data.name !== undefined) { + this.title = data.name; + } else if (data.shortName !== undefined) { + this.title = data.shortName; + } else if (data.projectName !== undefined) { + this.title = data.projectName; + this.id = this.title; + } else if (data.userName !== undefined) { + this.title = data.userName; + } else if (data.username !== undefined) { + this.title = data.username; + } + } + /** Generate Delete url from data @public */ + public createDeleteUrl(data: DELETEPARAMS): void { + this.deleteURL = ''; + if (data.page === 'ns-instance') { + this.deleteURL = environment.NSINSTANCESCONTENT_URL; + this.forceDelete = this.params.forceDeleteType; + } else if (data.page === 'ns-package') { + this.deleteURL = environment.NSDESCRIPTORSCONTENT_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'vnf-package') { + this.deleteURL = environment.VNFPACKAGESCONTENT_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'vim-account') { + this.deleteURL = environment.VIMACCOUNTS_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'wim-account') { + this.deleteURL = environment.WIMACCOUNTS_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'projects') { + this.deleteURL = environment.PROJECTS_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + this.id = data.id; + } else if (data.page === 'users') { + this.deleteURL = environment.USERS_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'network-slice') { + this.deleteURL = environment.NETWORKSLICETEMPLATECONTENT_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'net-slice-instance') { + this.deleteURL = environment.NETWORKSLICEINSTANCESCONTENT_URL; + this.forceDelete = this.params.forceDeleteType; + } else if (data.page === 'roles') { + this.deleteURL = environment.ROLES_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'pdu-instances') { + this.deleteURL = environment.PDUINSTANCE_URL; + } else if (data.page === 'sdn-controller') { + this.deleteURL = environment.SDNCONTROLLER_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'k8-cluster') { + this.deleteURL = environment.K8SCLUSTER_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else if (data.page === 'k8-repo') { + this.deleteURL = environment.K8REPOS_URL; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } + } + /** Generate Data function @public */ + public deleteData(): void { + this.isLoadingResults = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + let deletingURl: string = ''; + if (this.forceDelete) { + deletingURl = this.deleteURL + '/' + this.id + '?FORCE=true'; + this.notifyMessage = 'DELETEDSUCCESSFULLY'; + } else { + deletingURl = this.deleteURL + '/' + this.id; + } + this.restService.deleteResource(deletingURl).subscribe((res: {}) => { + this.activeModal.close(modalData); + this.notifierService.notify('success', this.translateService.instant(this.notifyMessage, { title: this.title})); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'delete'); + }, () => { + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/utilities/dragDropUpload/DragDirective.ts b/src/app/utilities/dragDropUpload/DragDirective.ts new file mode 100644 index 0000000..735ac7c --- /dev/null +++ b/src/app/utilities/dragDropUpload/DragDirective.ts @@ -0,0 +1,87 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Drag and Drop feature. + */ +import { Directive, EventEmitter, HostBinding, HostListener, Output } from '@angular/core'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; + +/** Interface for FileHandle */ +export interface FileHandle { + file: File; + url: SafeUrl; +} + +/** + * Creating Directive + * @Directive for handling the files. + */ +// tslint:disable-next-line:export-name +@Directive({ + selector: '[appDrag]' +}) +/** Exporting a class @exports DragDirective */ +export class DragDirective { + /** To publish the details of files @public */ + @Output() public files: EventEmitter = new EventEmitter(); + + /** To set the background of drag and drop region @public */ + @HostBinding('style.background') private background: string = '#e6f3fe'; + + /** To set the background of drag and drop region @public */ + @HostBinding('style.color') private color: string = '#6a7a8c'; + + /** To trust the SecurityURL @public */ + private sanitizer: DomSanitizer; + + constructor(sanitizer: DomSanitizer) { + this.sanitizer = sanitizer; + } + + /** To handle the Drag over Event @public */ + @HostListener('dragover', ['$event']) public onDragOver(evt: DragEvent): void { + evt.preventDefault(); + evt.stopPropagation(); + this.background = '#087add'; + this.color = '#fff'; + } + /** To handle Drag leave Event @public */ + @HostListener('dragleave', ['$event']) public onDragLeave(evt: DragEvent): void { + evt.preventDefault(); + evt.stopPropagation(); + this.background = '#e6f3fe'; + this.color = '#6a7a8c'; + } + /** To handle Drop Event @public */ + @HostListener('drop', ['$event']) public onDrop(evt: DragEvent): void { + evt.preventDefault(); + evt.stopPropagation(); + this.background = '#e6f3fe'; + this.color = '#6a7a8c'; + + const files: FileHandle[] = []; + Array.from(evt.dataTransfer.files).forEach((listFiles: File, index: number) => { + const file: File = listFiles; + const url: SafeUrl = this.sanitizer.bypassSecurityTrustUrl(window.URL.createObjectURL(file)); + files.push({ file, url }); + }); + if (files.length > 0) { + this.files.emit(evt.dataTransfer.files); + } + } +} diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.html b/src/app/utilities/edit-packages/EditPackagesComponent.html new file mode 100644 index 0000000..2defc33 --- /dev/null +++ b/src/app/utilities/edit-packages/EditPackagesComponent.html @@ -0,0 +1,61 @@ + +
+
{{'EDIT' | translate}} {{pacakgeType}} {{'DESCRIPTOR' | translate}}
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+ + + +
+
+
+
+ +
+ + {{'NODATAERROR' | translate}} + + \ No newline at end of file diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.scss b/src/app/utilities/edit-packages/EditPackagesComponent.scss new file mode 100644 index 0000000..5a9c483 --- /dev/null +++ b/src/app/utilities/edit-packages/EditPackagesComponent.scss @@ -0,0 +1,20 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +.ngx-codemirror { + font-size: 14px; +} \ No newline at end of file diff --git a/src/app/utilities/edit-packages/EditPackagesComponent.ts b/src/app/utilities/edit-packages/EditPackagesComponent.ts new file mode 100644 index 0000000..befafb8 --- /dev/null +++ b/src/app/utilities/edit-packages/EditPackagesComponent.ts @@ -0,0 +1,318 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Edit Actions Component + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, Injector, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import 'codemirror/addon/dialog/dialog'; +import 'codemirror/addon/display/autorefresh'; +import 'codemirror/addon/display/fullscreen'; +import 'codemirror/addon/edit/closebrackets'; +import 'codemirror/addon/edit/matchbrackets'; +import 'codemirror/addon/fold/brace-fold'; +import 'codemirror/addon/fold/foldcode'; +import 'codemirror/addon/fold/foldgutter'; +import 'codemirror/addon/search/search'; +import 'codemirror/addon/search/searchcursor'; +import 'codemirror/keymap/sublime'; +import 'codemirror/lib/codemirror'; +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/mode/markdown/markdown'; +import 'codemirror/mode/yaml/yaml'; +import { APIURLHEADER, ERRORDATA, GETAPIURLHEADER } from 'CommonModel'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import * as jsyaml from 'js-yaml'; +import { NSDDetails } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes EditPackagesComponent.html as template url + */ +@Component({ + selector: 'app-edit-packages', + templateUrl: './EditPackagesComponent.html', + styleUrls: ['./EditPackagesComponent.scss'] +}) + +/** Exporting a class @exports EditPackagesComponent */ +export class EditPackagesComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** dataService to pass the data from one component to another @public */ + public identifier: {} = {}; + + /** readOnly @public */ + public readOnly: boolean = false; + + /** Handle the formate Change @public */ + public defaults: {} = { + 'text/x-yaml': '', + 'text/json': '' + }; + + /** Get & Update URL VNFD & NSD */ + public getUpdateURL: string; + + /** Pass the type of VNFD & NSD for fetching text */ + public getFileContentType: string; + + /** Pass the type of VNFD & NSD for fileUpdate */ + public updateFileContentType: string; + + /** To Set Mode @public */ + public mode: string = 'text/x-yaml'; + + /** To Set Mode @public */ + public modeDefault: string = 'yaml'; + + /** options @public */ + public options: {} = { + mode: this.modeDefault, + showCursorWhenSelecting: true, + autofocus: true, + autoRefresh: true, + lineNumbers: true, + lineWrapping: true, + foldGutter: true, + gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], + autoCloseBrackets: true, + matchBrackets: true, + theme: 'neat', + keyMap: 'sublime' + }; + + /** Ymal Url for the VNFD & NSD */ + public ymalUrl: string; + + /** json Url for the VNFD & NSD */ + public jsonUrl: string; + + /** Navigation Path for the VNFD & NSD */ + public navigatePath: string; + + /** Package type */ + public pacakgeType: string; + + /** variables contains paramsID @public */ + public paramsID: string; + + /** Controls the File Type List form @public */ + public fileTypes: { value: string; viewValue: string; }[] = []; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + + /** Data @private */ + private data: string = ''; + + /** contains http options @private */ + private httpOptions: HttpHeaders; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.router = this.injector.get(Router); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'text/plain', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.paramsID = this.activatedRoute.snapshot.paramMap.get('id'); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.pacakgeType = this.activatedRoute.snapshot.paramMap.get('type'); + this.generateURLPath(); + } + + /** generate ymalURL, JSONURL, navigation Path */ + public generateURLPath(): void { + if (this.pacakgeType === 'vnf') { + this.getUpdateURL = environment.VNFPACKAGES_URL; + this.getFileContentType = 'vnfd'; + this.updateFileContentType = 'package_content'; + this.navigatePath = 'vnf'; + this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }, { value: 'text/json', viewValue: 'json' }]; + this.httpOptions = this.getHeadersWithContentAccept('application/zip', 'application/json'); + this.getEditFileData(); + } else if (this.pacakgeType === 'netslice') { + this.getUpdateURL = environment.NETWORKSLICETEMPLATE_URL; + this.getFileContentType = 'nst'; + this.updateFileContentType = 'nst_content'; + this.navigatePath = 'netslice'; + this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }]; + this.httpOptions = this.getHeadersWithContentAccept('application/yaml', 'application/json'); + this.getEditFileData(); + } else { + this.getUpdateURL = environment.NSDESCRIPTORS_URL; + this.getFileContentType = 'nsd'; + this.updateFileContentType = 'nsd_content'; + this.pacakgeType = 'nsd'; + this.navigatePath = 'ns'; + this.fileTypes = [{ value: 'text/x-yaml', viewValue: 'yaml' }, { value: 'text/json', viewValue: 'json' }]; + this.httpOptions = this.getHeadersWithContentAccept('application/zip', 'application/json'); + this.getEditFileData(); + } + } + + /** Get the headers based on the type @public */ + public getHeadersWithContentAccept(contentType: string, acceptType: string): HttpHeaders { + this.headers = new HttpHeaders({ + 'Content-Type': contentType, + Accept: acceptType, + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + return this.headers; + } + + /** ChangeMode function @public */ + public changeMode(): void { + if (this.mode === 'text/x-yaml') { + this.modeDefault = 'yaml'; + } else { + this.modeDefault = 'javascript'; + } + this.options = { + ...this.options, + mode: this.modeDefault + }; + this.data = ''; + } + + /** HandleChange function @public */ + public handleChange($event: string): void { + this.data = $event; + } + + /** Update function @public */ + public update(showgraph: boolean): void { + if (this.data === '') { + this.notifierService.notify('warning', this.translateService.instant('PAGE.TOPOLOGY.DATAEMPTY')); + } else { + this.updateCheck(showgraph); + } + } + /** Update the file Data @public */ + public updateFileData(urlHeader: APIURLHEADER, fileData: string | ArrayBuffer, showgraph: boolean, packageType: string): void { + this.restService.putResource(urlHeader, fileData).subscribe(() => { + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant( + (packageType !== 'netslice') ? 'PAGE.NSPACKAGE.EDITPACKAGES.UPDATEDSUCCESSFULLY' : 'PAGE.NETSLICE.UPDATEDSUCCESSFULLY')); + if (showgraph) { + if (packageType === 'nsd') { + this.router.navigate(['/packages/ns/compose/' + this.paramsID]).catch(); + } else if (packageType === 'vnf') { + this.router.navigate(['/packages/vnf/compose/' + this.paramsID]).catch(); + } + } + this.getEditFileData(); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'put'); + }); + } + /** Update method for NS, VNF and net-slice template */ + private updateCheck(showgraph: boolean): void { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: this.getUpdateURL + '/' + this.paramsID + '/' + this.updateFileContentType, + httpOptions: { headers: this.httpOptions } + }; + let descriptorInfo: string = ''; + if (this.mode === 'text/json') { + descriptorInfo = jsyaml.dump(JSON.parse(this.data), {sortKeys: true}); + } else { + descriptorInfo = this.data; + } + if (this.getFileContentType !== 'nst') { + this.sharedService.targzFile({ packageType: this.pacakgeType, id: this.paramsID, descriptor: descriptorInfo }) + .then((content: ArrayBuffer): void => { + this.updateFileData(apiURLHeader, content, showgraph, this.pacakgeType); + }).catch((): void => { + this.isLoadingResults = false; + this.notifierService.notify('error', this.translateService.instant('ERROR')); + }); + } else { + this.updateFileData(apiURLHeader, descriptorInfo, showgraph, this.pacakgeType); + } + } + /** Get the YAML content response as a plain/text and convert to JSON Format @private */ + private getEditFileData(): void { + this.isLoadingResults = true; + const gethttpOptions: HttpHeaders = this.getHeadersWithContentAccept('application/json', 'text/plain'); + const httpOptions: GETAPIURLHEADER = { + headers: gethttpOptions, + responseType: 'text' + }; + this.restService.getResource(this.getUpdateURL + '/' + this.paramsID + '/' + this.getFileContentType, httpOptions) + .subscribe((nsData: NSDDetails[]) => { + const getJson: string = jsyaml.load(nsData.toString(), { json: true }); + //tslint:disable-next-line:no-string-literal + this.defaults['text/x-yaml'] = nsData.toString(); + this.defaults['text/json'] = JSON.stringify(getJson, null, '\t'); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + error.error = typeof error.error === 'string' ? jsyaml.load(error.error) : error.error; + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED ) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/utilities/loader/LoaderComponent.html b/src/app/utilities/loader/LoaderComponent.html new file mode 100644 index 0000000..30ce264 --- /dev/null +++ b/src/app/utilities/loader/LoaderComponent.html @@ -0,0 +1,27 @@ + +
+
+
{{'LOADING' | translate}}...
+

+ {{getMessage | translate}} + . + +

+
+
\ No newline at end of file diff --git a/src/app/utilities/loader/LoaderComponent.scss b/src/app/utilities/loader/LoaderComponent.scss new file mode 100644 index 0000000..6bfd321 --- /dev/null +++ b/src/app/utilities/loader/LoaderComponent.scss @@ -0,0 +1,89 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; +.loader-overlay { + -ms-opacity: 0.9; + @include background(null, $white, null, null, null); + @include position_value(absolute, 0, null, null, 0); + @include wh-value(100%, 100%); + opacity: 0.9; + vertical-align: middle; + z-index: 100000; + .loader-content { + @include wh-value(50%, null); + margin-left: auto; + margin-top: auto; + .loader-text { + color: $body-color; + } + } + .loader-center { + @include position_value(absolute, 50%, null, null, 50%); + @include flexbox(block, null, null, null, null, null); + -moz-transform: translate(-50%, -50%); + -ms-transform: translate(-50%, -50%); + -o-transform: translate(-50%, -50%); + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -55%); + } +} +.loader, +.loader:after { + @include roundedCornersPercentage(50%); + @include wh-value(10em, 10em); +} +.loader { + @include font(null, 3px, null); + @include position_value(relative, null, null, null, null); + @include border(top, 2, solid, rgba(5, 76, 140, 0.28)); + @include border(right, 2, solid, rgba(5, 76, 140, 0.28)); + @include border(bottom, 2, solid, rgba(5, 76, 140, 0.28)); + @include border(left, 2, solid, $primary); + margin: 0 auto; + text-indent: -9999em; + -webkit-transform: translateZ(0); + -ms-transform: translateZ(0); + transform: translateZ(0); + -webkit-animation: load8 1.1s infinite linear; + animation: load8 1.1s infinite linear; +} +@-webkit-keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes load8 { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(360deg); + transform: rotate(360deg); + } +} +@keyframes blink {50% { color: transparent }} +.loader__dot { animation: 1s blink infinite } +.loader__dot:nth-child(2) { animation-delay: 250ms } +.loader__dot:nth-child(3) { animation-delay: 500ms } \ No newline at end of file diff --git a/src/app/utilities/loader/LoaderComponent.ts b/src/app/utilities/loader/LoaderComponent.ts new file mode 100644 index 0000000..ee8cab8 --- /dev/null +++ b/src/app/utilities/loader/LoaderComponent.ts @@ -0,0 +1,50 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Delete Model + */ +import { Component, Input, OnInit } from '@angular/core'; +/** + * Creating component + * @Component takes LoaderComponent.html as template url + */ +@Component({ + selector: 'app-loader', + templateUrl: './LoaderComponent.html', + styleUrls: ['./LoaderComponent.scss'] +}) +/** Exporting a class @exports LoaderComponent */ +export class LoaderComponent implements OnInit { + /** Variables declared to get the message from parents @public */ + @Input() public waitingMessage: string; + /** Variables declared to get the message of loader @public */ + public getMessage: string; + + constructor() { + // Empty block + } + + public ngOnInit(): void { + if (this.waitingMessage !== '') { + this.getMessage = this.waitingMessage; + } else { + this.getMessage = ''; + } + } + +} diff --git a/src/app/utilities/loader/LoaderModule.ts b/src/app/utilities/loader/LoaderModule.ts new file mode 100644 index 0000000..ba81b6a --- /dev/null +++ b/src/app/utilities/loader/LoaderModule.ts @@ -0,0 +1,41 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Loader Module. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { LoaderComponent } from 'LoaderComponent'; +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [CommonModule, TranslateModule], + declarations: [LoaderComponent], + exports: [LoaderComponent] +}) +/** Exporting a class @exports LoaderModule */ +export class LoaderModule { + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } +} diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html new file mode 100644 index 0000000..7fcc812 --- /dev/null +++ b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.html @@ -0,0 +1,42 @@ + +
+ + +
+ + +
+
\ No newline at end of file diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts new file mode 100644 index 0000000..0e528a8 --- /dev/null +++ b/src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent.ts @@ -0,0 +1,95 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Netslice InstancesAction Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { NSTInstanceData } from 'NetworkSliceModel'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; +/** + * Creating component + * @Component takes NetsliceInstancesActionComponent.html as template url + */ +@Component({ + templateUrl: './NetsliceInstancesActionComponent.html', + styleUrls: ['./NetsliceInstancesActionComponent.scss'] +}) +/** Exporting a class @exports NetsliceInstancesActionComponent */ +export class NetsliceInstancesActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: NSTInstanceData; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains instance ID @private */ + private instanceID: string; + + /** Service holds the router information @private */ + private router: Router; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + } + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.instanceID = this.value.identifier; + } + + /** Shows information using modalservice @public */ + public infoNetSliceInstance(): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.instanceID, + page: 'net-slice-instance', + titleName: 'PAGE.NETSLICETEMPLATE.NETSLICETEMPLATEDETAILS' + }; + } + + /** Delete NetSlice Instance packages @public */ + public deleteNetSliceInstance(forceAction: boolean): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.componentInstance.params = {forceDeleteType: forceAction}; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + /** History of operations for an Instanace @public */ + public historyOfOperations(): void { + this.router.navigate(['/instances/netslice/history-operations/', this.instanceID]).catch(() => { + // Catch Navigation Error + }); + } +} diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html new file mode 100644 index 0000000..d47d65e --- /dev/null +++ b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.html @@ -0,0 +1,34 @@ + +
+ + + + +
\ No newline at end of file diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts new file mode 100644 index 0000000..8be5f50 --- /dev/null +++ b/src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent.ts @@ -0,0 +1,102 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Netslice-packagesAction Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { InstantiateNetSliceTemplateComponent } from 'InstantiateNetSliceTemplate'; +import { NetworkSliceData } from 'NetworkSliceModel'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; + +/** + * Creating component + * @Component takes NetslicePackagesActionComponent.html as template url + */ +@Component({ + selector: 'app-netslice-packages-action', + templateUrl: './NetslicePackagesActionComponent.html', + styleUrls: ['./NetslicePackagesActionComponent.scss'] +}) +/** Exporting a class @exports NetslicePackagesActionComponent */ +export class NetslicePackagesActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: NetworkSliceData; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains instance ID @private */ + private instanceID: string; + + /** Service holds the router information @private */ + private router: Router; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.instanceID = this.value.identifier; + } + + /** Delete NetSliceTemplate packages @public */ + public deleteNetSliceTemplate(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'}); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Shows information using modalservice @public */ + public infoNetSlice(): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.instanceID, + page: 'net-slice-package', + titleName: 'PAGE.NETSLICETEMPLATE.NETSLICETEMPLATEDETAILS' + }; + } + + /** Set Edit for the @public */ + public netSliceEdit(): void { + this.router.navigate(['/packages/netslice/edit/', this.instanceID]).catch(() => { + // Catch Navigation Error + }); + } + + /** Instantiate Net Slice using modalservice @public */ + public instantiateNetSlice(): void { + this.modalService.open(InstantiateNetSliceTemplateComponent, { backdrop: 'static' }); + } +} diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.html b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.html new file mode 100644 index 0000000..41a58f5 --- /dev/null +++ b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.html @@ -0,0 +1,56 @@ + +
+ + + +
+ + +
+
+ \ No newline at end of file diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts new file mode 100644 index 0000000..8bf43ce --- /dev/null +++ b/src/app/utilities/ns-instances-action/NSInstancesActionComponent.ts @@ -0,0 +1,181 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file NS InstancesAction Component + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { ERRORDATA, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { environment } from 'environment'; +import { NSDDetails } from 'NSDModel'; +import { NSDInstanceData } from 'NSInstanceModel'; +import { NSPrimitiveComponent } from 'NSPrimitiveComponent'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; +/** + * Creating component + * @Component takes NSInstancesActionComponent.html as template url + */ +@Component({ + templateUrl: './NSInstancesActionComponent.html', + styleUrls: ['./NSInstancesActionComponent.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +/** Exporting a class @exports NSInstancesActionComponent */ +export class NSInstancesActionComponent { + /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: NSDInstanceData; + + /** Invoke service injectors @public */ + public injector: Injector; + + /** Instance of the modal service @public */ + public restService: RestService; + + /** Config Status Check @public */ + public configStatus: string; + + /** Operational Status Check @public */ + public operationalStatus: string; + + /** Check the loading results for loader status @public */ + public isLoadingMetricsResult: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Contains instance ID @private */ + private instanceID: string; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Detect changes for the User Input */ + private cd: ChangeDetectorRef; + + /** Set timeout @private */ + private timeOut: number = 1000; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.restService = this.injector.get(RestService); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.cd = this.injector.get(ChangeDetectorRef); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.configStatus = this.value.ConfigStatus; + this.operationalStatus = this.value.OperationalStatus; + this.instanceID = this.value.identifier; + } + + /** Shows information using modalservice @public */ + public infoNs(): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.instanceID, + page: 'ns-instance', + titleName: 'INSTANCEDETAILS' + }; + } + + /** Delete NS Instanace @public */ + public deleteNSInstance(forceAction: boolean): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.componentInstance.params = { forceDeleteType: forceAction }; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** History of operations for an Instanace @public */ + public historyOfOperations(): void { + this.router.navigate(['/instances/ns/history-operations/', this.instanceID]).catch(() => { + // Catch Navigation Error + }); + } + + /** NS Topology */ + public nsTopology(): void { + this.router.navigate(['/instances/ns/', this.instanceID]).catch(() => { + // Catch Navigation Error + }); + } + + /** Exec NS Primitive @public */ + public execNSPrimitiveModal(): void { + this.modalService.open(NSPrimitiveComponent).componentInstance.params = { + memberIndex: this.value.memberIndex, + nsConfig: this.value.nsConfig + }; + } + + /** Redirect to Grafana Metrics @public */ + public metrics(): void { + this.isLoadingMetricsResult = true; + this.restService.getResource(environment.NSDINSTANCES_URL + '/' + this.instanceID).subscribe((nsData: NSDDetails[]) => { + nsData['vnfd-id'].forEach((vnfdID: string[]) => { + this.restService.getResource(environment.VNFPACKAGES_URL + '/' + vnfdID) + .subscribe((vnfd: {}[]) => { + if (vnfd['monitoring-param'] !== undefined && vnfd['monitoring-param'].length > 0) { + this.isLoadingMetricsResult = false; + const location: string = environment.GRAFANA_URL + '/' + this.instanceID + '/osm-ns-metrics-metrics'; + window.open(location); + } else { + this.isLoadingMetricsResult = false; + this.notifierService.notify('error', this.translateService.instant('GRAFANA.METRICSERROR')); + } + setTimeout(() => { + this.cd.detectChanges(); + }, this.timeOut); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingMetricsResult = false; + }); + }); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingMetricsResult = false; + }); + } +} diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.html b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.html new file mode 100644 index 0000000..6e33d0d --- /dev/null +++ b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.html @@ -0,0 +1,55 @@ + +
+ + + +
+ + +
+
+ \ No newline at end of file diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts new file mode 100644 index 0000000..6e7fbfb --- /dev/null +++ b/src/app/utilities/ns-packages-action/NsPackagesActionComponent.ts @@ -0,0 +1,193 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file NS PackagesAction Component + */ +import { HttpHeaders } from '@angular/common/http'; +import { ChangeDetectorRef, Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { ClonePackageComponent } from 'ClonePackage'; +import { ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { environment } from 'environment'; +import { InstantiateNsComponent } from 'InstantiateNs'; +import { NSData } from 'NSDModel'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { ShowContentComponent } from 'ShowContent'; + +/** + * Creating component + * @Component takes NsPackagesActionComponent.html as template url + */ +@Component({ + selector: 'app-ns-packages-action', + templateUrl: './NsPackagesActionComponent.html', + styleUrls: ['./NsPackagesActionComponent.scss'] +}) + +/** Exporting a class @exports NsPackagesActionComponent */ +export class NsPackagesActionComponent { + /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: NSData; + + /** To inject services @public */ + public injector: Injector; + + /** Check the loading results for loader status @public */ + public isLoadingDownloadResult: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Variables holds NS ID @private */ + private nsdID: string; + + /** Variables holds NS name @private */ + private nsdName: string; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Detect changes for the User Input */ + private cd: ChangeDetectorRef; + + /** Set timeout @private */ + private timeOut: number = 1000; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.cd = this.injector.get(ChangeDetectorRef); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + Accept: 'application/zip, application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.nsdID = this.value.identifier; + this.nsdName = this.value.shortName; + } + + /** Instantiate NS using modalservice @public */ + public instantiateNS(): void { + this.modalService.open(InstantiateNsComponent, { backdrop: 'static' }); + } + + /** Delete NS Package @public */ + public deleteNSPackage(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Set instance for NSD Edit @public */ + public nsdEdit(): void { + this.router.navigate(['/packages/ns/edit/', this.nsdID]).catch(() => { + // Catch Navigation Error + }); + } + + /** list out all the file content of a descriptors @public */ + public showContent(): void { + this.modalService.open(ShowContentComponent, { backdrop: 'static' }).componentInstance.params = { id: this.nsdID, page: 'nsd' }; + } + + /** Download NS Package @public */ + public downloadNSPackage(): void { + this.isLoadingDownloadResult = true; + const httpOptions: GETAPIURLHEADER = { + headers: this.headers, + responseType: 'blob' + }; + this.restService.getResource(environment.NSDESCRIPTORS_URL + '/' + this.nsdID + '/nsd_content', httpOptions) + .subscribe((response: Blob) => { + const binaryData: Blob[] = []; + binaryData.push(response); + this.sharedService.downloadFiles(this.nsdName, binaryData, response.type); + this.isLoadingDownloadResult = false; + this.changeDetactionforDownload(); + }, (error: ERRORDATA) => { + this.isLoadingDownloadResult = false; + this.notifierService.notify('error', this.translateService.instant('ERROR')); + this.changeDetactionforDownload(); + if (typeof error.error === 'object') { + error.error.text().then((data: string): void => { + error.error = JSON.parse(data); + this.restService.handleError(error, 'getBlob'); + }); + } + }); + } + + /** Compose NS Packages @public */ + public composeNSPackages(): void { + this.router.navigate(['/packages/ns/compose/', this.nsdID]).catch(() => { + // Catch Navigation Error + }); + } + + /** Change the detaction @public */ + public changeDetactionforDownload(): void { + setTimeout(() => { + this.cd.detectChanges(); + }, this.timeOut); + } + + /** Clone NS Packages @public */ + public cloneNSPackage(): void { + const cloneModal: NgbModalRef = this.modalService.open(ClonePackageComponent, { backdrop: 'static' }); + cloneModal.componentInstance.params = { id: this.nsdID, page: 'nsd', name: this.nsdName }; + cloneModal.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/utilities/page-per-row/PagePerRow.html b/src/app/utilities/page-per-row/PagePerRow.html new file mode 100644 index 0000000..a63ebb4 --- /dev/null +++ b/src/app/utilities/page-per-row/PagePerRow.html @@ -0,0 +1,26 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/utilities/page-per-row/PagePerRow.scss b/src/app/utilities/page-per-row/PagePerRow.scss new file mode 100644 index 0000000..06c069e --- /dev/null +++ b/src/app/utilities/page-per-row/PagePerRow.scss @@ -0,0 +1,23 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +.page-per-row { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; +} \ No newline at end of file diff --git a/src/app/utilities/page-per-row/PagePerRow.ts b/src/app/utilities/page-per-row/PagePerRow.ts new file mode 100644 index 0000000..6794bfc --- /dev/null +++ b/src/app/utilities/page-per-row/PagePerRow.ts @@ -0,0 +1,80 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ + +/** + * @file PagePerRow Model + */ +import { Component, EventEmitter, Injector, Output } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { PAGERSMARTTABLE } from 'CommonModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes PagePerRow.html as template url + */ +@Component({ + selector: 'page-per-row', + templateUrl: './PagePerRow.html', + styleUrls: ['./PagePerRow.scss'] +}) +/** Exporting a class @exports PagePerRow */ +export class PagePerRow { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** get the pagaintion default select value @public */ + public getDefaultSelected: number; + + /** Controls the pagination List Count form @public */ + public pageCount: { value: number; viewValue: number; }[] = + [ + { value: 10, viewValue: 10 }, + { value: 25, viewValue: 25 }, + { value: 50, viewValue: 50 }, + { value: 100, viewValue: 100 } + ]; + + /** Contains all methods related to shared @private */ + public sharedService: SharedService; + + /** Event emitter to emit selected page number @public */ + @Output() public pagePerRow: EventEmitter = new EventEmitter(); + + constructor(injector: Injector) { + this.injector = injector; + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + const getPaginationValues: PAGERSMARTTABLE = this.sharedService.paginationPagerConfig(); + this.getDefaultSelected = getPaginationValues.perPage; + } + + /** Handles select event @public */ + public onSelectRow(e: number): void { + this.pagePerRow.emit(e); + } +} diff --git a/src/app/utilities/page-per-row/PagePerRowModule.ts b/src/app/utilities/page-per-row/PagePerRowModule.ts new file mode 100644 index 0000000..e5b8a29 --- /dev/null +++ b/src/app/utilities/page-per-row/PagePerRowModule.ts @@ -0,0 +1,42 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Page Per Row Module. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { TranslateModule } from '@ngx-translate/core'; +import { PagePerRow } from 'PagePerRow'; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [CommonModule, TranslateModule], + declarations: [PagePerRow], + exports: [PagePerRow] +}) +/** Exporting a class @exports PagePerRowModule */ +export class PagePerRowModule { + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } +} diff --git a/src/app/utilities/page-reload/PageReload.html b/src/app/utilities/page-reload/PageReload.html new file mode 100644 index 0000000..7d03e52 --- /dev/null +++ b/src/app/utilities/page-reload/PageReload.html @@ -0,0 +1,21 @@ + + \ No newline at end of file diff --git a/src/app/utilities/page-reload/PageReload.scss b/src/app/utilities/page-reload/PageReload.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/page-reload/PageReload.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/page-reload/PageReload.ts b/src/app/utilities/page-reload/PageReload.ts new file mode 100644 index 0000000..0ea3c3c --- /dev/null +++ b/src/app/utilities/page-reload/PageReload.ts @@ -0,0 +1,61 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Page Reload Component + */ +import { Component, Injector } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { SharedService } from 'SharedService'; +/** + * Creating component + * @Component takes PageReload.html as template url + */ +@Component({ + selector: 'page-reload', + templateUrl: './PageReload.html', + styleUrls: ['./PageReload.scss'] +}) +/** Exporting a class @exports PageReload */ +export class PageReload { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } + + /** Handles select event @public */ + public reloadPage(): void { + this.sharedService.dataEvent.emit(); + } +} diff --git a/src/app/utilities/page-reload/PageReloadModule.ts b/src/app/utilities/page-reload/PageReloadModule.ts new file mode 100644 index 0000000..56c35fd --- /dev/null +++ b/src/app/utilities/page-reload/PageReloadModule.ts @@ -0,0 +1,43 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Page Per Row Module. + */ +import { CommonModule } from '@angular/common'; +import { NgModule } from '@angular/core'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateModule } from '@ngx-translate/core'; +import { PageReload } from 'PageReload'; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [CommonModule, TranslateModule, NgbModule], + declarations: [PageReload], + exports: [PageReload] +}) +/** Exporting a class @exports PageReloadModule */ +export class PageReloadModule { + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // Empty Block + } +} diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html new file mode 100644 index 0000000..351cf9a --- /dev/null +++ b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.html @@ -0,0 +1,25 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts new file mode 100644 index 0000000..8cfb6cf --- /dev/null +++ b/src/app/utilities/pdu-instances-action/PDUInstancesActionComponent.ts @@ -0,0 +1,88 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file PDUInstancesActionComponent Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { PDUInstanceDetails } from 'PDUInstanceModel'; +import { SharedService } from 'SharedService'; +import { ShowInfoComponent } from 'ShowInfoComponent'; + +/** + * Creating component + * @Component takes PDUInstancesActionComponent.html as template url + */ +@Component({ + templateUrl: './PDUInstancesActionComponent.html', + styleUrls: ['./PDUInstancesActionComponent.scss'] +}) +/** Exporting a class @exports PDUInstancesActionComponent */ +export class PDUInstancesActionComponent { + /** To get the value from the PDU Instances via valuePrepareFunction default Property of ng-smarttable @public */ + public value: PDUInstanceDetails; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains PDU Instance ID @private */ + private pduInstanceID: string; + + /** Service holds the router information @private */ + private router: Router; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.pduInstanceID = this.value.identifier; + } + + /** Delete PDU Instances @public */ + public deletePDUInstance(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'}); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Shows PDU Instances information using modalservice @public */ + public showInfo(): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.pduInstanceID, + page: 'pdu-instances', + titleName: 'INSTANCEDETAILS' + }; + } +} diff --git a/src/app/utilities/project-link/ProjectLinkComponent.html b/src/app/utilities/project-link/ProjectLinkComponent.html new file mode 100644 index 0000000..6d29f0b --- /dev/null +++ b/src/app/utilities/project-link/ProjectLinkComponent.html @@ -0,0 +1,25 @@ + + + {{value.projectName}}  + + + +{{value.projectName}} \ No newline at end of file diff --git a/src/app/utilities/project-link/ProjectLinkComponent.scss b/src/app/utilities/project-link/ProjectLinkComponent.scss new file mode 100644 index 0000000..152cf8d --- /dev/null +++ b/src/app/utilities/project-link/ProjectLinkComponent.scss @@ -0,0 +1,28 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; +.link{ + text-decoration: none !important; + &.activeProject{ + border-radius: 3px; + @include padding-value(2, 2, 2, 2); + text-decoration: none !important; + cursor: default; + } +} \ No newline at end of file diff --git a/src/app/utilities/project-link/ProjectLinkComponent.ts b/src/app/utilities/project-link/ProjectLinkComponent.ts new file mode 100644 index 0000000..35c5b2c --- /dev/null +++ b/src/app/utilities/project-link/ProjectLinkComponent.ts @@ -0,0 +1,81 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Project Link Component. + */ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Injector, OnInit } from '@angular/core'; +import { environment } from 'environment'; +import { ProjectData } from 'ProjectModel'; +import { ProjectService } from 'ProjectService'; +import { RestService } from 'RestService'; +import { UserDetail } from 'UserModel'; +/** + * Creating component + * @Component takes ProjectLinkComponent.html as template url + */ +@Component({ + selector: 'app-project-link', + templateUrl: './ProjectLinkComponent.html', + styleUrls: ['./ProjectLinkComponent.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +/** Exporting a class @exports ProjectLinkComponent */ +export class ProjectLinkComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + /** Variables holds the selected project @public */ + public selectedProject: string; + /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: ProjectData; + /** Variables holds all the projects @public */ + public projectList: {}[] = []; + /** Check the project is present for the user @public */ + public isPresent: boolean = false; + /** Set timeout @private */ + private timeOut: number = 10; + /** Instance of the rest service @private */ + private restService: RestService; + /** Holds all project details @private */ + private projectService: ProjectService; + /** Detect changes for the User Input */ + private cd: ChangeDetectorRef; + constructor(injector: Injector) { + this.injector = injector; + this.projectService = this.injector.get(ProjectService); + this.restService = this.injector.get(RestService); + this.cd = this.injector.get(ChangeDetectorRef); + } + + public ngOnInit(): void { + this.selectedProject = localStorage.getItem('project'); + this.getAdminProjects(); + } + + /** Get the admin projects to be selectable @public */ + public getAdminProjects(): void { + const username: string = localStorage.getItem('username'); + this.restService.getResource(environment.USERS_URL + '/' + username).subscribe((projects: UserDetail) => { + this.projectList = projects.project_role_mappings; + this.isPresent = this.projectList.some((item: ProjectData) => item.project === this.value.project); + setTimeout(() => { + this.cd.detectChanges(); + }, this.timeOut); + }); + } + +} diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.html b/src/app/utilities/projects-action/ProjectsActionComponent.html new file mode 100644 index 0000000..a5d4d4e --- /dev/null +++ b/src/app/utilities/projects-action/ProjectsActionComponent.html @@ -0,0 +1,34 @@ + +
+
+ + +
+
diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.scss b/src/app/utilities/projects-action/ProjectsActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/projects-action/ProjectsActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/projects-action/ProjectsActionComponent.ts b/src/app/utilities/projects-action/ProjectsActionComponent.ts new file mode 100644 index 0000000..4ac0051 --- /dev/null +++ b/src/app/utilities/projects-action/ProjectsActionComponent.ts @@ -0,0 +1,78 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Projects Action Component + */ +import { Component, Injector } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { ProjectCreateUpdateComponent } from 'ProjectCreateUpdate'; +import { ProjectData } from 'ProjectModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes ProjectsActionComponent.html as template url + */ +@Component({ + selector: 'app-projects-action', + templateUrl: './ProjectsActionComponent.html', + styleUrls: ['./ProjectsActionComponent.scss'] +}) +/** Exporting a class @exports ProjectsActionComponent */ +export class ProjectsActionComponent { + /** To get the value from the nspackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: ProjectData; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + } + + /** Delete project @public */ + public projectDelete(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Edit project @public */ + public projectEdit(): void { + const modalRef: NgbModalRef = this.modalService.open(ProjectCreateUpdateComponent, { backdrop: 'static' }); + modalRef.componentInstance.projectType = 'Edit'; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/utilities/roles-action/RolesActionComponent.html b/src/app/utilities/roles-action/RolesActionComponent.html new file mode 100644 index 0000000..5a7453d --- /dev/null +++ b/src/app/utilities/roles-action/RolesActionComponent.html @@ -0,0 +1,34 @@ + +
+
+ + +
+
diff --git a/src/app/utilities/roles-action/RolesActionComponent.scss b/src/app/utilities/roles-action/RolesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/roles-action/RolesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/roles-action/RolesActionComponent.ts b/src/app/utilities/roles-action/RolesActionComponent.ts new file mode 100644 index 0000000..5b4d85b --- /dev/null +++ b/src/app/utilities/roles-action/RolesActionComponent.ts @@ -0,0 +1,79 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Roles Action Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { RoleData } from 'RolesModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes RolesActionComponent.html as template url + */ +@Component({ + selector: 'app-roles-action', + templateUrl: './RolesActionComponent.html', + styleUrls: ['./RolesActionComponent.scss'] +}) +/** Exporting a class @exports RolesActionComponent */ +export class RolesActionComponent { + /** To get the role data via valuePrepareFunction default Property of ng-smarttable @public */ + public value: RoleData; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Holds the instance of roter service @private */ + private router: Router; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + this.router = this.injector.get(Router); + } + + /** Delete Role click handler @public */ + public deleteRole(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Edit Role click handler @public */ + public editRole(): void { + this.router.navigate(['/roles/edit', this.value.identifier]).catch(() => { + // Catch Navigation Error + }); + } + +} diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html new file mode 100644 index 0000000..454527e --- /dev/null +++ b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.html @@ -0,0 +1,27 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts new file mode 100644 index 0000000..cbf3fc1 --- /dev/null +++ b/src/app/utilities/sdn-controller-action/SDNControllerActionComponent.ts @@ -0,0 +1,83 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file SDN Controller Action Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { SDNControllerInfoComponent } from 'SDNControllerInfoComponent'; +import { SDNControllerList } from 'SDNControllerModel'; +import { SharedService } from 'SharedService'; + +/** + * Creating component + * @Component takes SDNControllerActionComponent.html as template url + */ +@Component({ + templateUrl: './SDNControllerActionComponent.html', + styleUrls: ['./SDNControllerActionComponent.scss'] +}) +/** Exporting a class @exports SDNControllerActionComponent */ +export class SDNControllerActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: SDNControllerList; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Variables holds SDN ID @private */ + private sdnID: string; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.sdnID = this.value.identifier; + } + + /** Show SDN Controller Information @public */ + public showSDNControllerInfo(): void { + this.modalService.open(SDNControllerInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.sdnID, + page: 'sdn-controller' + }; + } + + /** Delete SDN Controller @public */ + public deleteSDNController(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/utilities/show-info/ShowInfoComponent.html b/src/app/utilities/show-info/ShowInfoComponent.html new file mode 100644 index 0000000..7fff58d --- /dev/null +++ b/src/app/utilities/show-info/ShowInfoComponent.html @@ -0,0 +1,35 @@ + + + + + \ No newline at end of file diff --git a/src/app/utilities/show-info/ShowInfoComponent.scss b/src/app/utilities/show-info/ShowInfoComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/show-info/ShowInfoComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/show-info/ShowInfoComponent.ts b/src/app/utilities/show-info/ShowInfoComponent.ts new file mode 100644 index 0000000..0fb22e7 --- /dev/null +++ b/src/app/utilities/show-info/ShowInfoComponent.ts @@ -0,0 +1,216 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Info Ns Model + */ +import { HttpClient } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import 'codemirror/addon/dialog/dialog'; +import 'codemirror/addon/display/autorefresh'; +import 'codemirror/addon/display/fullscreen'; +import 'codemirror/addon/edit/closebrackets'; +import 'codemirror/addon/edit/matchbrackets'; +import 'codemirror/addon/fold/brace-fold'; +import 'codemirror/addon/fold/foldcode'; +import 'codemirror/addon/fold/foldgutter'; +import 'codemirror/addon/search/search'; +import 'codemirror/addon/search/searchcursor'; +import 'codemirror/keymap/sublime'; +import 'codemirror/lib/codemirror'; +import 'codemirror/mode/javascript/javascript'; +import 'codemirror/mode/markdown/markdown'; +import 'codemirror/mode/yaml/yaml'; +import { ERRORDATA, URLPARAMS } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { NSDDetails } from 'NSDModel'; +import { RestService } from 'RestService'; +/** Set defaults json as type in information modal @constant */ +const defaults: {} = { + 'text/json': '' +}; +/** + * Creating component + * @Component takes ShowInfoComponent.html as template url + */ +@Component({ + templateUrl: './ShowInfoComponent.html', + styleUrls: ['./ShowInfoComponent.scss'] +}) +/** Exporting a class @exports ShowInfoComponent */ +export class ShowInfoComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** dataService to pass the data from one component to another @public */ + public dataService: DataService; + + /** Default variables holds NS data @public */ + public defaults: {} = defaults; + + /** Varaibles to hold http client @public */ + public httpClient: HttpClient; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** variables readOnly holds boolean @public */ + public readOnly: boolean = true; + + /** variables to hold mode changes of editor @public */ + public mode: string = 'text/json'; + + /** To Set Mode @public */ + public modeDefault: string = 'javascript'; + + /** variables to hold options of editor @public */ + public options: {} = { + mode: this.modeDefault, + showCursorWhenSelecting: true, + autofocus: true, + lineNumbers: true, + lineWrapping: true, + foldGutter: true, + gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'], + autoCloseBrackets: true, + matchBrackets: true, + theme: 'neat', + keyMap: 'sublime' + }; + + /** Reading the page Name @public */ + public titleName: string; + + /** Check the loading results @public */ + public isLoadingResults: Boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Input contains component objects @private */ + @Input() private params: URLPARAMS; + + /** Instance of the rest service @private */ + private restService: RestService; + + constructor(injector: Injector) { + this.injector = injector; + this.dataService = this.injector.get(DataService); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.isLoadingResults = true; + this.defaults['text/json'] = ''; + this.titleName = this.params.titleName; + // Checks page and assign URL + if (this.params.page === 'ns-instance') { + this.restService.getResource(environment.NSINSTANCESCONTENT_URL + '/' + this.params.id).subscribe((nsData: NSDDetails[]) => { + this.defaults['text/json'] = JSON.stringify(nsData, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'ns-history-operation') { + this.restService.getResource(environment.NSHISTORYOPERATIONS_URL + '/' + + this.params.id).subscribe((nsHistoryOpn: {}[]) => { + this.defaults['text/json'] = JSON.stringify(nsHistoryOpn, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'vnf-instance') { + this.restService.getResource(environment.VNFINSTANCES_URL + '/' + this.params.id).subscribe((vnfData: {}[]) => { + this.defaults['text/json'] = JSON.stringify(vnfData, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'net-slice-package') { + this.restService.getResource(environment.NETWORKSLICETEMPLATECONTENT_URL + '/' + this.params.id).subscribe((netSliceData: {}[]) => { + this.defaults['text/json'] = JSON.stringify(netSliceData, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'net-slice-instance') { + this.restService.getResource(environment.NETWORKSLICEINSTANCESCONTENT_URL + '/' + this.params.id) + .subscribe((netSliceInstanceData: {}[]) => { + this.defaults['text/json'] = JSON.stringify(netSliceInstanceData, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'nst-history-operation') { + this.restService.getResource(environment.NSTHISTORYOPERATIONS_URL + '/' + + this.params.id).subscribe((nstHistoryOpn: {}[]) => { + this.defaults['text/json'] = JSON.stringify(nstHistoryOpn, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'pdu-instances') { + this.restService.getResource(environment.PDUINSTANCE_URL + '/' + + this.params.id).subscribe((pduInstanceOpn: {}[]) => { + this.defaults['text/json'] = JSON.stringify(pduInstanceOpn, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'k8s-cluster') { + this.restService.getResource(environment.K8SCLUSTER_URL + '/' + + this.params.id).subscribe((k8sclusterOpn: {}[]) => { + this.defaults['text/json'] = JSON.stringify(k8sclusterOpn, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } else if (this.params.page === 'k8s-repo') { + this.restService.getResource(environment.K8REPOS_URL + '/' + + this.params.id).subscribe((k8srepoOpn: {}[]) => { + this.defaults['text/json'] = JSON.stringify(k8srepoOpn, null, '\t'); + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'get'); + }, () => { + this.isLoadingResults = false; + }); + } + } +} diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.html b/src/app/utilities/switch-project/SwitchProjectComponent.html new file mode 100644 index 0000000..948591a --- /dev/null +++ b/src/app/utilities/switch-project/SwitchProjectComponent.html @@ -0,0 +1,40 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.scss b/src/app/utilities/switch-project/SwitchProjectComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/switch-project/SwitchProjectComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/switch-project/SwitchProjectComponent.ts b/src/app/utilities/switch-project/SwitchProjectComponent.ts new file mode 100644 index 0000000..1df6a16 --- /dev/null +++ b/src/app/utilities/switch-project/SwitchProjectComponent.ts @@ -0,0 +1,139 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Switch Project Component + */ +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { APIURLHEADER, ERRORDATA, LOCALSTORAGE, URLPARAMS } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; + +/** + * Creating component + * @Component takes SwitchProjectComponent.html as template url + */ +@Component({ + templateUrl: './SwitchProjectComponent.html', + styleUrls: ['./SwitchProjectComponent.scss'] +}) +/** Exporting a class @exports SwitchProjectComponent */ +export class SwitchProjectComponent implements OnInit { + /** Invoke service injectors @public */ + public injector: Injector; + + /** dataService to pass the data from one component to another @public */ + public dataService: DataService; + + /** Varaibles to hold http client @public */ + public httpClient: HttpClient; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** FormGroup instance added to the form @ html @public */ + public switchProjectForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Check the Projects loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Input contains component objects @private */ + @Input() private params: URLPARAMS; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + constructor(injector: Injector) { + this.injector = injector; + this.dataService = this.injector.get(DataService); + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.formBuilder = this.injector.get(FormBuilder); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.switchProjectForm.controls; } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.initializeForm(); + } + + /** initialize Forms @public */ + public initializeForm(): void { + this.switchProjectForm = this.formBuilder.group({ + password: ['', [Validators.required]] + }); + } + + /** Switch project @public */ + public switchProject(): void { + this.submitted = true; + if (!this.switchProjectForm.invalid) { + this.isLoadingResults = true; + this.headers = new HttpHeaders({ + 'Content-Type': 'application/json', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + const payLoad: {} = JSON.stringify({ + username: this.params.username, + password: this.switchProjectForm.value.password, + project_id: this.params.projectID + }); + const apiURLHeader: APIURLHEADER = { + url: environment.GENERATETOKEN_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, payLoad).subscribe((data: LOCALSTORAGE) => { + if (data) { + localStorage.setItem('id_token', data.id); + localStorage.setItem('project_id', this.params.projectID); + localStorage.setItem('expires', data.expires.toString()); + localStorage.setItem('username', data.username); + localStorage.setItem('project', data.project_name); + localStorage.setItem('token_state', data.id); + this.activeModal.close(); + location.reload(); + this.isLoadingResults = false; + } + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + this.restService.handleError(error, 'post'); + this.activeModal.close(); + }); + } + } +} diff --git a/src/app/utilities/users-action/UsersActionComponent.html b/src/app/utilities/users-action/UsersActionComponent.html new file mode 100644 index 0000000..9ce546e --- /dev/null +++ b/src/app/utilities/users-action/UsersActionComponent.html @@ -0,0 +1,42 @@ + +
+
+ + +
+
\ No newline at end of file diff --git a/src/app/utilities/users-action/UsersActionComponent.scss b/src/app/utilities/users-action/UsersActionComponent.scss new file mode 100644 index 0000000..fdec4ed --- /dev/null +++ b/src/app/utilities/users-action/UsersActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ diff --git a/src/app/utilities/users-action/UsersActionComponent.ts b/src/app/utilities/users-action/UsersActionComponent.ts new file mode 100644 index 0000000..1d8e895 --- /dev/null +++ b/src/app/utilities/users-action/UsersActionComponent.ts @@ -0,0 +1,101 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Users Action Component + */ +import { Component, Injector } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { AddEditUserComponent } from 'AddEditUserComponent'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { ProjectRoleComponent } from 'ProjectRoleComponent'; +import { SharedService } from 'SharedService'; +import { UserData } from 'UserModel'; +/** + * Creating component + * @Component takes UsersActionComponent.html as template url + */ +@Component({ + templateUrl: './UsersActionComponent.html', + styleUrls: ['./UsersActionComponent.scss'] +}) +/** Exporting a class @exports UsersActionComponent */ +export class UsersActionComponent { + /** To inject services @public */ + public injector: Injector; + + /** To get the value from the Users action via valuePrepareFunction default Property of ng-smarttable @public */ + public value: UserData; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + } + + /** Delete User Account @public */ + public deleteUser(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Edit User Account @public */ + public editUserModal(editType: string): void { + const modalRef: NgbModalRef = this.modalService.open(AddEditUserComponent, { backdrop: 'static' }); + modalRef.componentInstance.userID = this.value.identifier; + if (editType === 'editPassword') { + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITCREDENTIALS'); + } else { + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITUSERNAME'); + } + modalRef.componentInstance.userType = editType; + modalRef.componentInstance.userName = this.value.username; + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Edit User Account @public */ + public projectRolesModal(): void { + const modalRef: NgbModalRef = this.modalService.open(ProjectRoleComponent, { backdrop: 'static' }); + modalRef.componentInstance.userID = this.value.identifier; + modalRef.componentInstance.userTitle = this.translateService.instant('PAGE.USERS.EDITPROJECTROLEMAPPING'); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html new file mode 100644 index 0000000..7491d59 --- /dev/null +++ b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.html @@ -0,0 +1,46 @@ + +
+ + {{'PAGE.DASHBOARD.RUNNINGINSTANCES' | translate}} + + + + + + + + +
\ No newline at end of file diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts new file mode 100644 index 0000000..57f1f64 --- /dev/null +++ b/src/app/utilities/vim-accounts-action/VimAccountsActionComponent.ts @@ -0,0 +1,104 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Vim AccountsAction Component + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { NSInstanceDetails } from 'NSInstanceModel'; +import { SharedService } from 'SharedService'; +import { VIMData } from 'VimAccountModel'; + +/** + * Creating component + * @Component takes VimAccountsActionComponent.html as template url + */ +@Component({ + selector: 'app-vim-accounts-action', + templateUrl: './VimAccountsActionComponent.html', + styleUrls: ['./VimAccountsActionComponent.scss'] +}) +/** Exporting a class @exports VimAccountsActionComponent */ +export class VimAccountsActionComponent implements OnInit { + /** To get the value from the vimAccounts via valuePrepareFunction default Property of ng-smarttable @public */ + public value: VIMData; + + /** To inject services @public */ + public injector: Injector; + + /** To show Instances running @public */ + public showMapIcon: boolean = false; + + /** To show Details Instances running @public */ + public showInstanceDetails: {}[]; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Variables holds NS ID @private */ + private vimID: string; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.sharedService = this.injector.get(SharedService); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.getInstancesDetails(); + } + + /** Delete VIM Account @public */ + public deleteVIMAccount(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, {backdrop: 'static'}); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** On navigate to Info VimAccount @public */ + public vimInfo(): void { + this.vimID = this.value.identifier; + this.router.navigate(['/vim/info', this.vimID]).catch(() => { + // Catch Navigation Error + }); + } + + /** To show the Instances Info for the particular VimAccount @public */ + public getInstancesDetails(): void { + this.showInstanceDetails = []; + this.value.instancesData.filter((item: NSInstanceDetails) => { + if (item.datacenter === this.value.identifier) { + this.showMapIcon = true; + this.showInstanceDetails.push(item); + } + }); + } +} diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html new file mode 100644 index 0000000..333beea --- /dev/null +++ b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.html @@ -0,0 +1,23 @@ + +
+ +
\ No newline at end of file diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss new file mode 100644 index 0000000..8c2b739 --- /dev/null +++ b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ diff --git a/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts new file mode 100644 index 0000000..d3a95f2 --- /dev/null +++ b/src/app/utilities/vnf-instances-action/VNFInstancesActionComponent.ts @@ -0,0 +1,67 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file VNF-instancesAction Component + */ +import { Component, Injector } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ShowInfoComponent } from 'ShowInfoComponent'; +import { VNFInstanceData } from 'VNFInstanceModel'; +/** + * Creating component + * @Component takes VNFInstancesActionComponent.html as template url + */ +@Component({ + templateUrl: './VNFInstancesActionComponent.html', + styleUrls: ['./VNFInstancesActionComponent.scss'] +}) +/** Exporting a class @exports VNFInstancesActionComponent */ +export class VNFInstancesActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: VNFInstanceData; + + /** Invoke service injectors @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Contains instance ID @private */ + private instanceID: string; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.instanceID = this.value.identifier; + } + + /** Shows information using modalservice @public */ + public infoVNF(): void { + this.modalService.open(ShowInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.instanceID, + page: 'vnf-instance', + titleName: 'INSTANCEDETAILS' + }; + } +} diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html new file mode 100644 index 0000000..df3aa52 --- /dev/null +++ b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.html @@ -0,0 +1,51 @@ + +
+ + +
+ + +
+
+ \ No newline at end of file diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts new file mode 100644 index 0000000..f9d1955 --- /dev/null +++ b/src/app/utilities/vnf-packages-action/VNFPackagesActionComponent.ts @@ -0,0 +1,187 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file VNF-packagesAction Component + */ +import { HttpHeaders } from '@angular/common/http'; +import { ChangeDetectorRef, Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { ClonePackageComponent } from 'ClonePackage'; +import { ERRORDATA, GETAPIURLHEADER, MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { ShowContentComponent } from 'ShowContent'; +import { VNFData } from 'VNFDModel'; + +/** + * Creating component + * @Component takes VNFPackagesActionComponent.html as template url + */ +@Component({ + templateUrl: './VNFPackagesActionComponent.html', + styleUrls: ['./VNFPackagesActionComponent.scss'] +}) +/** Exporting a class @exports VNFPackagesActionComponent */ +export class VNFPackagesActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: VNFData; + + /** To inject services @public */ + public injector: Injector; + + /** Check the loading results for loader status @public */ + public isLoadingDownloadResult: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Variables holds NS ID @private */ + private vnfID: string; + + /** Variables holds NS name @private */ + private vnfName: string; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Detect changes for the User Input */ + private cd: ChangeDetectorRef; + + /** Set timeout @private */ + private timeOut: number = 1000; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.sharedService = this.injector.get(SharedService); + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.cd = this.injector.get(ChangeDetectorRef); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.headers = new HttpHeaders({ + Accept: 'application/zip, application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + this.vnfID = this.value.identifier; + this.vnfName = this.value.shortName; + } + + /** Delete VNF packages @public */ + public deleteVNFPackage(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Set instance for NSD Edit @public */ + public vnfdEdit(): void { + this.router.navigate(['/packages/vnf/edit/', this.vnfID]).then((nav: {}) => { + // Navigated Successfully + }, (error: Error) => { + // Navigation Error Handler + }); + } + + /** list out all the file content of a descriptors @public */ + public showContent(): void { + this.modalService.open(ShowContentComponent, { backdrop: 'static' }).componentInstance.params = { id: this.vnfID, page: 'vnfd' }; + } + + /** Download VNF Package @public */ + public downloadVNFPackage(): void { + this.isLoadingDownloadResult = true; + const httpOptions: GETAPIURLHEADER = { + headers: this.headers, + responseType: 'blob' + }; + this.restService.getResource(environment.VNFPACKAGES_URL + '/' + this.vnfID + '/package_content', httpOptions) + .subscribe((response: Blob) => { + this.isLoadingDownloadResult = false; + this.changeDetactionforDownload(); + const binaryData: Blob[] = []; + binaryData.push(response); + this.sharedService.downloadFiles(this.vnfName, binaryData, response.type); + }, (error: ERRORDATA) => { + this.isLoadingDownloadResult = false; + this.notifierService.notify('error', this.translateService.instant('ERROR')); + this.changeDetactionforDownload(); + if (typeof error.error === 'object') { + error.error.text().then((data: string): void => { + error.error = JSON.parse(data); + this.restService.handleError(error, 'getBlob'); + }); + } + }); + } + + /** Compose VNF Packages @public */ + public composeVNFPackages(): void { + this.router.navigate(['/packages/vnf/compose/', this.vnfID]).catch(); + } + + /** Change the detaction @public */ + public changeDetactionforDownload(): void { + setTimeout(() => { + this.cd.detectChanges(); + }, this.timeOut); + } + + /** Clone NS Packages @public */ + public cloneVNFPackage(): void { + const cloneModal: NgbModalRef = this.modalService.open(ClonePackageComponent, { backdrop: 'static' }); + cloneModal.componentInstance.params = { id: this.vnfID, page: 'vnfd', name: this.vnfName }; + cloneModal.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html new file mode 100644 index 0000000..902bb42 --- /dev/null +++ b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.html @@ -0,0 +1,27 @@ + +
+ + +
\ No newline at end of file diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss new file mode 100644 index 0000000..031e56e --- /dev/null +++ b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts new file mode 100644 index 0000000..0769863 --- /dev/null +++ b/src/app/utilities/wim-accounts-action/WIMAccountsActionComponent.ts @@ -0,0 +1,83 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file WIM AccountsAction Component + */ +import { Component, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbActiveModal, NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { MODALCLOSERESPONSEDATA } from 'CommonModel'; +import { DeleteComponent } from 'DeleteComponent'; +import { SharedService } from 'SharedService'; +import { WIMAccountInfoComponent } from 'WIMAccountInfo'; +import { WIMValue } from 'WIMAccountModel'; + +/** + * Creating component + * @Component takes WIMAccountsActionComponent.html as template url + */ +@Component({ + templateUrl: './WIMAccountsActionComponent.html', + styleUrls: ['./WIMAccountsActionComponent.scss'] +}) +/** Exporting a class @exports WIMAccountsActionComponent */ +export class WIMAccountsActionComponent { + /** To get the value from the vnfpackage via valuePrepareFunction default Property of ng-smarttable @public */ + public value: WIMValue; + + /** To inject services @public */ + public injector: Injector; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Variables holds WIM ID @private */ + private wimID: string; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.modalService = this.injector.get(NgbModal); + this.sharedService = this.injector.get(SharedService); + } + + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.wimID = this.value.identifier; + } + + /** Show WIM account information @public */ + public showWIMAccountInfo(): void { + this.modalService.open(WIMAccountInfoComponent, { backdrop: 'static' }).componentInstance.params = { + id: this.wimID, + page: 'wim-accounts' + }; + } + + /** Delete WIM Account @public */ + public deleteWIMAccount(): void { + const modalRef: NgbModalRef = this.modalService.open(DeleteComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } +} diff --git a/src/app/vim-accounts/VimAccountsComponent.html b/src/app/vim-accounts/VimAccountsComponent.html new file mode 100644 index 0000000..3f96ff8 --- /dev/null +++ b/src/app/vim-accounts/VimAccountsComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/vim-accounts/VimAccountsComponent.scss b/src/app/vim-accounts/VimAccountsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/vim-accounts/VimAccountsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/vim-accounts/VimAccountsComponent.ts b/src/app/vim-accounts/VimAccountsComponent.ts new file mode 100644 index 0000000..9951cfc --- /dev/null +++ b/src/app/vim-accounts/VimAccountsComponent.ts @@ -0,0 +1,56 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Vim Account Component. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; + +/** + * Creating component + * @Component takes VimAccountsComponent.html as template url + */ +@Component({ + selector: 'app-vim-accounts', + templateUrl: './VimAccountsComponent.html', + styleUrls: ['./VimAccountsComponent.scss'] +}) +/** Exporting a class @exports VimAccountsComponent */ +export class VimAccountsComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/vim') { + this.router.navigate(['/vim/details']).catch(); + } + } +} diff --git a/src/app/vim-accounts/VimAccountsModule.ts b/src/app/vim-accounts/VimAccountsModule.ts new file mode 100644 index 0000000..3424bc4 --- /dev/null +++ b/src/app/vim-accounts/VimAccountsModule.ts @@ -0,0 +1,92 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Vim Account module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataService } from 'DataService'; +import { InfoVimComponent } from 'InfoVim'; +import { LoaderModule } from 'LoaderModule'; +import { NewVimaccountComponent } from 'NewVimaccount'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { VimAccountDetailsComponent } from 'VimAccountDetails'; +import { VimAccountsComponent } from 'VimAccountsComponent'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** const values for dashboard Routes */ +const routes: Routes = [ + { + path: '', + component: VimAccountsComponent, + children: [ + { + path: 'details', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VIMACCOUNTS', url: null }] + }, + component: VimAccountDetailsComponent + }, + { + path: 'info/:id', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VIMACCOUNTS', url: '/vim/details' }, { title: '{id}', url: null }] + }, + component: InfoVimComponent + }, + { + path: 'new', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'VIMACCOUNTS', url: '/vim/details' }, { title: 'PAGE.VIMDETAILS.NEWVIM', url: null }] + }, + component: NewVimaccountComponent + } + ] + } +]; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule, + HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule, + PagePerRowModule, LoaderModule, PageReloadModule], + declarations: [VimAccountsComponent, InfoVimComponent, VimAccountDetailsComponent, NewVimaccountComponent], + providers: [DataService], + entryComponents: [InfoVimComponent] +}) +/** Exporting a class @exports VimAccountsModule */ +export class VimAccountsModule { + /** Variables declared to avoid state-less class */ + private vimModule: string; +} diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.html b/src/app/vim-accounts/info-vim/InfoVimComponent.html new file mode 100644 index 0000000..2eac832 --- /dev/null +++ b/src/app/vim-accounts/info-vim/InfoVimComponent.html @@ -0,0 +1,47 @@ + +
+
{{'PAGE.VIMDETAILS.VIMACCOUNTDETAILS' | translate}}
+
+
+
+
+ + {{details.value}} +
+
+
+
+ +
+
+
+
+ + {{(details.value !== undefined)?details.value : '--'}} +
+
+
+ + \ No newline at end of file diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.scss b/src/app/vim-accounts/info-vim/InfoVimComponent.scss new file mode 100644 index 0000000..8c2b739 --- /dev/null +++ b/src/app/vim-accounts/info-vim/InfoVimComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ diff --git a/src/app/vim-accounts/info-vim/InfoVimComponent.ts b/src/app/vim-accounts/info-vim/InfoVimComponent.ts new file mode 100644 index 0000000..d40b696 --- /dev/null +++ b/src/app/vim-accounts/info-vim/InfoVimComponent.ts @@ -0,0 +1,445 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Info VIM Page + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { ERRORDATA } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import { RestService } from 'RestService'; +import { isNullOrUndefined } from 'util'; +import { CONFIG, VimAccountDetails, VIMData } from 'VimAccountModel'; + +/** + * Creating component + * @Component InfoVimComponent.html as template url + */ +@Component({ + selector: 'app-info-vim', + templateUrl: './InfoVimComponent.html', + styleUrls: ['./InfoVimComponent.scss'] +}) +/** Exporting a class @exports InfoVimComponent */ +export class InfoVimComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** vimAccountDetails to populate in InfoVIM Page @private */ + public vimAccountDetails: VimAccountDetails; + + /** Information Top Left @public */ + public configParams: {}[] = []; + + /** Showing more details of collapase */ + public isCollapsed: boolean = true; + + /** Contains vim details @public */ + public vimDetails: {}[]; + + /** Check the Projects loading results @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** variables contains paramsID @private */ + private paramsID: string; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Holds the instance of router class @private */ + private router: Router; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** vimId to populate in InfoVIM Page @private */ + private vimId: string; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private activatedRoute: ActivatedRoute; + + /** Utilizes modal service for any modal operations @private */ + private modalService: NgbModal; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.activatedRoute = this.injector.get(ActivatedRoute); + this.modalService = this.injector.get(NgbModal); + this.router = this.injector.get(Router); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + // tslint:disable-next-line:no-backbone-get-set-outside-model + this.paramsID = this.activatedRoute.snapshot.paramMap.get('id'); + this.dataService.currentMessage.subscribe((data: VIMData) => { + this.vimId = data.identifier; + }); + this.generateData(); + } + + /** Routing to VIM Account Details Page @public */ + public onVimAccountBack(): void { + this.router.navigate(['vim/details']).catch(() => { + // Error Cached + }); + } + + /** Generate Data function @public */ + public generateData(): void { + this.isLoadingResults = true; + this.restService.getResource(environment.VIMACCOUNTS_URL + '/' + this.paramsID) + .subscribe((vimAccountsData: VimAccountDetails) => { + this.showDetails(vimAccountsData); + if (vimAccountsData.config !== undefined) { + if (vimAccountsData.vim_type === 'openstack') { + this.showOpenstackConfig(vimAccountsData.config); + } else if (vimAccountsData.vim_type === 'aws') { + this.awsConfig(vimAccountsData.config); + } else if (vimAccountsData.vim_type === 'openvim' || vimAccountsData.vim_type === 'opennebula') { + this.openVIMOpenNebulaConfig(vimAccountsData.config); + } else if (vimAccountsData.vim_type === 'vmware') { + this.vmwareConfig(vimAccountsData.config); + } else if (vimAccountsData.vim_type === 'azure') { + this.azureConfig(vimAccountsData.config); + } + } + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.isLoadingResults = false; + if (error.error.status === HttpStatus.NOT_FOUND || error.error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + } + }); + } + + /** show general vim detailed information @public */ + public showDetails(vimAccountsData: VimAccountDetails): void { + this.vimDetails = [ + { + title: 'PAGE.VIMDETAILS.NAME', + value: vimAccountsData.name + }, + { + title: 'PAGE.VIMDETAILS.VIMUSERNAME', + value: vimAccountsData.vim_user + }, + { + title: 'PAGE.VIMDETAILS.VIMURL', + value: vimAccountsData.vim_url + }, + { + title: 'PAGE.VIMDETAILS.VIMTYPE', + value: vimAccountsData.vim_type + }, + { + title: 'PAGE.VIMDETAILS.TENANTNAME', + value: vimAccountsData.vim_tenant_name + }, + { + title: 'PAGE.VIMDETAILS.DESCRIPTION', + value: vimAccountsData.description + }, + { + title: 'PAGE.VIMDETAILS.SCHEMATYPE', + value: vimAccountsData.schema_type + }, + { + title: 'PAGE.VIMDETAILS.SCHEMAVERSION', + value: vimAccountsData.schema_version + } + ]; + } + + /** Openstack Config @public */ + public showOpenstackConfig(config: CONFIG): void { + if (!isNullOrUndefined(config)) { + Object.keys(config).forEach((key: string) => { + if (Array.isArray(config[key])) { + config[key] = JSON.stringify(config[key]); + } + }); + } + let location: string = config.location; + if (!isNullOrUndefined(location)) { + const locationArr: string[] = config.location.split(','); + if (Array.isArray(locationArr)) { + location = locationArr[0]; + } + } + + this.configParams = [ + { + title: 'PAGE.VIMDETAILS.SDNCONTROLLER', + value: config.sdn_controller + }, + { + title: 'PAGE.VIMDETAILS.SDNPORTMAPPING', + value: config.sdn_port_mapping + }, + { + title: 'PAGE.VIMDETAILS.VIMNETWORKNAME', + value: config.vim_network_name + }, + { + title: 'PAGE.VIMDETAILS.SECURITYGROUPS', + value: config.security_groups + }, + { + title: 'PAGE.VIMDETAILS.AVAILABILITYZONE', + value: config.availabilityZone + }, + { + title: 'PAGE.VIMDETAILS.REGIONALNAME', + value: config.region_name + }, + { + title: 'PAGE.VIMDETAILS.INSECURE', + value: config.insecure + }, + { + title: 'PAGE.VIMDETAILS.USEEXISTINGFLAVOURS', + value: config.use_existing_flavors + }, + { + title: 'PAGE.VIMDETAILS.USEINTERNALENDPOINT', + value: config.use_internal_endpoint + }, + { + title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG', + value: config.additional_conf + }, + { + title: 'PAGE.VIMDETAILS.APIVERSION', + value: config.APIversion + }, + { + title: 'PAGE.VIMDETAILS.PROJECTDOMAINID', + value: config.project_domain_id + }, + { + title: 'PAGE.VIMDETAILS.PROJECTDOMAINNAME', + value: config.project_domain_name + }, + { + title: 'PAGE.VIMDETAILS.USERDOMAINID', + value: config.user_domain_id + }, + { + title: 'PAGE.VIMDETAILS.USERDOMAINUSER', + value: config.user_domain_name + }, + { + title: 'PAGE.VIMDETAILS.KEYPAIR', + value: config.keypair + }, + { + title: 'PAGE.VIMDETAILS.DATAPLANEPHYSICALNET', + value: config.dataplane_physical_net + }, + { + title: 'PAGE.VIMDETAILS.USEFLOATINGIP', + value: config.use_floating_ip + }, + { + title: 'PAGE.VIMDETAILS.MICROVERSION', + value: config.microversion + }, + { + title: 'PAGE.VIMDETAILS.VIMLOCATION', + value: location + } + ]; + } + + /** AWS Config @public */ + public awsConfig(config: CONFIG): void { + this.configParams = [ + { + title: 'PAGE.VIMDETAILS.SDNCONTROLLER', + value: config.sdn_controller + }, + { + title: 'PAGE.VIMDETAILS.VPCCIDRBLOCK', + value: config.vpc_cidr_block + }, + { + title: 'PAGE.VIMDETAILS.SDNPORTMAPPING', + value: config.sdn_port_mapping + }, + { + title: 'PAGE.VIMDETAILS.SECURITYGROUPS', + value: config.security_groups + }, + { + title: 'PAGE.VIMDETAILS.VIMNETWORKNAME', + value: config.vim_network_name + }, + { + title: 'PAGE.VIMDETAILS.KEYPAIR', + value: config.keypair + }, + { + title: 'PAGE.VIMDETAILS.REGIONALNAME', + value: config.region_name + }, + { + title: 'PAGE.VIMDETAILS.FLAVORIINFO', + value: config.flavor_info + }, + { + title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG', + value: config.additional_conf + } + ]; + } + + /** Open vim and open nebula config @public */ + public openVIMOpenNebulaConfig(config: CONFIG): void { + this.configParams = [ + { + title: 'PAGE.VIMDETAILS.SDNCONTROLLER', + value: config.sdn_controller + }, + { + title: 'PAGE.VIMDETAILS.SDNPORTMAPPING', + value: config.sdn_port_mapping + }, + { + title: 'PAGE.VIMDETAILS.VIMNETWORKNAME', + value: config.vim_network_name + }, + { + title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG', + value: config.additional_conf + } + ]; + } + + /** vmware config @public */ + public vmwareConfig(config: CONFIG): void { + this.configParams = [ + { + title: 'PAGE.VIMDETAILS.SDNCONTROLLER', + value: config.sdn_controller + }, + { + title: 'PAGE.VIMDETAILS.ORGNAME', + value: config.orgname + }, + { + title: 'PAGE.VIMDETAILS.SDNPORTMAPPING', + value: config.sdn_port_mapping + }, + { + title: 'PAGE.VIMDETAILS.VCENTERIP', + value: config.vcenter_ip + }, + { + title: 'PAGE.VIMDETAILS.VIMNETWORKNAME', + value: config.vim_network_name + }, + { + title: 'PAGE.VIMDETAILS.VCENTERPORT', + value: config.vcenter_port + }, + { + title: 'PAGE.VIMDETAILS.ADMINUSERNAME', + value: config.admin_username + }, + { + title: 'PAGE.VIMDETAILS.VCENTERUSER', + value: config.vcenter_user + }, + { + title: 'PAGE.VIMDETAILS.ADMINPASSWORD', + value: config.admin_password + }, + { + title: 'PAGE.VIMDETAILS.VCENTERPASSWORD', + value: config.vcenter_password + }, + { + title: 'PAGE.VIMDETAILS.NSXMANAGER', + value: config.nsx_manager + }, + { + title: 'PAGE.VIMDETAILS.VROPSSITE', + value: config.vrops_site + }, + { + title: 'PAGE.VIMDETAILS.NSXUSER', + value: config.nsx_user + }, + { + title: 'PAGE.VIMDETAILS.VROPSUSER', + value: config.vrops_user + }, + { + title: 'PAGE.VIMDETAILS.NSXPASSWORD', + value: config.nsx_password + }, + { + title: 'PAGE.VIMDETAILS.VROPSPASSWORD', + value: config.vrops_password + }, + { + title: 'PAGE.VIMDETAILS.ADDITIONALCONFIG', + value: config.additional_conf + } + ]; + } + + /** Azure Config @public */ + public azureConfig(config: CONFIG): void { + this.configParams = [ + { + title: 'PAGE.VIMDETAILS.SUBSCRIPTIONID', + value: config.subscription_id + }, + { + title: 'PAGE.VIMDETAILS.REGIONALNAME', + value: config.region_name + }, + { + title: 'PAGE.VIMDETAILS.RESOURCEGROUP', + value: config.resource_group + }, + { + title: 'PAGE.VIMDETAILS.VNETNAME', + value: config.vnet_name + }, + { + title: 'PAGE.VIMDETAILS.FLAVORSPATTERN', + value: config.flavors_pattern + } + ]; + } +} diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html new file mode 100644 index 0000000..cc56017 --- /dev/null +++ b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.html @@ -0,0 +1,661 @@ + +
+
+
{{'PAGE.VIMDETAILS.NEWVIMACCOUNT' | translate}}
+
+
+
+ +
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
{{'DOMVALIDATIONS.INVALIDURL' | translate}}
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+
+
+
+ +
+
+
+ + +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+
+
+ +
+
+ + +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ + +
+
+
+
+ +
+
+ + + {{'PAGE.VIM.LOACTIONINFO' | translate}} +
+
+
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+ +
+
+ +
+
+
+
+ +
+
+ +
+
+
+
+
+ +
+ \ No newline at end of file diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss new file mode 100644 index 0000000..d750ccc --- /dev/null +++ b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts new file mode 100644 index 0000000..bc6fd1e --- /dev/null +++ b/src/app/vim-accounts/new-vimaccount/NewVimaccountComponent.ts @@ -0,0 +1,321 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Vim Account Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, TYPESECTION, VIM_TYPES } from 'CommonModel'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; +import { FEATURES, VIMLOCATION, VIMLOCATIONDATA } from 'VimAccountModel'; + +/** + * Creating component + * @Component takes NewVimaccountComponent.html as template url + */ +@Component({ + selector: 'app-new-vimaccount', + templateUrl: './NewVimaccountComponent.html', + styleUrls: ['./NewVimaccountComponent.scss'] +}) +/** Exporting a class @exports NewVimaccountComponent */ +export class NewVimaccountComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** FormGroup vim New Account added to the form @ html @public */ + public vimNewAccountForm: FormGroup; + + /** Supported Vim type for the dropdown */ + public vimType: TYPESECTION[]; + + /** Supported Vim type for the dropdown */ + public selectedVimType: string; + + /** Supported true and false value for the dropdown */ + public boolValue: {}[]; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Showing more details of collapase */ + public isCollapsed: boolean = false; + + /** Vim location values @public */ + public getVIMLocation: VIMLOCATIONDATA[] = []; + + /** Check the Projects loading results @public */ + public isLocationLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** set the longitude value of the selected place @public */ + public setLong: number; + + /** set the latitude value of the selected place @public */ + public setLat: number; + + /** Element ref for fileInput @public */ + @ViewChild('fileInput', { static: true }) public fileInput: ElementRef; + + /** Element ref for fileInput @public */ + @ViewChild('fileInputLabel', { static: true }) public fileInputLabel: ElementRef; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Holds the instance of router class @private */ + private router: Router; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Contains configuration key variables @private */ + private configKeys: string[] = []; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.formBuilder = this.injector.get(FormBuilder); + this.router = this.injector.get(Router); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.sharedService = this.injector.get(SharedService); + + /** Initializing Form Action */ + this.vimNewAccountForm = this.formBuilder.group({ + name: [null, Validators.required], + vim_type: [null, Validators.required], + vim_tenant_name: [null, Validators.required], + description: [null], + vim_url: [null, [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]], + schema_type: [''], + vim_user: [null, Validators.required], + vim_password: [null, Validators.required], + vimconfig: this.paramsBuilder() + }); + } + + /** Generate params for config @public */ + public paramsBuilder(): FormGroup { + return this.formBuilder.group({ + use_existing_flavors: [null], + location: [null], + sdn_controller: [null], + APIversion: [null], + sdn_port_mapping: [null], + project_domain_id: [null], + vim_network_name: [null], + project_domain_name: [null], + config_vim_ype: [null], + user_domain_id: [null], + security_groups: [null], + user_domain_name: [null], + availabilityZone: [null], + keypair: [null], + region_name: [null], + dataplane_physical_net: [null], + insecure: [null], + use_floating_ip: [null], + microversion: [null], + use_internal_endpoint: [null], + additional_conf: [null], + orgname: [null], + vcenter_ip: [null], + vcenter_port: [null], + admin_username: [null], + vcenter_user: [null], + admin_password: [null], + vcenter_password: [null], + nsx_manager: [null], + vrops_site: [null], + nsx_user: [null], + vrops_user: [null], + nsx_password: [null], + vrops_password: [null], + vpc_cidr_block: [null], + flavor_info: [null], + subscription_id: [null], + resource_group: [null], + vnet_name: [null], + flavors_pattern: [null] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.vimNewAccountForm.controls; } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.vimType = VIM_TYPES; + this.boolValue = [ + { id: '', name: 'None' }, + { id: true, name: 'True' }, + { id: false, name: 'False' } + ]; + this.headers = new HttpHeaders({ + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** On modal submit newVimAccountSubmit will called @public */ + public newVimAccountSubmit(): void { + this.submitted = true; + if (!this.vimNewAccountForm.invalid) { + this.isLocationLoadingResults = true; + this.configKeys.forEach((key: string) => { + this.vimNewAccountForm.controls.vimconfig.get(key).setValue(JSON.parse(this.vimNewAccountForm.controls.vimconfig.get(key).value)); + }); + this.sharedService.cleanForm(this.vimNewAccountForm); + Object.keys(this.vimNewAccountForm.value.vimconfig).forEach((key: string) => { + if (this.vimNewAccountForm.value.vimconfig[key] === undefined || this.vimNewAccountForm.value.vimconfig[key] === null || + this.vimNewAccountForm.value.vimconfig[key] === '') { + delete this.vimNewAccountForm.value.vimconfig[key]; + } + }); + this.vimNewAccountForm.value.config = this.vimNewAccountForm.value.vimconfig; + delete this.vimNewAccountForm.value.vimconfig; + const apiURLHeader: APIURLHEADER = { + url: environment.VIMACCOUNTS_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, this.vimNewAccountForm.value) + .subscribe((result: {}) => { + this.notifierService.notify('success', this.translateService.instant('PAGE.VIM.CREATEDSUCCESSFULLY')); + this.isLocationLoadingResults = false; + this.router.navigate(['vim/details']).catch(() => { + // Error Cached; + }); + // Post the New Vim data and reflect in the VIM Details Page. + }, (error: ERRORDATA) => { + this.configKeys.forEach((key: string) => { + this.vimNewAccountForm.controls.vimconfig.get(key) + .setValue(JSON.stringify(this.vimNewAccountForm.controls.vimconfig.get(key).value)); + }); + this.restService.handleError(error, 'post'); + this.isLocationLoadingResults = false; + }); + } + } + + /** Routing to VIM Account Details Page @public */ + public onVimAccountBack(): void { + this.router.navigate(['vim/details']).catch(() => { + // Error Cached + }); + } + + /** Fetching the location with name,latitude,longitude @public */ + public fetchLocationLatLong(value: string): void { + this.isLocationLoadingResults = true; + const newVIMLocation: VIMLOCATIONDATA[] = []; + const locationTrack: string = environment.MAPLATLONGAPI_URL; + const locationAPIURL: string = locationTrack.replace('{value}', value); + this.restService.getResource(locationAPIURL).subscribe((result: VIMLOCATION) => { + result.features.forEach((getFeturesResult: FEATURES) => { + if ('extent' in getFeturesResult.properties) { + getFeturesResult.properties.extent.forEach((extentResult: number, index: number) => { + if (index === 0) { + this.setLong = extentResult; + } + if (index === 1) { + this.setLat = extentResult; + } + }); + } else { + getFeturesResult.geometry.coordinates.forEach((coordinateResult: number, index: number) => { + if (index === 0) { + this.setLong = coordinateResult; + } + if (index === 1) { + this.setLat = coordinateResult; + } + }); + } + newVIMLocation.push({ + label: getFeturesResult.properties.name + ',' + getFeturesResult.properties.state + ', ' + getFeturesResult.properties.country, + value: getFeturesResult.properties.name + ',' + this.setLong + ',' + this.setLat + }); + }); + this.getVIMLocation = newVIMLocation; + this.isLocationLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLocationLoadingResults = false; + }); + } + + /** Drag and drop feature and fetchind the details of files @private */ + public filesDropped(files: FileList): void { + this.configKeys = []; + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => { + const getJson: string = jsyaml.load(fileContent, { json: true }); + Object.keys(getJson).forEach((item: string) => { + if (!isNullOrUndefined(this.vimNewAccountForm.controls.vimconfig.get(item))) { + if (typeof getJson[item] === 'object') { + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.vimNewAccountForm.controls.vimconfig.get(item).setValue(JSON.stringify(getJson[item])); + this.configKeys.push(item); + } else { + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.vimNewAccountForm.controls.vimconfig.get(item).setValue(getJson[item]); + } + } + }); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInput.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputLabel.nativeElement.innerText = files[0].name; + this.fileInput.nativeElement.value = null; + } +} diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html new file mode 100644 index 0000000..7feabe2 --- /dev/null +++ b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.html @@ -0,0 +1,67 @@ + +
+
+
{{'VIMACCOUNTS' | translate}}
+
+
+
+ + +
+ + + +
+
+
+
+ +
+ + +
+
+ + +
+
+
+ + \ No newline at end of file diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss new file mode 100644 index 0000000..aeb086e --- /dev/null +++ b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.scss @@ -0,0 +1,73 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +@import '../../../assets/scss/mixins/mixin'; +@import '../../../assets/scss/variable'; +.map { + height: 60vh; + width: 100%; + .ol-popup { + @include background(null, $white, null, null, null); + -webkit-filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + filter: drop-shadow(0 1px 4px rgba(0,0,0,0.2)); + @include border(all, 1, solid, $gray-80); + @include position_value(absolute, $top: null, $right: null, $bottom: 12px, $left: -50px); + @include wh-value(280px, null); + @include font-style(normal); + @include font(null, .765625rem, 400); + @include line-height(1.5); + text-align: start; + text-decoration: none; + letter-spacing: normal; + word-break: normal; + word-spacing: normal; + white-space: normal; + line-break: auto; + word-wrap: break-word; + @include roundedCorners(2px); + &:after, &:before{ + top: 100%; + @include border(all, 1, solid, transparent); + content: " "; + height: 0; + width: 0; + position: absolute; + pointer-events: none; + } + &:after { + border-top-color: $white; + border-width: 10px; + left: 48px; + margin-left: -10px; + } + &:before { + border-top-color: $gray-80; + border-width: 11px; + left: 48px; + margin-left: -11px; + } + } + .ol-popup-closer { + text-decoration: none; + position: absolute; + top: 2px; + right: 8px; + &:after { + content: "✖"; + } + } +} \ No newline at end of file diff --git a/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts new file mode 100644 index 0000000..71455f5 --- /dev/null +++ b/src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent.ts @@ -0,0 +1,476 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Vim Account Component. + */ +import { Component, Injector, OnInit } from '@angular/core'; +import { Router } from '@angular/router'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, CONSTANTNUMBER, ERRORDATA, VIM_TYPES } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { LocalDataSource } from 'ng2-smart-table'; +import { NSInstanceDetails } from 'NSInstanceModel'; +import Feature from 'ol/Feature'; +import Point from 'ol/geom/Point'; +import { defaults as defaultInteractions } from 'ol/interaction'; +import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer'; +import Map from 'ol/Map'; +import Overlay from 'ol/Overlay'; +import { fromLonLat } from 'ol/proj.js'; +import OSM from 'ol/source/OSM'; +import VectorSource from 'ol/source/Vector'; +import { Icon, Style } from 'ol/style'; +import View from 'ol/View'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { VimAccountDetails, VIMData } from 'VimAccountModel'; +import { VimAccountsActionComponent } from 'VimAccountsAction'; +/** + * Creating component + * @Component takes VimAccountDetailsComponent.html as template url + */ +@Component({ + selector: 'app-vim-account-details', + templateUrl: './VimAccountDetailsComponent.html', + styleUrls: ['./VimAccountDetailsComponent.scss'] +}) +/** Exporting a class @exports VimAccountDetailsComponent */ +export class VimAccountDetailsComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + /** handle translate @public */ + public translateService: TranslateService; + /** initially show the map container@public */ + public showMap: boolean; + /** hide and show popup @public */ + public popupShow: boolean = false; + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + /** Columns list of the smart table @public */ + public columnLists: object = {}; + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + /** initially hide the list@private */ + public showList: boolean; + /** to store locations name @public */ + public getLocation: GetLocation[]; + /** Contains content for map popup @public */ + public popupData: string; + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + /** Class for empty and present data @public */ + public checkDataClass: string; + /** Formation of appropriate Data for LocalDatasource @public */ + public vimData: VIMData[]; + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.vimOperationalStateFirstStep; + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.vimOperationalStateStateSecondStep; + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.vimOperationalStateThirdStep; + /** NS Instances operational State failed data @public */ + public nsinstancesoperationalStateRunning: string = CONFIGCONSTANT.operationalStateSecondStep; + /** Instance of the rest service @private */ + private restService: RestService; + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + /** Holds the instance of router class @private */ + private router: Router; + /** ns INstance Data @private */ + private nsData: NSInstanceDetails[]; + /** map object @private */ + private map: Map; + /** used to bind marker @private */ + private vectorSource: VectorSource; + /** used to bind vectorSource @private */ + private vectorLayer: VectorLayer; + /** marker @private */ + private marker: Feature; + /** latitude @private */ + private lat: number; + /** longitude @private */ + private lng: number; + /** each vector layer of marker is pushed to layers array @private */ + private layers: VectorLayer[] = []; + /** locationData @private */ + private locationData: VimAccountDetails[]; + /** popup array @private */ + private overLay: Overlay[] = []; + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.router = this.injector.get(Router); + this.translateService = this.injector.get(TranslateService); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.osmMapView(); + this.listView(); + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + name: { title: this.translateService.instant('NAME'), width: '15%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '25%' }, + type: { + title: this.translateService.instant('TYPE'), width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: VIM_TYPES + } + } + }, + operationalState: { + title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: VIMData, row: VIMData): string => { + if (row.operationalState === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.operationalState}`; + } + } + }, + description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: VIMData, row: VIMData): VIMData => row, + renderComponent: VimAccountsActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', + confirmSave: true + }, + delete: { + deleteButtonContent: '', + confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, + edit: false, + delete: false, + position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'vim-account' }); + this.dataService.changeMessage(event.data); + } + + /** on Navigate to Composer Page @public */ + public composeVIM(): void { + this.router.navigate(['vim/new']).catch(() => { + //empty block + }); + } + + /** To show map conatainer @public */ + public mapView(): void { + this.showList = true; + this.showMap = false; + } + /** To show listview @public */ + public listView(): void { + this.showMap = true; + this.showList = false; + } + /** Load the datasource appropriatetype @public */ + public loadDatasource(getdata: VIMData[]): void { + if (getdata.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(getdata).then((data: boolean) => { + //empty block + }).catch(() => { + //empty block + }); + } + + /** Generate generateVIMData object from loop and return for the datasource @public */ + public generateVIMData(vimAccountData: VimAccountDetails): VIMData { + return { + name: vimAccountData.name, + identifier: vimAccountData._id, + type: vimAccountData.vim_type, + operationalState: vimAccountData._admin.operationalState, + description: vimAccountData.description, + instancesData: this.nsData + }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + private generateData(): void { + this.isLoadingResults = true; + this.vimData = []; + this.getNSData().then((): void => { + this.restService.getResource(environment.VIMACCOUNTS_URL).subscribe((vimAccountsData: VimAccountDetails[]) => { + this.locationData = vimAccountsData; + vimAccountsData.forEach((vimAccountData: VimAccountDetails) => { + const vimDataObj: VIMData = this.generateVIMData(vimAccountData); + this.vimData.push(vimDataObj); + }); + this.loadDatasource(this.vimData); + this.removeLayersOverLay(); + this.arrayOfLocation(); + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + }).catch((error: ERRORDATA): void => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } + + /** fetching the nsdata @private */ + private async getNSData(): Promise { + return new Promise((resolve: Function, reject: Function): void => { + this.nsData = []; + this.restService.getResource(environment.NSDINSTANCES_URL).subscribe((nsdInstancesData: NSInstanceDetails[]) => { + const nsRunningInstancesData: NSInstanceDetails[] = nsdInstancesData.filter((instancesData: NSInstanceDetails) => + instancesData['operational-status'] === this.nsinstancesoperationalStateRunning); + this.nsData = nsRunningInstancesData; + resolve(true); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + resolve(true); + }); + }); + } + + /** create map view @private */ + private osmMapView(): void { + this.map = new Map({ + target: 'map', + layers: [new TileLayer({ + source: new OSM() + })], + interactions: defaultInteractions({ + mouseWheelZoom: true + }), + view: new View({ + center: fromLonLat([CONSTANTNUMBER.osmapviewlong, CONSTANTNUMBER.osmapviewlat]), + zoom: 3 + }) + }); + } + + /** remove the layers and overlay @private */ + private removeLayersOverLay(): void { + this.layers.forEach((layer: VectorLayer) => { + this.map.removeLayer(layer); + }); + this.overLay.forEach((lay: Overlay) => { + this.map.removeOverlay(lay); + }); + } + + /** filter locations from vimaccounts @private */ + private arrayOfLocation(): void { + this.getLocation = []; + this.locationData.filter((item: VimAccountDetails) => { + if (item.hasOwnProperty('config')) { + if (item.config.hasOwnProperty('location')) { + this.getLocation.push({ name: item.name, location: item.config.location, id: item._id }); + } + } + }); + if (this.getLocation !== []) { + this.getLocation.filter((loc: GetLocation) => { + if (loc.location !== '') { + const getLatLong: string[] = loc.location.split(','); + this.lng = +getLatLong[CONSTANTNUMBER.splitLongitude]; + this.lat = +getLatLong[CONSTANTNUMBER.splitLatitude]; + this.addMarker(getLatLong[0], loc.id, loc.name); + } + }); + } + } + /** add markers on map @private */ + private addMarker(loc: string, id: string, name: string): void { + const container: HTMLElement = document.getElementById('popup'); + const closer: HTMLElement = document.getElementById('popup-closer'); + this.popupShow = true; + const overlay: Overlay = this.addOverlay(container); + this.marker = this.addFeature(loc, id, name); + this.setStyleMarker(); + this.setVectorSource(); + this.setVectorLayer(); + this.map.addLayer(this.vectorLayer); + this.layers.push(this.vectorLayer); + if (this.layers.length === 1) { + this.markerClickEvent(closer, overlay); + } + } + /** Create an overlay to anchor the popup to the map @private */ + private addOverlay(container: HTMLElement): Overlay { + return new Overlay({ + element: container, + autoPan: true, + autoPanAnimation: { + duration: 250 + } + }); + } + /** Return the Feature of creating a marker in the map @private */ + private addFeature(loc: string, id: string, name: string): Feature { + return new Feature({ + geometry: new Point(fromLonLat([this.lng, this.lat])), + location: loc, + Id: id, + vimName: name + }); + } + /** Set the style of the marker @private */ + private setStyleMarker(): void { + this.marker.setStyle(new Style({ + image: new Icon(({ + crossOrigin: 'anonymous', + src: 'assets/images/map-icon.png' + })) + })); + } + /** Set the map vector source @private */ + private setVectorSource(): void { + this.vectorSource = new VectorSource({ + features: [this.marker] + }); + } + /** Set the map vector layer @private */ + private setVectorLayer(): void { + this.vectorLayer = new VectorLayer({ + source: this.vectorSource + }); + } + /** Add a click handler to the map to render the popup. @private */ + private markerClickEvent(closer: HTMLElement, overlay: Overlay): void { + // tslint:disable-next-line: no-any + this.map.on('singleclick', (evt: any) => { + const feature: Feature = this.map.forEachFeatureAtPixel(evt.pixel, + (f: Feature) => { + return f; + }); + if (feature) { + this.setCoordinates(feature, overlay); + } else { + this.map.removeOverlay(overlay); + } + }); + /** Handle close event for overlay */ + closer.onclick = (): boolean => { + overlay.setPosition(undefined); + closer.blur(); + return false; + }; + } + /** Set the coordinates point if the feature is available @private */ + // tslint:disable-next-line: no-any + private setCoordinates(feature: any, overlay: Overlay): void { + this.popupData = ''; + this.popupData += '

' + feature.values_.vimName + '

'; + this.popupData += '
    '; + const instnaceData: NSInstanceDetails[] = this.nsData.filter((item: NSInstanceDetails) => { + if (item.datacenter === feature.values_.Id) { + this.popupData += '
  • ' + + item.name + '
  • '; + return item; + } + }); + if (instnaceData.length === 0) { + this.popupData += '
  • ' + this.translateService.instant('PAGE.DASHBOARD.NOINSTANCES') + '
  • '; + } + this.popupData += '
'; + const coordinates: number[] = feature.getGeometry().getCoordinates(); + overlay.setPosition(coordinates); + this.overLay.push(overlay); + this.map.addOverlay(overlay); + } +} + +/** interface for get location */ +interface GetLocation { + location: string; + id: string; + name?: string; +} diff --git a/src/app/wim-accounts/WIMAccountsComponent.html b/src/app/wim-accounts/WIMAccountsComponent.html new file mode 100644 index 0000000..3f96ff8 --- /dev/null +++ b/src/app/wim-accounts/WIMAccountsComponent.html @@ -0,0 +1,18 @@ + + \ No newline at end of file diff --git a/src/app/wim-accounts/WIMAccountsComponent.scss b/src/app/wim-accounts/WIMAccountsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/wim-accounts/WIMAccountsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/wim-accounts/WIMAccountsComponent.ts b/src/app/wim-accounts/WIMAccountsComponent.ts new file mode 100644 index 0000000..5914f30 --- /dev/null +++ b/src/app/wim-accounts/WIMAccountsComponent.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file WIM Account Component. + */ +import { Component, Injector } from '@angular/core'; +import { Router, RouterEvent } from '@angular/router'; + +/** + * Creating component + * @Component takes WIMAccountsComponent.html as template url + */ +@Component({ + templateUrl: './WIMAccountsComponent.html', + styleUrls: ['./WIMAccountsComponent.scss'] +}) +/** Exporting a class @exports WIMAccountsComponent */ +export class WIMAccountsComponent { + /** Invoke service injectors @public */ + public injector: Injector; + + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + + // creates packages component + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.router.events.subscribe((event: RouterEvent) => { + this.redirectToList(event.url); + }); + } + + /** Return to list NS Package List */ + public redirectToList(getURL: string): void { + if (getURL === '/wim') { + this.router.navigate(['/wim/details']).catch(); + } + } +} diff --git a/src/app/wim-accounts/WIMAccountsModule.ts b/src/app/wim-accounts/WIMAccountsModule.ts new file mode 100644 index 0000000..088502f --- /dev/null +++ b/src/app/wim-accounts/WIMAccountsModule.ts @@ -0,0 +1,77 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file WIM Account module. + */ +import { CommonModule } from '@angular/common'; +import { HttpClientModule } from '@angular/common/http'; +import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core'; +import { FormsModule } from '@angular/forms'; +import { ReactiveFormsModule } from '@angular/forms'; +import { RouterModule, Routes } from '@angular/router'; +import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgSelectModule } from '@ng-select/ng-select'; +import { TranslateModule } from '@ngx-translate/core'; +import { DataService } from 'DataService'; +import { LoaderModule } from 'LoaderModule'; +import { NewWIMAccountComponent } from 'NewWIMAccount'; +import { Ng2SmartTableModule } from 'ng2-smart-table'; +import { PagePerRowModule } from 'PagePerRowModule'; +import { PageReloadModule } from 'PageReloadModule'; +import { WIMAccountDetailsComponent } from 'WIMAccountDetails'; +import { WIMAccountInfoComponent } from 'WIMAccountInfo'; +import { WIMAccountsComponent } from 'WIMAccountsComponent'; + +/** To halndle project information */ +const projectInfo: {} = { title: '{project}', url: '/' }; + +/** const values for dashboard Routes */ +const routes: Routes = [ + { + path: '', + component: WIMAccountsComponent, + children: [ + { + path: 'details', + data: { + breadcrumb: [{ title: 'PAGE.DASHBOARD.DASHBOARD', url: '/' }, { title: 'PAGE.DASHBOARD.PROJECTS', url: '/projects' }, + projectInfo, { title: 'WIMACCOUNTS', url: null }] + }, + component: WIMAccountDetailsComponent + } + ] + } +]; + +/** + * Creating @NgModule component for Modules + */ +@NgModule({ + imports: [ReactiveFormsModule.withConfig({ warnOnNgModelWithFormControl: 'never' }), FormsModule, CommonModule, + HttpClientModule, NgSelectModule, Ng2SmartTableModule, TranslateModule, RouterModule.forChild(routes), NgbModule, + PagePerRowModule, LoaderModule, PageReloadModule], + declarations: [WIMAccountsComponent, WIMAccountInfoComponent, WIMAccountDetailsComponent, NewWIMAccountComponent], + providers: [DataService], + schemas: [CUSTOM_ELEMENTS_SCHEMA], + entryComponents: [WIMAccountInfoComponent, NewWIMAccountComponent] +}) +/** Exporting a class @exports WIMAccountsModule */ +export class WIMAccountsModule { + /** Variables declared to avoid state-less class */ + private wimModule: string; +} diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html new file mode 100644 index 0000000..a97107f --- /dev/null +++ b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.html @@ -0,0 +1,97 @@ + +
+ + + +
+ \ No newline at end of file diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts new file mode 100644 index 0000000..7587b58 --- /dev/null +++ b/src/app/wim-accounts/new-wim-account/NewWIMAccountComponent.ts @@ -0,0 +1,189 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file WIM Account Component. + */ +import { HttpHeaders } from '@angular/common/http'; +import { Component, ElementRef, Injector, OnInit, ViewChild } from '@angular/core'; +import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { APIURLHEADER, ERRORDATA, MODALCLOSERESPONSEDATA, TYPESECTION, WIM_TYPES } from 'CommonModel'; +import { environment } from 'environment'; +import * as jsyaml from 'js-yaml'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { isNullOrUndefined } from 'util'; + +/** + * Creating component + * @Component takes NewWIMAccountComponent.html as template url + */ +@Component({ + templateUrl: './NewWIMAccountComponent.html', + styleUrls: ['./NewWIMAccountComponent.scss'] +}) +/** Exporting a class @exports NewWIMAccountComponent */ +export class NewWIMAccountComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Setting wim types in array @public */ + public wimType: TYPESECTION[]; + + /** Set WIM Type select to empty @public */ + public wimTypeMod: string = null; + + /** New WIM account form controls using formgroup @public */ + public wimNewAccountForm: FormGroup; + + /** Form submission Add */ + public submitted: boolean = false; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = false; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Element ref for fileInputConfig @public */ + @ViewChild('fileInputConfig', { static: true }) public fileInputConfig: ElementRef; + + /** Element ref for fileInputConfig @public */ + @ViewChild('fileInputConfigLabel', { static: true }) public fileInputConfigLabel: ElementRef; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Controls the header form @private */ + private headers: HttpHeaders; + + /** FormBuilder instance added to the formBuilder @private */ + private formBuilder: FormBuilder; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.formBuilder = this.injector.get(FormBuilder); + this.notifierService = this.injector.get(NotifierService); + this.translateService = this.injector.get(TranslateService); + this.activeModal = this.injector.get(NgbActiveModal); + this.sharedService = this.injector.get(SharedService); + + /** Initializing Form Action */ + this.wimNewAccountForm = this.formBuilder.group({ + name: ['', Validators.required], + wim_type: ['', Validators.required], + wim_url: ['', [Validators.required, Validators.pattern(this.sharedService.REGX_URL_PATTERN)]], + user: ['', Validators.required], + password: ['', Validators.required], + description: [null], + config: [null] + }); + } + + /** convenience getter for easy access to form fields */ + get f(): FormGroup['controls'] { return this.wimNewAccountForm.controls; } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.wimType = WIM_TYPES; + this.headers = new HttpHeaders({ + Accept: 'application/json', + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** On modal submit newWimAccountSubmit will called @public */ + public newWimAccountSubmit(): void { + this.submitted = true; + const modalData: MODALCLOSERESPONSEDATA = { + message: 'Done' + }; + this.sharedService.cleanForm(this.wimNewAccountForm); + if (this.wimNewAccountForm.value.description === '') { + this.wimNewAccountForm.value.description = null; + } + if (isNullOrUndefined(this.wimNewAccountForm.value.config) || this.wimNewAccountForm.value.config === '') { + delete this.wimNewAccountForm.value.config; + } else { + const validJSON: boolean = this.sharedService.checkJson(this.wimNewAccountForm.value.config); + if (validJSON) { + this.wimNewAccountForm.value.config = JSON.parse(this.wimNewAccountForm.value.config); + } else { + this.notifierService.notify('error', this.translateService.instant('INVALIDCONFIG')); + return; + } + } + if (!this.wimNewAccountForm.invalid) { + this.isLoadingResults = true; + const apiURLHeader: APIURLHEADER = { + url: environment.WIMACCOUNTS_URL, + httpOptions: { headers: this.headers } + }; + this.restService.postResource(apiURLHeader, this.wimNewAccountForm.value) + .subscribe((result: {}) => { + this.activeModal.close(modalData); + this.isLoadingResults = false; + this.notifierService.notify('success', this.translateService.instant('PAGE.WIMACCOUNTS.CREATEDSUCCESSFULLY')); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'post'); + this.isLoadingResults = false; + }); + } + } + + /** Config file process @private */ + public configFile(files: FileList): void { + if (files && files.length === 1) { + this.sharedService.getFileString(files, 'yaml').then((fileContent: string): void => { + const getConfigJson: string = jsyaml.load(fileContent, { json: true }); + // tslint:disable-next-line: no-backbone-get-set-outside-model + this.wimNewAccountForm.get('config').setValue(JSON.stringify(getConfigJson)); + }).catch((err: string): void => { + if (err === 'typeError') { + this.notifierService.notify('error', this.translateService.instant('YAMLFILETYPEERRROR')); + } else { + this.notifierService.notify('error', this.translateService.instant('ERROR')); + } + this.fileInputConfigLabel.nativeElement.innerText = this.translateService.instant('CHOOSEFILE'); + this.fileInputConfig.nativeElement.value = null; + }); + } else if (files && files.length > 1) { + this.notifierService.notify('error', this.translateService.instant('DROPFILESVALIDATION')); + } + this.fileInputConfigLabel.nativeElement.innerText = files[0].name; + this.fileInputConfig.nativeElement.value = null; + } +} diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html new file mode 100644 index 0000000..2c2d839 --- /dev/null +++ b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.html @@ -0,0 +1,42 @@ + +
+
{{'WIMACCOUNTS' | translate}}
+ + + +
+
+
+ +
+ + +
+
+ + +
+ \ No newline at end of file diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts new file mode 100644 index 0000000..b1d16f7 --- /dev/null +++ b/src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent.ts @@ -0,0 +1,246 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file WIM Account Component. + */ +import { Component, Injector, OnDestroy, OnInit } from '@angular/core'; +import { NgbModal, NgbModalRef } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { CONFIGCONSTANT, ERRORDATA, MODALCLOSERESPONSEDATA, WIM_TYPES } from 'CommonModel'; +import { DataService } from 'DataService'; +import { environment } from 'environment'; +import { NewWIMAccountComponent } from 'NewWIMAccount'; +import { LocalDataSource } from 'ng2-smart-table'; +import { RestService } from 'RestService'; +import { Subscription } from 'rxjs'; +import { SharedService } from 'SharedService'; +import { WIMAccountData, WIMAccountModel } from 'WIMAccountModel'; +import { WIMAccountsActionComponent } from 'WIMAccountsAction'; +/** + * Creating component + * @Component takes WIMAccountDetailsComponent.html as template url + */ +@Component({ + templateUrl: './WIMAccountDetailsComponent.html', + styleUrls: ['./WIMAccountDetailsComponent.scss'] +}) +/** Exporting a class @exports WIMAccountDetailsComponent */ +export class WIMAccountDetailsComponent implements OnInit, OnDestroy { + /** To inject services @public */ + public injector: Injector; + + /** handle translate @public */ + public translateService: TranslateService; + + /** Data of smarttable populate through LocalDataSource @public */ + public dataSource: LocalDataSource = new LocalDataSource(); + + /** Columns list of the smart table @public */ + public columnLists: object = {}; + + /** Settings for smarttable to populate the table with columns @public */ + public settings: object = {}; + + /** Check the loading results @public */ + public isLoadingResults: boolean = true; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Class for empty and present data @public */ + public checkDataClass: string; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.wimOperationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.wimOperationalStateStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.wimOperationalStateThirdStep; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** dataService to pass the data from one component to another @private */ + private dataService: DataService; + + /** Formation of appropriate Data for LocalDatasource @private */ + private wimData: {}[] = []; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Instance of subscriptions @private */ + private generateDataSub: Subscription; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.dataService = this.injector.get(DataService); + this.sharedService = this.injector.get(SharedService); + this.translateService = this.injector.get(TranslateService); + this.modalService = this.injector.get(NgbModal); + } + /** Lifecyle Hooks the trigger before component is instantiate @public */ + public ngOnInit(): void { + this.generateColumns(); + this.generateSettings(); + this.generateData(); + this.generateDataSub = this.sharedService.dataEvent.subscribe(() => { this.generateData(); }); + } + + /** smart table Header Colums @public */ + public generateColumns(): void { + this.columnLists = { + name: { title: this.translateService.instant('NAME'), width: '20%', sortDirection: 'asc' }, + identifier: { title: this.translateService.instant('IDENTIFIER'), width: '20%' }, + type: { + title: this.translateService.instant('TYPE'), width: '15%', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: WIM_TYPES + } + } + }, + operationalState: { + title: this.translateService.instant('OPERATIONALSTATUS'), width: '15%', type: 'html', + filter: { + type: 'list', + config: { + selectText: 'Select', + list: [ + { value: this.operationalStateFirstStep, title: this.operationalStateFirstStep }, + { value: this.operationalStateSecondStep, title: this.operationalStateSecondStep }, + { value: this.operationalStateThirdStep, title: this.operationalStateThirdStep } + ] + } + }, + valuePrepareFunction: (cell: WIMAccountData, row: WIMAccountData): string => { + if (row.operationalState === this.operationalStateFirstStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateSecondStep) { + return ` + + `; + } else if (row.operationalState === this.operationalStateThirdStep) { + return ` + + `; + } else { + return `${row.operationalState}`; + } + } + }, + description: { title: this.translateService.instant('DESCRIPTION'), width: '25%' }, + Actions: { + name: 'Action', width: '5%', filter: false, sort: false, title: this.translateService.instant('ACTIONS'), type: 'custom', + valuePrepareFunction: (cell: WIMAccountData, row: WIMAccountData): WIMAccountData => row, + renderComponent: WIMAccountsActionComponent + } + }; + } + + /** smart table Data Settings @public */ + public generateSettings(): void { + this.settings = { + edit: { + editButtonContent: '', confirmSave: true + }, + delete: { + deleteButtonContent: '', confirmDelete: true + }, + columns: this.columnLists, + actions: { + add: false, edit: false, delete: false, position: 'right' + }, + attr: this.sharedService.tableClassConfig(), + pager: this.sharedService.paginationPagerConfig(), + noDataMessage: this.translateService.instant('NODATAMSG') + }; + } + + /** smart table listing manipulation @public */ + public onChange(perPageValue: number): void { + this.dataSource.setPaging(1, perPageValue, true); + } + + /** smart table listing manipulation @public */ + public onUserRowSelect(event: MessageEvent): void { + Object.assign(event.data, { page: 'wim-account' }); + this.dataService.changeMessage(event.data); + } + + /** Compose new WIM Accounts @public */ + public composeWIM(): void { + const modalRef: NgbModalRef = this.modalService.open(NewWIMAccountComponent, { backdrop: 'static' }); + modalRef.result.then((result: MODALCLOSERESPONSEDATA) => { + if (result) { + this.sharedService.callData(); + } + }).catch(); + } + + /** Generate generateWIMData object from loop and return for the datasource @public */ + public generateWIMData(wimAccountData: WIMAccountModel): WIMAccountData { + return { + name: wimAccountData.name, + identifier: wimAccountData._id, + type: wimAccountData.wim_type, + operationalState: wimAccountData._admin.operationalState, + description: wimAccountData.description + }; + } + + /** + * Lifecyle hook which get trigger on component destruction + */ + public ngOnDestroy(): void { + this.generateDataSub.unsubscribe(); + } + + /** Fetching the data from server to Load in the smarttable @protected */ + protected generateData(): void { + this.isLoadingResults = true; + this.wimData = []; + this.restService.getResource(environment.WIMACCOUNTS_URL).subscribe((wimAccountsDetails: {}[]) => { + wimAccountsDetails.forEach((wimAccountsData: WIMAccountModel) => { + const wimDataObj: WIMAccountData = this.generateWIMData(wimAccountsData); + this.wimData.push(wimDataObj); + }); + if (this.wimData.length > 0) { + this.checkDataClass = 'dataTables_present'; + } else { + this.checkDataClass = 'dataTables_empty'; + } + this.dataSource.load(this.wimData).then((data: {}) => { + this.isLoadingResults = false; + }).catch(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html new file mode 100644 index 0000000..25126b8 --- /dev/null +++ b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.html @@ -0,0 +1,84 @@ + + + + + diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss new file mode 100644 index 0000000..021d205 --- /dev/null +++ b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.scss @@ -0,0 +1,17 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ \ No newline at end of file diff --git a/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts new file mode 100644 index 0000000..1e7be9f --- /dev/null +++ b/src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent.ts @@ -0,0 +1,96 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) +*/ +/** + * @file Info WIM Page + */ +import { Component, Injector, Input, OnInit } from '@angular/core'; +import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; +import { CONFIGCONSTANT, ERRORDATA, URLPARAMS } from 'CommonModel'; +import { environment } from 'environment'; +import { RestService } from 'RestService'; +import { SharedService } from 'SharedService'; +import { WIMAccountModel } from 'WIMAccountModel'; + +/** + * Creating component + * @Component takes WIMAccountInfoComponent.html as template url + */ +@Component({ + templateUrl: './WIMAccountInfoComponent.html', + styleUrls: ['./WIMAccountInfoComponent.scss'] +}) +/** Exporting a class @exports WIMAccountInfoComponent */ +export class WIMAccountInfoComponent implements OnInit { + /** To inject services @public */ + public injector: Injector; + + /** Input contains component objects @public */ + @Input() public params: URLPARAMS; + + /** Contains WIM details @public */ + public wimDetails: WIMAccountModel; + + /** Instance for active modal service @public */ + public activeModal: NgbActiveModal; + + /** Check the loading results for loader status @public */ + public isLoadingResults: boolean = true; + + /** operational State init data @public */ + public operationalStateFirstStep: string = CONFIGCONSTANT.wimOperationalStateFirstStep; + + /** operational State running data @public */ + public operationalStateSecondStep: string = CONFIGCONSTANT.wimOperationalStateStateSecondStep; + + /** operational State failed data @public */ + public operationalStateThirdStep: string = CONFIGCONSTANT.wimOperationalStateThirdStep; + + /** Give the message for the loading @public */ + public message: string = 'PLEASEWAIT'; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.activeModal = this.injector.get(NgbActiveModal); + this.sharedService = this.injector.get(SharedService); + } + + /** + * Lifecyle Hooks the trigger before component is instantiate + */ + public ngOnInit(): void { + this.generateData(); + } + + /** Generate Data function @public */ + public generateData(): void { + this.restService.getResource(environment.WIMACCOUNTS_URL + '/' + this.params.id).subscribe((wimDetails: WIMAccountModel) => { + this.wimDetails = wimDetails; + this.isLoadingResults = false; + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'get'); + this.isLoadingResults = false; + }); + } +} diff --git a/src/assets/config/rolePermissions.json b/src/assets/config/rolePermissions.json new file mode 100644 index 0000000..7111144 --- /dev/null +++ b/src/assets/config/rolePermissions.json @@ -0,0 +1,692 @@ +{ + "rolePermissions": [ + { + "title": "Default", + "permissions": [ + { + "operation": "default", + "value": "NA" + } + ] + }, + { + "title": "Admin", + "permissions": [ + { + "operation": "admin", + "value": "NA" + }, + { + "operation": "admin:get", + "value": "NA" + }, + { + "operation": "admin:post", + "value": "NA" + }, + { + "operation": "admin:patch", + "value": "NA" + }, + { + "operation": "admin:put", + "value": "NA" + }, + { + "operation": "admin:delete", + "value": "NA" + } + ] + }, + { + "title": "NS Descriptors", + "permissions": [ + { + "operation": "nsds", + "value": "NA" + }, + { + "operation": "nsds:get", + "value": "NA" + }, + { + "operation": "nsds:post", + "value": "NA" + }, + { + "operation": "nsds:id:get", + "value": "NA" + }, + { + "operation": "nsds:id:put", + "value": "NA" + }, + { + "operation": "nsds:id:delete", + "value": "NA" + }, + { + "operation": "nsds:id:patch", + "value": "NA" + }, + { + "operation": "nsds:content:post", + "value": "NA" + }, + { + "operation": "nsds:id:content:get", + "value": "NA" + }, + { + "operation": "nsds:id:content:put", + "value": "NA" + }, + { + "operation": "nsds:id:nsd:get", + "value": "NA" + }, + { + "operation": "nsds:id:nsd_artifact:get", + "value": "NA" + } + ] + }, + { + "title": "VNF Descriptors", + "permissions": [ + { + "operation": "vnfds", + "value": "NA" + }, + { + "operation": "vnfds:post", + "value": "NA" + }, + { + "operation": "vnfds:content:post", + "value": "NA" + }, + { + "operation": "vnfds:id:get", + "value": "NA" + }, + { + "operation": "vnfds:id:put", + "value": "NA" + }, + { + "operation": "vnfds:id:delete", + "value": "NA" + }, + { + "operation": "vnfds:id:patch", + "value": "NA" + }, + { + "operation": "vnfds:id:content:get", + "value": "NA" + }, + { + "operation": "vnfds:id:content:put", + "value": "NA" + }, + { + "operation": "vnfds:id:vnfd:get", + "value": "NA" + }, + { + "operation": "vnfds:id:vnfd_artifact:get", + "value": "NA" + }, + { + "operation": "vnfds:id:action:post", + "value": "NA" + }, + { + "operation": "vnfds:vnfpkgops:get", + "value": "NA" + }, + { + "operation": "vnfds:vnfpkgops:id:get", + "value": "NA" + } + ] + }, + { + "title": "NS Instances", + "permissions": [ + { + "operation": "ns_instances", + "value": "NA" + }, + { + "operation": "ns_instances:get", + "value": "NA" + }, + { + "operation": "ns_instances:post", + "value": "NA" + }, + { + "operation": "ns_instances:content:post", + "value": "NA" + }, + { + "operation": "ns_instances:id:get", + "value": "NA" + }, + { + "operation": "ns_instances:id:delete", + "value": "NA" + }, + { + "operation": "ns_instances:id:instantiate:post", + "value": "NA" + }, + { + "operation": "ns_instances:id:terminate:post", + "value": "NA" + }, + { + "operation": "ns_instances:id:action:post", + "value": "NA" + }, + { + "operation": "ns_instances:id:scale:post", + "value": "NA" + }, + { + "operation": "ns_instances:opps:get", + "value": "NA" + }, + { + "operation": "ns_instances:opps:id:get", + "value": "NA" + } + ] + }, + { + "title": "VNF Instances", + "permissions": [ + { + "operation": "vnf_instances", + "value": "NA" + }, + { + "operation": "vnf_instances:get", + "value": "NA" + }, + { + "operation": "vnf_instances:id:get", + "value": "NA" + } + ] + }, + { + "title": "VIMs", + "permissions": [ + { + "operation": "vims", + "value": "NA" + }, + { + "operation": "vims:get", + "value": "NA" + }, + { + "operation": "vims:post", + "value": "NA" + }, + { + "operation": "vims:id:get", + "value": "NA" + }, + { + "operation": "vims:id:delete", + "value": "NA" + }, + { + "operation": "vims:id:patch", + "value": "NA" + } + ] + }, + { + "title": "VIMs Accounts", + "permissions": [ + { + "operation": "vim_accounts", + "value": "NA" + }, + { + "operation": "vim_accounts:get", + "value": "NA" + }, + { + "operation": "vim_accounts:post", + "value": "NA" + }, + { + "operation": "vim_accounts:id:get", + "value": "NA" + }, + { + "operation": "vim_accounts:id:delete", + "value": "NA" + }, + { + "operation": "vim_accounts:id:patch", + "value": "NA" + } + ] + }, + { + "title": "SDN Controllers", + "permissions": [ + { + "operation": "sdn_controllers", + "value": "NA" + }, + { + "operation": "sdn_controllers:get", + "value": "NA" + }, + { + "operation": "sdn_controllers:post", + "value": "NA" + }, + { + "operation": "sdn_controllers:id:get", + "value": "NA" + }, + { + "operation": "sdn_controllers:id:delete", + "value": "NA" + }, + { + "operation": "sdn_controllers:id:patch", + "value": "NA" + } + ] + }, + { + "title": "WIMs", + "permissions": [ + { + "operation": "wims", + "value": "NA" + }, + { + "operation": "wims:get", + "value": "NA" + }, + { + "operation": "wims:post", + "value": "NA" + }, + { + "operation": "wims:id:get", + "value": "NA" + }, + { + "operation": "wims:id:delete", + "value": "NA" + }, + { + "operation": "wims:id:patch", + "value": "NA" + } + ] + }, + { + "title": "WIMs Accounts", + "permissions": [ + { + "operation": "wim_accounts", + "value": "NA" + }, + { + "operation": "wim_accounts:get", + "value": "NA" + }, + { + "operation": "wim_accounts:post", + "value": "NA" + }, + { + "operation": "wim_accounts:id:get", + "value": "NA" + }, + { + "operation": "wim_accounts:id:delete", + "value": "NA" + }, + { + "operation": "wim_accounts:id:patch", + "value": "NA" + } + ] + }, + { + "title": "PDUDs", + "permissions": [ + { + "operation": "pduds", + "value": "NA" + }, + { + "operation": "pduds:get", + "value": "NA" + }, + { + "operation": "pduds:post", + "value": "NA" + }, + { + "operation": "pduds:put", + "value": "NA" + }, + { + "operation": "pduds:delete", + "value": "NA" + }, + { + "operation": "pduds:patch", + "value": "NA" + }, + { + "operation": "pduds:id:get", + "value": "NA" + }, + { + "operation": "pduds:id:post", + "value": "NA" + }, + { + "operation": "pduds:id:put", + "value": "NA" + }, + { + "operation": "pduds:id:delete", + "value": "NA" + }, + { + "operation": "pduds:id:patch", + "value": "NA" + } + ] + }, + { + "title": "Network Slice Templates", + "permissions": [ + { + "operation": "slice_templates", + "value": "NA" + }, + { + "operation": "slice_templates:get", + "value": "NA" + }, + { + "operation": "slice_templates:content:post", + "value": "NA" + }, + { + "operation": "slice_templates:id:get", + "value": "NA" + }, + { + "operation": "slice_templates:id:put", + "value": "NA" + }, + { + "operation": "slice_templates:id:delete", + "value": "NA" + }, + { + "operation": "slice_templates:id:patch", + "value": "NA" + }, + { + "operation": "slice_templates:content:get", + "value": "NA" + }, + { + "operation": "slice_templates:content:put", + "value": "NA" + }, + { + "operation": "slice_templates:id:nst:get", + "value": "NA" + }, + { + "operation": "slice_templates:id:nst_artifact:get", + "value": "NA" + } + ] + }, + { + "title": "Network Slice Instances", + "permissions": [ + { + "operation": "slice_instances", + "value": "NA" + }, + { + "operation": "slice_instances:get", + "value": "NA" + }, + { + "operation": "slice_instances:content:post", + "value": "NA" + }, + { + "operation": "slice_instances:id:get", + "value": "NA" + }, + { + "operation": "slice_instances:id:delete", + "value": "NA" + }, + { + "operation": "slice_instances:post", + "value": "NA" + }, + { + "operation": "slice_instances:id:instantiate:post", + "value": "NA" + }, + { + "operation": "slice_instances:id:terminate:post", + "value": "NA" + }, + { + "operation": "slice_instances:id:action:post", + "value": "NA" + }, + { + "operation": "slice_instances:opps:get", + "value": "NA" + }, + { + "operation": "slice_instances:opps:id:get", + "value": "NA" + } + ] + }, + { + "title": "K8 Clusters", + "permissions": [ + { + "operation": "k8sclusters", + "value": "NA" + }, + { + "operation": "k8sclusters:get", + "value": "NA" + }, + { + "operation": "k8sclusters:post", + "value": "NA" + }, + { + "operation": "k8sclusters:id:get", + "value": "NA" + }, + { + "operation": "k8sclusters:id:delete", + "value": "NA" + }, + { + "operation": "k8sclusters:id:patch", + "value": "NA" + } + ] + }, + { + "title": "K8 Repos", + "permissions": [ + { + "operation": "k8srepos", + "value": "NA" + }, + { + "operation": "k8srepos:get", + "value": "NA" + }, + { + "operation": "k8srepos:post", + "value": "NA" + }, + { + "operation": "k8srepos:id:get", + "value": "NA" + }, + { + "operation": "k8srepos:id:delete", + "value": "NA" + } + ] + }, + { + "title": "Users", + "permissions": [ + { + "operation": "users", + "value": "NA" + }, + { + "operation": "users:get", + "value": "NA" + }, + { + "operation": "users:post", + "value": "NA" + }, + { + "operation": "users:id:get", + "value": "NA" + }, + { + "operation": "users:id:delete", + "value": "NA" + }, + { + "operation": "users:id:patch", + "value": "NA" + }, + { + "operation": "domains:get", + "value": "NA" + } + ] + }, + { + "title": "Projects", + "permissions": [ + { + "operation": "projects", + "value": "NA" + }, + { + "operation": "projects:get", + "value": "NA" + }, + { + "operation": "projects:post", + "value": "NA" + }, + { + "operation": "projects:id:get", + "value": "NA" + }, + { + "operation": "projects:id:patch", + "value": "NA" + }, + { + "operation": "projects:id:delete", + "value": "NA" + } + ] + }, + { + "title": "Roles", + "permissions": [ + { + "operation": "roles", + "value": "NA" + }, + { + "operation": "roles:get", + "value": "NA" + }, + { + "operation": "roles:post", + "value": "NA" + }, + { + "operation": "roles:id:get", + "value": "NA" + }, + { + "operation": "roles:id:delete", + "value": "NA" + }, + { + "operation": "roles:id:patch", + "value": "NA" + } + ] + }, + { + "title": "Tokens", + "permissions": [ + { + "operation": "tokens", + "value": "NA" + }, + { + "operation": "tokens:get", + "value": "NA" + }, + { + "operation": "tokens:post", + "value": "NA" + }, + { + "operation": "tokens:delete", + "value": "NA" + }, + { + "operation": "tokens:id:get", + "value": "NA" + }, + { + "operation": "tokens:id:delete", + "value": "NA" + } + ] + } + ] +} \ No newline at end of file diff --git a/src/assets/i18n/de.json b/src/assets/i18n/de.json new file mode 100644 index 0000000..6c80bf8 --- /dev/null +++ b/src/assets/i18n/de.json @@ -0,0 +1,479 @@ +{ + "OSM": "OSM", + "APPVERSION": "App Version", + "OSMVERSION": "OSM Version", + "OSMSOURCEMANO": "Open Source MANO", + "ADMIN": "Admin", + "ENTRIES": "Einträge", + "COMPOSE": "Komponieren a", + "CREATE": "Erstellen", + "SELECT": "Wählen", + "CANCEL": "Stornieren", + "SAVE": "speichern", + "COUNT": "Anzahl", + "IMAGE": "Bild", + "IPPROFILEREF": "IP-Profil Ref", + "ACTION": "Aktion", + "ADD": "Hinzufügen", + "EDIT": "Bearbeiten", + "APPLY": "Sich bewerben", + "FORCE": "Macht", + "DOWNLOAD": "Herunterladen", + "CONTENT": "Inhalt", + "DELETE": "Löschen", + "FORCEDELETE": "Löschen erzwingen", + "RENAME": "Umbenennen", + "INFO": "Info", + "NSPACKAGES": "NS Pakete", + "VNFPACKAGES": "VNF Pakete", + "INSTANCES": "Instanzen", + "INSTANTIATE": "Instanziieren", + "NSINSTANCES": "NS Instanzen", + "VNFINSTANCES": "VNF Instanzen", + "PDUINSTANCES": "PDU Instanzen", + "VIMACCOUNTS": "VIM Konten", + "WIMACCOUNTS": "WIM-Konten", + "SDNCONTROLLER": "SDN Reglerin", + "NETSLICE": "Netslice", + "PROJECT": "Projekt", + "DOMAIN": "Domain", + "PACKAGES": "Pakete", + "MODIFIED": "Geändert", + "NODATAMSG": "Keine Daten in der Tabelle verfügbar", + "SHORTNAME": "Kurzer Name", + "IDENTIFIER": "Kennung", + "DESCRIPTION": "Beschreibung", + "VENDOR": "Verkäuferin", + "VERSION": "Ausführung", + "ACTIONS": "Aktionen", + "NAME": "Name", + "USAGESTATE": "Nutzungsstatus", + "MODIFICATIONDATE": "Änderungsdatum", + "CREATEDDATE": "Erstellungsdatum", + "OPERATIONALSTATUS": "Betriebs Status", + "OPERATIONALSTATE": "Betriebszustand", + "CONFIGSTATUS": "Konfigurations Status", + "DETAILEDSTATUS": "Detaillierter Status", + "NSDNAME": "Nsd name", + "NSTNAME": "Nst name", + "TYPE": "Art", + "VNFD": "VNFD", + "VNF": "VNF", + "MEMBERINDEX": "Mitglieds Index", + "NS": "NS", + "CREATEDAT": "Hergestellt in", + "CREATED": "Erstellt", + "ALL": "Alle", + "ID": "Id", + "OPERATIONSTATE": "Betriebszustand", + "STARTTIME": "Startzeit", + "STATUSENTEREDTIME": "Status Eingegebene Zeit", + "HISTORYOFOPERATIONS": "Geschichte der Operationen", + "UPDATE": "Aktualisieren", + "READONLYMODE": "Nur-Lese-Modus", + "CURRENTLY": "Zur Zeit", + "ON": "Auf", + "OFF": "aus", + "IN": "im", + "FILES": "Dateien", + "NEW": "Neu", + "RECENTLY": "Vor kurzem", + "TOPOLOGY": "Topologie", + "PLEASEWAIT": "Warten Sie mal", + "LOADING": "Wird geladen", + "RESOURCEORCHESTRATOR": "Ressource Orchestrator", + "VIEW": "Aussicht", + "DROP": "Fallen", + "HERE": "Here", + "MAPVIEW": "Kartenansicht", + "LISTVIEW": "Listenansicht", + "OK": "Okay", + "DELETEDSUCCESSFULLY": "Erfolgreich gelöscht", + "SESSIONEXPIRY": "Sitzung abgelaufen, bitte erneut anmelden", + "DELETECONFIRMPOPUPMESSAGE": "Möchten Sie wirklich löschen?", + "DELETELOADERMESSAGE": "Bitte warten Sie, während der Löschvorgang ausgeführt wird", + "VALUE": "Wert", + "PERFORMACTION": "Aktion ausführen", + "EXECUTE": "Execute", + "EXECNSPRIMITIVE": "Exec NS Primitive", + "PRIMITIVETYPE": "Primitiver Typ", + "VNFPRIMITIVE": "VNF Level Primitive", + "NSPRIMITIVE": "NS Level Primitive", + "DESCRIPTOR": "Deskriptor", + "ERROR": "Etwas ist schief gelaufen. Bitte versuche es erneut", + "SHOWGRAPH": "Grafik anzeigen", + "UPDATESHOWGRAPH": "Grafik aktualisieren und anzeigen", + "CREATEPACKAGE": "Neues Paket erstellen", + "GZFILETYPEERRROR": "Laden Sie nur eine tar.gz-Datei hoch und die Größe sollte 15 MB nicht überschreiten", + "YAMLFILETYPEERRROR": "Laden Sie nur YAML-Dateien hoch und die Größe sollte 15 MB nicht überschreiten", + "JSONFILETYPEERRROR": "Laden Sie nur JSON-Dateien hoch und die Größe sollte 15 MB nicht überschreiten", + "PUBFILETYPEERRROR": "Laden Sie nur PUB-Dateien hoch und die Größe sollte 15 MB nicht überschreiten", + "PACKAGE": "Paket", + "URL": "URL", + "DEPLOYED": "Bereitgestellt", + "ROLES": "Rollen", + "INSTANCEDETAILS": "Instanzdetails", + "IPADDRESS": "IP Adresse", + "MGMT": "Mgmt", + "NETNAME": "Netzname", + "USER": "Benutzerin", + "PORT": "Hafen", + "USERNAME": "Nutzername", + "PASSWORD": "Passwort", + "NODATAERROR": "Beim Abrufen der Informationen ist ein Fehler aufgetreten", + "FREEZE": "Bevriezen", + "UNFREEZE": "Auftauen", + "CLONE": "Klon", + "CLONECONFIRMPOPUPMESSAGE": "Möchten Sie wirklich klonen", + "CLONESUCCESSFULLY": "Paket erfolgreich geklont", + "DROPFILES": "Ziehen Sie die Dateien einfach hierher oder klicken Sie hier, um sie hochzuladen", + "DROPFILESVALIDATION": "Bitte wählen Sie eine zu verarbeitende Datei aus", + "METRICS": "Metriken", + "NOOFHOURS": "Anzahl der Stunden", + "MANDATORYCHECK": "Verplichte velden zijn gemarkeerd met een sterretje (*)", + "K8VERSION": "K8-versie", + "ENTER": "Eingeben", + "SWITCHPROJECT": "Projekt wechseln", + "CURRENTPROJECT": "Derzeitiges Projekt", + "SUBMIT": "Submit", + "REFRESH": "Aktualisierung", + "OPEN": "Öffnen", + "UPLOADCONFIG": "Upload Config", + "FILEUPLOADLABEL": "Oder aus Datei laden", + "CONFIG": "Konfig", + "YAMLCONFIG": "Yaml Konfig", + "CHOOSEFILE": "Datei wählen", + "INVALIDCONFIG": "Ungültige Konfiguration", + "PAGE": { + "DASHBOARD": { + "DASHBOARD": "Instrumententafel", + "RECENTUSERLOG": "Letztes Benutzerprotokoll", + "LOGS": "Protokolle", + "FAILEDINSTANCES": "Fehlgeschlagene Instanzen", + "NOINSTANCES": "Keine Instanzen verfügbar", + "UPTIME": "Betriebszeit", + "RUNNINGINSTANCES": "Laufende Instanzen", + "NETSLICETEMPLATE": "NetSlice Vorlage", + "NETSLICEINSTANCE": "NetSlice Instanzen", + "USERS": "Benutzer", + "PROJECTS": "Projekte", + "USERSETTINGS": "Benutzereinstellungen", + "LOGOUT": "Ausloggen" + }, + "LOGIN": { + "USERNAME": "Nutzername", + "PASSWORD": "Passwort", + "SIGNUP": "Anmelden", + "ACCOUNTCREATEMESSAGE": "Sie haben noch keinen Account?", + "LOGIN": "Anmeldung", + "PASSWORDVALIDMESSAGE": "Passwort wird benötigt", + "USERNAMEVALIDMESSAGE": "Ein Benutzername wird benötigt", + "SIGNINMSG": "Melden Sie sich an, um Ihre Sitzung zu starten", + "PASSWORDMINLENGTHVALIDMESSAGE": "Das Passwort muss aus 8 Zeichen bestehen und mindestens ein Groß-, Klein-, Ziffern- und Sonderzeichen enthalten", + "USERNAMEMINLENGTHVALIDMESSAGE": "Der Benutzername muss aus mindestens 5 Zeichen bestehen" + }, + "INSTANCEINSTANTIATE": { + "NEWINSTANCE": "Neue Instanz", + "NSNAME": "Ns Name", + "DESCRIPTION": "Beschrijving", + "NSID": "Nsd Id", + "SSHKEY": "SSH-Schlüssel", + "VIMACCOUNT": "VIM-Konto", + "SSHKEYMSG": "Fügen Sie hier Ihren Schlüssel ein" + }, + "NSMETRIC": { + "INSTANCESMETRIC": "Instanzmetrik", + "METRICERROR": "Daten in Metriken nicht verfügbar" + }, + "USERSETTINGS": { + "LANGUAGE": "Sprache" + }, + "VIM": { + "CREATEDSUCCESSFULLY": "VIM erfolgreich erstellt", + "LOACTIONINFO": "Geben Sie den Standortnamen ein und klicken Sie auf die Eingabetaste, um den Standort aus der Liste auszuwählen" + }, + "VIMDETAILS": { + "NEWVIM": "Nieuwe VIM", + "VIMACCOUNTDETAILS": "VIM-Kontodetails", + "NAME": "Name", + "VIMUSERNAME": "VIM-Benutzername", + "VIMURL": "VIM-URL", + "VIMTYPE": "Art", + "TENANTNAME": "Name des Mieters", + "DESCRIPTION": "Beschreibung", + "SCHEMATYPE": "Schematyp", + "SCHEMAVERSION": "Schema-Version", + "CONFIGPARAMETERS": "KONFIG-PARAMETER", + "SDNCONTROLLER": "SDN-Controller", + "SDNPORTMAPPING": "SDN-Port-Zuordnung", + "VIMNETWORKNAME": "VIM-Netzwerkname", + "SECURITYGROUPS": "Sicherheitsgruppen", + "AVAILABILITYZONE": "Verfügbarkeitszone", + "REGIONALNAME": "Name der Region", + "INSECURE": "Unsicher", + "USEEXISTINGFLAVOURS": "Verwenden Sie vorhandene Aromen", + "USEINTERNALENDPOINT": "Verwenden Sie den internen Endpunkt", + "APIVERSION": "API-Version", + "PROJECTDOMAINID": "Projektdomänen-ID", + "PROJECTDOMAINNAME": "Projektdomänenname", + "USERDOMAINID": "Benutzer-Domain-ID", + "USERDOMAINUSER": "Benutzer-Domainname", + "KEYPAIR": "Schlüsselpaar", + "DATAPLANEPHYSICALNET": "Dataplane physikalisches Netz", + "USEFLOATINGIP": "Verwenden Sie Floating IP", + "DATAPLANENETVLANRANGE": "Dataplane Net VLAN-Bereich", + "MICROVERSION": "Mikroversion", + "BACKTOVIMACCOUNTS": "Zurück zu VimAccounts", + "VIMPASSWORD": "VIM-Passwort", + "ADDITIONALCONFIG": "Zusätzliche Konfiguration", + "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}", + "NEWVIMACCOUNT": "Neues VIM-Konto", + "ORGNAME": "Orgname", + "VCENTERIP": "Vcenter ip", + "VCENTERPORT": "Vcenter-Anschluss", + "ADMINUSERNAME": "Admin-Benutzername", + "VCENTERUSER": "Vcenter-Benutzer", + "ADMINPASSWORD": "Administrator-Passwort", + "VCENTERPASSWORD": "Vcenter Passwort", + "NSXMANAGER": "Nsx Manager", + "VROPSSITE": "Vrops Seite", + "NSXUSER": "Nsx Benutzer", + "VROPSUSER": "Vrops Benutzer", + "NSXPASSWORD": "Nsx Passwort", + "VROPSPASSWORD": "Vrops Passwort", + "VPCCIDRBLOCK": "VPC-CIDR-Block", + "FLAVORIINFO": "Geschmacksinfo", + "VIM_TYPE": "VIM-Typ", + "VIMLOCATION": "VIM-Speicherort", + "SUBSCRIPTIONID": "Abonnement-ID", + "RESOURCEGROUP": "Ressourcengruppe", + "VNETNAME": "VNet Name", + "FLAVORSPATTERN": "Geschmacksmuster" + }, + "WIMACCOUNTS": { + "CREATEDSUCCESSFULLY": "WIM erfolgreich erstellt", + "WIMDETAILS": "WIM-Details", + "NEWWIM": "Neuer WIM", + "SCHEMAVERSION": "Schema-Version", + "RO": "RO", + "ROACCOUNT": "RO-Konto", + "USERNAME": "WIM-Benutzername", + "PASSWORD": "WIM-Passwort" + }, + "NSINSTANCE": { + "NEWNSINSTANCE": "Nieuwe NS", + "CREATEDSUCCESSFULLY": "NS-Instanz erfolgreich erstellt" + }, + "VNFINSTANCE": { + "ADDVNFINSTANCE": "VNF-Instanz hinzufügen" + }, + "PDUINSTANCE": { + "NEWPDUINSTANCE": "Nieuwe PDU", + "PDUTYPE": "PDU-Typ", + "PARAMETERS": "PDU-Instanzparameter", + "ADDINSTANCEPARAMS": "Instanzparameter hinzufügen", + "CREATEDSUCCESSFULLY": "PDU-Instanzen erfolgreich erstellt" + }, + "NETSLICEINSTANCE": { + "CREATENETSLICEINSTANCE": "Maak NSI" + }, + "SDNCONTROLLER": { + "NEWSDNCONTROLLER": "Nieuwe SDN-controller", + "REGISTEREDSDNCONTROLLER": "Registrierte SDN Controller", + "RO": "RO", + "DPID": "DPID", + "CREATEDSUCCESSFULLY": "SDN erfolgreich registriert", + "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx", + "DETAILS": "SDN-Controller-Details" + }, + "USERS": { + "CREATEUSER": "Gebruiker aanmaken", + "NEWUSER": "Neuer Benutzer", + "USERNAME": "Nutzername", + "PASSWORD": "Passwort", + "CONFPASSWORD": "Passwort bestätigen", + "EDITUSER": "Benutzer bearbeiten", + "NEWPASSWORD": "Neues Kennwort", + "DEFAULTPROJECT": "Standardprojekt", + "PASSWORDCONFLICT": "Passwort und Passwort bestätigen stimmen nicht überein", + "PASSWORDMATCH": "Passwort-Übereinstimmung", + "CREATEDSUCCESSFULLY": "Benutzer erfolgreich erstellt", + "EDITEDSUCCESSFULLY": "Benutzer erfolgreich bearbeiten", + "EDITCREDENTIALS": "Passwort ändern", + "EDITUSERNAME": "Benutzernamen ändern", + "PROJECTSROLES": "Projekte Rollen", + "EDITPROJECTROLEMAPPING": "Projektrollenzuordnung bearbeiten", + "ADDMAPPINGS": "Mappings hinzufügen", + "EDITPROJECTROLEERROR": "Bitte geben Sie mindestens eine Projektrollenzuordnung an, um fortzufahren" + }, + "TOPOLOGY": { + "SELECTELEMENT": "Element auswählen", + "VL": "VL", + "VNF": "VNF", + "VNFD": "VNFD", + "CP": "CP", + "NSD": "NSD", + "NS": "NS", + "VIRTUALLINK": "Virtueller Link", + "CONNECTIONPOINT": "Verbindungspunkt", + "INTCONNECTIONPOINT": "Int Verbindungspunkt", + "LINK": "Verknüpfung", + "ADDINGCP": "Bitte wählen Sie einen Verbindungspunkt von {{vnfdname}}, um {{vlname}} zu verknüpfen?", + "INFO": "Info", + "HELP": "Hilfe", + "HELPINFO": { + "CREATEEDGE": "Kante erstellen", + "CREATEEDGEFIRSTSETENCE": "Wählen Sie den ersten Scheitelpunkt aus, indem Sie mit darauf klicken", + "CREATEEDGESECONDSETENCE": "auf einem anderen Scheitelpunkt (anders als der ausgewählte).", + "DELETEEDGEVERTEX": "Kante / Scheitelpunkt löschen", + "DELETEEDGEVERTEXSENTENCE": "Doppelklicken Sie auf Kante / Scheitelpunkt.", + "SPREADEDGE": "Kante spreizen", + "SPREADEDGESENTENCE": "Wählen Sie den Scheitelpunkt aus, indem Sie mit darauf klicken", + "EDGEINFO": "Kanteninformationen anzeigen", + "EDGEINFOSENTENCE": "Wählen Sie die Kante durch Klicken aus. Die Informationen werden auf der linken Seite angezeigt." + }, + "VDU": "VDU", + "INTVL": "IntVL", + "INTCP": "IntCP", + "DATAEMPTY": "Bitte ändere etwas" + }, + "PROJECT": { + "NEWPROJECT": "Nieuw project", + "CREATEDSUCCESSFULLY": "Projekt erfolgreich erstellt", + "UPDATEDSUCCESSFULLY": "Projekt erfolgreich aktualisiert" + }, + "NSPACKAGE": { + "ADDNSPACKAGE": "Verfassen Sie eine neue NS", + "CREATEDSUCCESSFULLY": "NS-Paket erfolgreich erstellt", + "NSCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated", + "CONFIRMCONNECTIONPOINT": "Bitte bestätigen Sie, um den Verbindungspunkt hinzuzufügen", + "CANNOTLINKVNF": "Sie können einen VNF nicht mit einem VNF verknüpfen", + "CANNOTLINKVL": "Sie können eine VL nicht mit einer VL verknüpfen", + "CANNOTLINKVLVNF": "Sie können eine VL nicht mit einer VNF verknüpfen", + "CANNOTLINKVNFCP": "Sie können einen VNF nicht mit einem CP verknüpfen", + "CANNOTLINKVLCP": "Sie können eine VL nicht mit einem CP verknüpfen", + "CANNOTLINKCP": "Sie können einen CP nicht mit einem CP verknüpfen", + "ADDNSD": "Virtueller Link wurde erfolgreich hinzugefügt", + "ADDVNFD": "VNFD wurde erfolgreich hinzugefügt", + "ADDNS": "Der Verbindungslink wurde erfolgreich hinzugefügt", + "DELETENSD": "Der virtuelle Link wurde erfolgreich gelöscht", + "DELETEVNFD": "VNF erfolgreich gelöscht", + "DELETENS": "Der Verbindungspunkt wurde erfolgreich gelöscht", + "DELETELINK": "Der Link wurde erfolgreich gelöscht", + "MGMTNETWORK": "Mgmt Network", + "VIMNETWORKNAME": "Vim Network Name", + "MEMBER-VNF-INDEX": "member-vnf-index", + "VNFD-ID-REF": "vnfd-id-ref", + "VLD-ID": "vld-id", + "VNFD-CP-REF": "vnfd-Verbindungspunkt-ref" + }, + "EDITPACKAGES": { + "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated" + } + }, + "VNFPACKAGE": { + "ADDVNFPACKAGE": "Erstellen Sie eine neue VNF", + "CREATEDSUCCESSFULLY": "VNF-Paket erfolgreich erstellt", + "VNFCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Erfolgreich geupdated", + "INVALIDSELECTION": "Ungültige Auswahl", + "YOUCANNOTDELETELINK": "Sie können den Link nicht löschen", + "CANNOTLINKVDUANDINTCP": "Sie können vdu nicht mit int_cp verknüpfen", + "CANNOTLINKINTCPANDVDU": "Sie können int_cp nicht mit vdu verknüpfen", + "CANNOTLINKCPANDVNFVL": "Sie können cp nicht mit vnf_vl verknüpfen", + "CANNOTLINKVNFVLANDCP": "Sie können vnf_vl nicht mit cp verknüpfen", + "CANNOTLINKINTCPANDCP": "Sie können intcp nicht mit cp verknüpfen", + "CANNOTLINKCPANDINTCP": "Sie können cp nicht mit int_cp verknüpfen", + "CANNOTLINKVDUANDVDU": "Sie können ein vdu nicht mit einem vdu verknüpfen" + } + }, + "NETSLICE": { + "CREATEDSUCCESSFULLY": "Netslice erfolgreich erstellt", + "TEMPLATECREATEDSUCCESSFULLY": "Netslice-Vorlage erfolgreich erstellt", + "UPDATEDSUCCESSFULLY": "Vorlage erfolgreich aktualisiert" + }, + "NETSLICETEMPLATE": { + "NETSLICETEMPLATEDETAILS": "Netzwerk-Slices-Vorlagendetails" + }, + "NSTINSTANCEINSTANTIATE": { + "NEWINSTANCE": "Neue Instanz", + "NSNAME": "Ns Name", + "DESCRIPTION": "Beschrijving", + "NSTID": "Nst Id", + "SSHKEY": "SSH-Schlüssel", + "VIMACCOUNT": "VIM-Konto", + "SSHKEYMSG": "Fügen Sie Ihren Schlüssel hier ein ..." + }, + "NSPRIMITIVE": { + "PRIMITIVE": "Primitive", + "PRIMITIVEPARAMETERS": "Primitive Parameter", + "ADDPRIMITIVEPARAMS": "Primitive Parameter hinzufügen", + "EXECUTEDSUCCESSFULLY": "NS Primitive Configuration ausgeführt" + }, + "ROLES": { + "CREATEROLE": "Rolle erstellen", + "ROLE": "Rolle", + "PERMISSIONS": "Berechtigungen", + "YAMLPERMISSIONS": "YAML Berechtigungen", + "CREATEDSUCCESSFULLY": "Rolle erfolgreich erstellt", + "UPDATEDSUCCESSFULLY": "Rolle erfolgreich aktualisiert", + "ROLEJSONERROR": "Rollenberechtigungen sollten in einer Schlüsselwertweise bereitgestellt werden", + "ROLEKEYERROR": "Der Wert von '{{roleKey}}' in Rollenberechtigungen sollte boolesch sein", + "EDITROLE": "Rolle bearbeiten", + "PREVIEW": "Vorschau", + "TEXTVIEW": "Textvorschau" + }, + "K8S": { + "MENUK8S": "K8s", + "MENUK8SCLUSTER": "K8s Clusters", + "MENUK8SREPO": "K8s Repos", + "REGISTERK8CLUSTER": "Geregistreerde K8s-clusters", + "ADDK8CLUSTER": "K8s-cluster toevoegen", + "K8SCLUSTERDETAILS": "K8s Clusterdetails", + "REGISTERK8REPO": "Geregistreerde K8s-repository", + "ADDK8REPO": "K8s Repository toevoegen", + "K8SREPODETAILS": "K8s Repository Details", + "CREATEDSUCCESSFULLY": "K8s met succes gemaakt", + "NEWK8SCLUSTER": "Nieuw K8s-cluster", + "NAME": "Naam", + "K8SVERSION": "K8s-versie", + "VIMACCOUNT": "Vim-account", + "DESCRIPTION": "Beschrijving", + "NETS": "Nets", + "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}", + "CREDENTIALS": "Inloggegevens", + "NEWK8SREPO": "Nieuwe K8s Repository", + "TYPE": "Type", + "URL": "URL" + } + }, + "HTTPERROR": { + "401": "Zugriff verweigert", + "400": "Bitte überprüfen Sie die Anfrage und versuchen Sie es erneut", + "404": "Erwarteter Dienst nicht verfügbar. Bitte versuchen Sie es später erneut.", + "500": "Serverfehler, Bitte versuchen Sie es später noch einmal", + "502": "Slechte gateway, probeer het later opnieuw", + "503": "Dienst vorübergehend nicht verfügbar. Bitte versuchen Sie es später erneut.", + "504": "Gateway timeout fehler. Bitte versuchen Sie es später erneut", + "409": "Bitte versuchen Sie es später noch einmal." + }, + "PAGENOTFOUND": { + "OOPS": "Hoppla!", + "NOTFOUND": "404 Nicht gefunden", + "CONTENT": "Die Seite kann nicht gefunden oder nicht autorisiert werden, ist möglicherweise nicht mehr relevant oder hat ihren Namen geändert", + "MEAN": "In der Zwischenzeit können Sie zu zurückkehren", + "HOME": "Zuhause" + }, + "DOMVALIDATIONS": { + "INVALIDURL": "Geben Sie eine gültige URL ein", + "INVALIDIPADDRESS": "Geben Sie eine gültige IP-Adresse ein", + "INVALIDPORTADDRESS": "Geben Sie eine gültige PORT-Adresse ein", + "INVALIDDPID": "Geben Sie eine gültige DPID ein", + "INVALIDJSON": "Geben Sie ein gültiges JSON-Format ein", + "INVALIDYAML": "Geben Sie ein gültiges YAML-Format ein" + }, + "GRAFANA": { + "METRICSERROR": "Keine gültigen Metriken" + } +} \ No newline at end of file diff --git a/src/assets/i18n/en.json b/src/assets/i18n/en.json new file mode 100644 index 0000000..d22cbae --- /dev/null +++ b/src/assets/i18n/en.json @@ -0,0 +1,479 @@ +{ + "OSM": "OSM", + "APPVERSION": "App Version", + "OSMVERSION": "OSM Version", + "OSMSOURCEMANO": "Open Source MANO", + "ADMIN": "Admin", + "ENTRIES": "Entries", + "COMPOSE": "Compose a", + "CREATE": "Create", + "SELECT": "Select", + "CANCEL": "Cancel", + "SAVE": "Save", + "ACTION": "Action", + "COUNT": "Count", + "IMAGE": "Image", + "IPPROFILEREF": "IP Profile Ref", + "ADD": "Add", + "EDIT": "Edit", + "APPLY": "Apply", + "FORCE": "Force", + "DOWNLOAD": "Download", + "CONTENT": "Content", + "DELETE": "Delete", + "FORCEDELETE": "Force Delete", + "RENAME": "Rename", + "INFO": "Info", + "NSPACKAGES": "NS Packages", + "VNFPACKAGES": "VNF Packages", + "INSTANCES": "Instances", + "INSTANTIATE": "Instantiate", + "NSINSTANCES": "NS Instances", + "VNFINSTANCES": "VNF Instances", + "PDUINSTANCES": "PDU Instances", + "VIMACCOUNTS": "VIM Accounts", + "WIMACCOUNTS": "WIM Accounts", + "SDNCONTROLLER": "SDN Controller", + "NETSLICE": "Netslice", + "PROJECT": "Project", + "DOMAIN": "Domain", + "PACKAGES": "Packages", + "MODIFIED": "Modified", + "NODATAMSG": "No data available in table", + "SHORTNAME": "Short Name", + "IDENTIFIER": "Identifier", + "DESCRIPTION": "Description", + "VENDOR": "Vendor", + "VERSION": "Version", + "ACTIONS": "Actions", + "NAME": "Name", + "USAGESTATE": "UsageState", + "MODIFICATIONDATE": "Modification Date", + "CREATEDDATE": "Creation Date", + "OPERATIONALSTATUS": "Operational Status", + "OPERATIONALSTATE": "Operational State", + "CONFIGSTATUS": "Config Status", + "DETAILEDSTATUS": "Detailed Status", + "NSDNAME": "Nsd name", + "NSTNAME": "Nst name", + "TYPE": "Type", + "VNFD": "VNFD", + "VNF": "VNF", + "MEMBERINDEX": "Member Index", + "NS": "NS", + "CREATEDAT": "Created At", + "CREATED": "Created", + "ALL": "All", + "ID": "Id", + "OPERATIONSTATE": "Operation State", + "STARTTIME": "Start Time", + "STATUSENTEREDTIME": "Status Entered Time", + "HISTORYOFOPERATIONS": "History Of Operations", + "UPDATE": "Update", + "READONLYMODE": "Read only mode", + "CURRENTLY": "Currently", + "ON": "On", + "OFF": "Off", + "IN": "in", + "FILES": "Files", + "NEW": "New", + "RECENTLY": "Recently", + "TOPOLOGY": "Topology", + "PLEASEWAIT": "Please Wait", + "LOADING": "Loading", + "RESOURCEORCHESTRATOR": "Resource Orchestrator", + "VIEW": "View", + "DROP": "Drop", + "HERE": "Here", + "MAPVIEW": "Map View", + "LISTVIEW": "List View", + "OK": "Ok", + "DELETEDSUCCESSFULLY": "{{title}} deleted successfully", + "SESSIONEXPIRY": "Session expired, please login again", + "DELETECONFIRMPOPUPMESSAGE": "Are you sure want to delete", + "DELETELOADERMESSAGE": "Please wait while {{title}} deletion is in progress", + "VALUE": "Value", + "PERFORMACTION": "Perform Action", + "EXECUTE": "Execute", + "EXECNSPRIMITIVE": "Exec NS Primitive", + "PRIMITIVETYPE": "Primitive Type", + "VNFPRIMITIVE": "VNF Level Primitive", + "NSPRIMITIVE": "NS Level Primitive", + "DESCRIPTOR": "Descriptor", + "ERROR": "Something Went wrong please try again", + "SHOWGRAPH": "Show Graph", + "UPDATESHOWGRAPH": "Update and Show Graph", + "CREATEPACKAGE": "Create New Package", + "GZFILETYPEERRROR": "Upload only tar.gz file and size should not exceed 15 MB", + "YAMLFILETYPEERRROR": "Upload only YAML file and size should not exceed 15 MB", + "JSONFILETYPEERRROR": "Upload only JSON file and size should not exceed 15 MB", + "PUBFILETYPEERRROR": "Upload only PUB file and size should not exceed 15 MB", + "PACKAGE": "Package", + "URL": "URL", + "DEPLOYED": "Deployed", + "ROLES": "Roles", + "INSTANCEDETAILS": "Instance Details", + "IPADDRESS": "IP Address", + "MGMT": "Mgmt", + "NETNAME": "Net Name", + "USER": "User", + "PORT": "Port", + "USERNAME": "Username", + "PASSWORD": "Password", + "NODATAERROR": "An error occurred while retrieving the information", + "FREEZE": "Freeze", + "UNFREEZE": "Unfreeze", + "CLONE": "Clone", + "CLONECONFIRMPOPUPMESSAGE": "Are you sure want to clone", + "CLONESUCCESSFULLY": "Package cloned successfully", + "DROPFILES": "Just drag and drop files or click here to upload files", + "DROPFILESVALIDATION": "Please select one file to process", + "METRICS": "Metrics", + "NOOFHOURS": "No Of Hours", + "MANDATORYCHECK": "Mandatory fields are marked with an asterisk (*)", + "K8VERSION": "K8 Version", + "ENTER": "Enter", + "SWITCHPROJECT": "Switch Project", + "CURRENTPROJECT": "Current Project", + "SUBMIT": "Submit", + "REFRESH": "Refresh", + "OPEN": "Open", + "UPLOADCONFIG": "Upload Config", + "FILEUPLOADLABEL": "Or load from file", + "CONFIG": "Config", + "YAMLCONFIG": "Yaml Config", + "CHOOSEFILE": "Choose File", + "INVALIDCONFIG": "Invalid configuration", + "PAGE": { + "DASHBOARD": { + "DASHBOARD": "Dashboard", + "RECENTUSERLOG": "Recent User Log", + "LOGS": "Logs", + "FAILEDINSTANCES": "Failed Instances", + "NOINSTANCES": "No Instances Available", + "UPTIME": "Uptime", + "RUNNINGINSTANCES": "Running Instances", + "NETSLICETEMPLATE": "NetSlice Template", + "NETSLICEINSTANCE": "NetSlice Instances", + "USERS": "Users", + "PROJECTS": "Projects", + "USERSETTINGS": "User Settings", + "LOGOUT": "Logout" + }, + "LOGIN": { + "USERNAME": "Username", + "PASSWORD": "Password", + "SIGNUP": "Sign Up", + "ACCOUNTCREATEMESSAGE": "Don't have an account?", + "LOGIN": "Log In", + "PASSWORDVALIDMESSAGE": "Password is required", + "USERNAMEVALIDMESSAGE": "Username is required", + "SIGNINMSG": "Sign in to start your session", + "PASSWORDMINLENGTHVALIDMESSAGE": "Password must be 8 characters and contains at least one upper case, lower case, numeric & special character", + "USERNAMEMINLENGTHVALIDMESSAGE": "Username must be at least 5 characters" + }, + "INSTANCEINSTANTIATE": { + "NEWINSTANCE": "New Instance", + "NSNAME": "Ns Name", + "DESCRIPTION": "Description", + "NSID": "Nsd Id", + "SSHKEY": "SSH Key", + "VIMACCOUNT": "VIM Account", + "SSHKEYMSG": "Paste your key here" + }, + "NSMETRIC": { + "INSTANCESMETRIC": "Instances Metric", + "METRICERROR": "Data not available in metrics" + }, + "USERSETTINGS": { + "LANGUAGE": "Language" + }, + "VIM": { + "CREATEDSUCCESSFULLY": "VIM Created Successfully", + "LOACTIONINFO": "Type the location name and click enter button to select the location from the list" + }, + "VIMDETAILS": { + "NEWVIM": "New VIM", + "VIMACCOUNTDETAILS": "VIM Account details", + "NAME": "Name", + "VIMUSERNAME": "VIM Username", + "VIMURL": "VIM URL", + "VIMTYPE": "Type", + "TENANTNAME": "Tenant name", + "DESCRIPTION": "Description", + "SCHEMATYPE": "Schema Type", + "SCHEMAVERSION": "Schema Version", + "CONFIGPARAMETERS": "CONFIG PARAMETERS", + "SDNCONTROLLER": "SDN Controller", + "SDNPORTMAPPING": "SDN Port Mapping", + "VIMNETWORKNAME": "VIM Network Name", + "SECURITYGROUPS": "Security Groups", + "AVAILABILITYZONE": "Availability Zone", + "REGIONALNAME": "Region Name", + "INSECURE": "Insecure", + "USEEXISTINGFLAVOURS": "Use existing flavors", + "USEINTERNALENDPOINT": "Use internal endpoint", + "APIVERSION": "API version", + "PROJECTDOMAINID": "Project domain id", + "PROJECTDOMAINNAME": "Project domain name", + "USERDOMAINID": "User domain id", + "USERDOMAINUSER": "User domain name", + "KEYPAIR": "Keypair", + "DATAPLANEPHYSICALNET": "Dataplane physical net", + "USEFLOATINGIP": "Use floating ip", + "DATAPLANENETVLANRANGE": "Dataplane net vlan range", + "MICROVERSION": "Microversion", + "BACKTOVIMACCOUNTS": "Back to VimAccounts", + "VIMPASSWORD": "VIM Password", + "ADDITIONALCONFIG": "Additional configuration", + "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}", + "NEWVIMACCOUNT": "New VIM Account", + "ORGNAME": "Orgname", + "VCENTERIP": "Vcenter ip", + "VCENTERPORT": "Vcenter port", + "ADMINUSERNAME": "Admin username", + "VCENTERUSER": "Vcenter user", + "ADMINPASSWORD": "Admin password", + "VCENTERPASSWORD": "Vcenter password", + "NSXMANAGER": "Nsx manager", + "VROPSSITE": "Vrops site", + "NSXUSER": "Nsx user", + "VROPSUSER": "Vrops user", + "NSXPASSWORD": "Nsx password", + "VROPSPASSWORD": "Vrops password", + "VPCCIDRBLOCK": "VPC cidr block", + "FLAVORIINFO": "Flavor info", + "VIM_TYPE": "VIM Type", + "VIMLOCATION": "VIM Location", + "SUBSCRIPTIONID": "Subscription ID", + "RESOURCEGROUP": "Resource Group", + "VNETNAME": "VNet Name", + "FLAVORSPATTERN": "Flavors Pattern" + }, + "WIMACCOUNTS": { + "CREATEDSUCCESSFULLY": "WIM Created Successfully", + "WIMDETAILS": "WIM Details", + "NEWWIM": "New WIM", + "SCHEMAVERSION": "Schema Version", + "RO": "RO", + "ROACCOUNT": "RO Account", + "USERNAME": "WIM Username", + "PASSWORD": "WIM Password" + }, + "NSINSTANCE": { + "NEWNSINSTANCE": "New NS", + "CREATEDSUCCESSFULLY": "NS Instance Created Successfully" + }, + "VNFINSTANCE": { + "ADDVNFINSTANCE": "Add VNF Instance" + }, + "PDUINSTANCE": { + "NEWPDUINSTANCE": "New PDU", + "PDUTYPE": "PDU Type", + "PARAMETERS": "PDU Instances Parameters", + "ADDINSTANCEPARAMS": "Add Params", + "CREATEDSUCCESSFULLY": "PDU Instances Created Successfully" + }, + "NETSLICEINSTANCE": { + "CREATENETSLICEINSTANCE": "Create NSI" + }, + "SDNCONTROLLER": { + "NEWSDNCONTROLLER": "New SDN Controller", + "REGISTEREDSDNCONTROLLER": "Registered SDN Controllers", + "RO": "RO", + "DPID": "DPID", + "CREATEDSUCCESSFULLY": "SDN Registered Successfully", + "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx", + "DETAILS": "SDN Controller Details" + }, + "USERS": { + "CREATEUSER": "Create User", + "NEWUSER": "New User", + "USERNAME": "User Name", + "PASSWORD": "Password", + "CONFPASSWORD": "Confirm Password", + "EDITUSER": "Edit User", + "NEWPASSWORD": "New Password", + "DEFAULTPROJECT": "Default Project", + "PASSWORDCONFLICT": "Password and confirm password are not matched", + "PASSWORDMATCH": "Password Match", + "CREATEDSUCCESSFULLY": "User Created Successfully", + "EDITEDSUCCESSFULLY": "User Edit Successfully", + "EDITCREDENTIALS": "Change Password", + "EDITUSERNAME": "Change Username", + "PROJECTSROLES": "Projects Roles", + "EDITPROJECTROLEMAPPING": "Edit Project Role Mapping", + "ADDMAPPINGS": "Add Mappings", + "EDITPROJECTROLEERROR": "Please provide at least one project role mapping to continue" + }, + "TOPOLOGY": { + "SELECTELEMENT": "Select Element", + "VL": "VL", + "VNF": "VNF", + "VNFD": "VNFD", + "CP": "CP", + "NSD": "NSD", + "NS": "NS", + "VIRTUALLINK": "Virtual Link", + "CONNECTIONPOINT": "Connection Point", + "INTCONNECTIONPOINT": "Int Connection Point", + "LINK": "Link", + "ADDINGCP": "Please select a connection point of {{vnfdname}} to link {{vlname}}?", + "INFO": "Info", + "HELP": "Help", + "HELPINFO": { + "CREATEEDGE": "Create edge", + "CREATEEDGEFIRSTSETENCE": "Select the first vertex by clicking on it using", + "CREATEEDGESECONDSETENCE": "on another vertex (different than the selected one).", + "DELETEEDGEVERTEX": "Delete edge/vertex", + "DELETEEDGEVERTEXSENTENCE": "Double clicking on edge/vertex.", + "SPREADEDGE": "Spread edge", + "SPREADEDGESENTENCE": "Select the vertex by clicking on it using", + "EDGEINFO": "Show edge information", + "EDGEINFOSENTENCE": "Select the edge by clicking. The information will be shown on the left side." + }, + "VDU": "VDU", + "INTVL": "IntVL", + "INTCP": "IntCP", + "DATAEMPTY": "Please change something" + }, + "PROJECT": { + "NEWPROJECT": "New Project", + "CREATEDSUCCESSFULLY": "Project Created Successfully", + "UPDATEDSUCCESSFULLY": "Project Updated Successfully" + }, + "NSPACKAGE": { + "ADDNSPACKAGE": "Compose a new NS", + "CREATEDSUCCESSFULLY": "NS Package Created Successfully", + "NSCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully", + "CONFIRMCONNECTIONPOINT": "Please confirm to add connection point", + "CANNOTLINKVNF": "You can't link a vnf with a vnf", + "CANNOTLINKVL": "You can't link a VL with a VL", + "CANNOTLINKVLVNF": "You can't link a VL with a vnf", + "CANNOTLINKVNFCP": "You can't link a VNF with a CP", + "CANNOTLINKVLCP": "You can't link a VL with a CP", + "CANNOTLINKCP": "You can't link a CP with a CP", + "ADDNSD": "Virtual Link is added succesfully", + "ADDVNFD": "VNFD is added succesfully", + "ADDNS": "Connection Link is added succesfully", + "DELETENSD": "Successfully Deleted the Virtual Link", + "DELETEVNFD": "Successfully Deleted the VNF", + "DELETENS": "Successfully Deleted the Connection point", + "DELETELINK": "Successfully Deleted the Link", + "MGMTNETWORK": "Mgmt Network", + "VIMNETWORKNAME": "Vim Network Name", + "MEMBER-VNF-INDEX": "member-vnf-index", + "VNFD-ID-REF": "vnfd-id-ref", + "VLD-ID": "vld-id", + "VNFD-CP-REF": "vnfd-connection-point-ref" + }, + "EDITPACKAGES": { + "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully" + } + }, + "VNFPACKAGE": { + "ADDVNFPACKAGE": "Compose a new VNF", + "CREATEDSUCCESSFULLY": "VNF Package Created Successfully", + "VNFCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Descriptor Updated Successfully", + "INVALIDSELECTION": "Invalid Selection", + "YOUCANNOTDELETELINK": "You cannot delete link", + "CANNOTLINKVDUANDINTCP": "You cant link vdu with int_cp", + "CANNOTLINKINTCPANDVDU": "You cant link int_cp with vdu", + "CANNOTLINKCPANDVNFVL": "You cant link cp with vnf_vl", + "CANNOTLINKVNFVLANDCP": "You cant link vnf_vl with cp", + "CANNOTLINKINTCPANDCP": "You cant link intcp with cp", + "CANNOTLINKCPANDINTCP": "You cant link cp with int_cp", + "CANNOTLINKVDUANDVDU": "You can't link a vdu with a vdu" + } + }, + "NETSLICE": { + "CREATEDSUCCESSFULLY": "Netslice Created Successfully", + "TEMPLATECREATEDSUCCESSFULLY": "Netslice Template Created Successfully", + "UPDATEDSUCCESSFULLY": "Template Updated Successfully" + }, + "NETSLICETEMPLATE": { + "NETSLICETEMPLATEDETAILS": "Network Slices Template Details" + }, + "NSTINSTANCEINSTANTIATE": { + "NEWINSTANCE": "New Instance", + "NSNAME": "Ns Name", + "DESCRIPTION": "Description", + "NSTID": "Nst Id", + "SSHKEY": "SSH Key", + "VIMACCOUNT": "VIM Account", + "SSHKEYMSG": "Paste your key here ..." + }, + "NSPRIMITIVE": { + "PRIMITIVE": "Primitive", + "PRIMITIVEPARAMETERS": "Primitive Parameters", + "ADDPRIMITIVEPARAMS": "Add Primitive Params", + "EXECUTEDSUCCESSFULLY": "Executed NS Primitive Configuration" + }, + "ROLES": { + "CREATEROLE": "Create Role", + "ROLE": "Role", + "PERMISSIONS": "Permissions", + "YAMLPERMISSIONS": "YAML Permissions", + "CREATEDSUCCESSFULLY": "Role Created Successfully", + "UPDATEDSUCCESSFULLY": "Role Updated Successfully", + "ROLEJSONERROR": "Role permissions should be provided in a key-value fashion", + "ROLEKEYERROR": "Value of '{{roleKey}}' in a role permissions should be boolean", + "EDITROLE": "Edit Role", + "PREVIEW": "Preview", + "TEXTVIEW": "Text View" + }, + "K8S": { + "MENUK8S": "K8s", + "MENUK8SCLUSTER": "K8s Clusters", + "MENUK8SREPO": "K8s Repos", + "REGISTERK8CLUSTER": "Registered K8s clusters", + "ADDK8CLUSTER": "Add K8s Cluster", + "K8SCLUSTERDETAILS": "K8s Cluster Details", + "REGISTERK8REPO": "Registered K8s repository", + "ADDK8REPO": "Add K8s Repository", + "K8SREPODETAILS": "K8s Repository Details", + "CREATEDSUCCESSFULLY": "K8s Created Successfully", + "NEWK8SCLUSTER": "New K8s Cluster", + "NAME": "Name", + "K8SVERSION": "K8s Version", + "VIMACCOUNT": "Vim Account", + "DESCRIPTION": "Description", + "NETS": "Nets", + "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}", + "CREDENTIALS": "Credentials", + "NEWK8SREPO": "New K8s Repository", + "TYPE": "Type", + "URL": "URL" + } + }, + "HTTPERROR": { + "401": "Access denied, Lack of permissions", + "400": "Please check the request and try again", + "404": "Expected service not avilable, Please try again later", + "500": "Server error, Please try again later", + "502": "Bad Gateway, Please try again later", + "503": "Service temporarily unavailable, Please try again later", + "504": "Gateway timeout error, Please try again later", + "409": "Please try again later" + }, + "PAGENOTFOUND": { + "OOPS": "Oops!", + "NOTFOUND": "404 Not Found", + "CONTENT": "The page cannot be found or unauthorized, it might be no longer relevant or had its name changed", + "MEAN": "Meanwhile, you may return to", + "HOME": "Home" + }, + "DOMVALIDATIONS": { + "INVALIDURL": "Enter a valid URL", + "INVALIDIPADDRESS": "Enter a valid IP Address", + "INVALIDPORTADDRESS": "Enter a valid PORT Address", + "INVALIDDPID": "Enter a valid DPID", + "INVALIDJSON": "Enter a valid JSON Format", + "INVALIDYAML": "Enter a valid JSON Format" + }, + "GRAFANA": { + "METRICSERROR": "Not a valid metrics" + } +} \ No newline at end of file diff --git a/src/assets/i18n/es.json b/src/assets/i18n/es.json new file mode 100644 index 0000000..0cd37b1 --- /dev/null +++ b/src/assets/i18n/es.json @@ -0,0 +1,479 @@ +{ + "OSM": "OSM", + "APPVERSION": "Versión de la aplicación", + "OSMVERSION": "Versión OSM", + "OSMSOURCEMANO": "Fuente abierta MANO", + "ADMIN": "Admin", + "ENTRIES": "entradas", + "COMPOSE": "Componer un", + "CREATE": "Crear", + "SELECT": "Seleccionar", + "CANCEL": "Cancelar", + "SAVE": "Salvar", + "COUNT": "contar", + "IMAGE": "Imagen", + "IPPROFILEREF": "IP Profile Ref", + "ACTION": "Acción", + "ADD": "Añadir", + "EDIT": "Editar", + "APPLY": "Aplicar", + "FORCE": "Fuerza", + "DOWNLOAD": "Descargar", + "CONTENT": "contenido", + "DELETE": "Borrar", + "FORCEDELETE": "Eliminar forzado", + "RENAME": "Rebautizar", + "INFO": "Info", + "NSPACKAGES": "NS Paquetes", + "VNFPACKAGES": "VNF Paquetes", + "INSTANCES": "Instancias", + "INSTANTIATE": "Instanciar", + "NSINSTANCES": "Instancias de NS", + "VNFINSTANCES": "Instancias VNF", + "PDUINSTANCES": "Instancias PDU", + "VIMACCOUNTS": "Cuentas VIM", + "WIMACCOUNTS": "Cuentas WIM", + "SDNCONTROLLER": "Controlador SDN", + "NETSLICE": "Netslice", + "PROJECT": "Proyecto", + "DOMAIN": "Dominio", + "PACKAGES": "Paquetes", + "MODIFIED": "Modificado", + "NODATAMSG": "No hay datos disponibles en la tabla", + "SHORTNAME": "Nombre corto", + "IDENTIFIER": "Identificador", + "DESCRIPTION": "Descripción", + "VENDOR": "Vendedor", + "VERSION": "Versión", + "ACTIONS": "Comportamiento", + "NAME": "NOMBRE", + "USAGESTATE": "Estado de uso", + "MODIFICATIONDATE": "Fecha de modificación", + "CREATEDDATE": "Fecha de creación", + "OPERATIONALSTATUS": "Estado operativo", + "OPERATIONALSTATE": "Estado operacional", + "CONFIGSTATUS": "Estado de configuración", + "DETAILEDSTATUS": "Estado detallado", + "NSDNAME": "Nombre nsd", + "NSTNAME": "Nst name", + "TYPE": "Tipo", + "VNFD": "VNFD", + "VNF": "VNF", + "MEMBERINDEX": "Índice de miembros", + "NS": "NS", + "CREATEDAT": "Creado en", + "CREATED": "Creado", + "ALL": "Todas", + "ID": "Id", + "OPERATIONSTATE": "Estado de la operación", + "STARTTIME": "Hora de inicio", + "STATUSENTEREDTIME": "Tiempo ingresado estado", + "HISTORYOFOPERATIONS": "Historia de operaciones", + "UPDATE": "Actualizar", + "READONLYMODE": "Modo de solo lectura", + "CURRENTLY": "Actualmente", + "ON": "En", + "OFF": "APAGADA", + "IN": "en", + "FILES": "Archivos", + "NEW": "Nueva", + "RECENTLY": "Recientemente", + "TOPOLOGY": "Topología", + "PLEASEWAIT": "Por favor espera", + "LOADING": "Cargando", + "RESOURCEORCHESTRATOR": "Orquestador de recursos", + "VIEW": "Ver", + "DROP": "soltar", + "HERE": "aquí", + "MAPVIEW": "Vista del mapa", + "LISTVIEW": "Vista de la lista", + "OK": "Okay", + "DELETEDSUCCESSFULLY": "Eliminada Exitosamente", + "SESSIONEXPIRY": "Sesión expirada, por favor ingrese nuevamente", + "DELETECONFIRMPOPUPMESSAGE": "¿Seguro que quieres eliminar?", + "DELETELOADERMESSAGE": "Por favor espere mientras la eliminación está en progreso", + "VALUE": "Valor", + "PERFORMACTION": "Realizar una acción", + "EXECUTE": "Ejecutar", + "EXECNSPRIMITIVE": "Ejecutar NS Primitiva", + "PRIMITIVETYPE": "Tipo primitivo", + "VNFPRIMITIVE": "Nivel VNF Primitivo", + "NSPRIMITIVE": "NS Level Primitive", + "DESCRIPTOR": "Descriptora", + "ERROR": "Algo salió mal. Por favor, vuelva a intentarlo", + "SHOWGRAPH": "Mostrar gráfico", + "UPDATESHOWGRAPH": "Actualizar y mostrar gráfico", + "CREATEPACKAGE": "Crear nuevo paquete", + "GZFILETYPEERRROR": "Cargue solo el archivo tar.gz y el tamaño no debe exceder los 15 MB", + "YAMLFILETYPEERRROR": "Cargue solo el archivo YAML y el tamaño no debe exceder los 15 MB", + "JSONFILETYPEERRROR": "Cargue solo el archivo JSON y el tamaño no debe exceder los 15 MB", + "PUBFILETYPEERRROR": "Cargue solo el archivo PUB y el tamaño no debe exceder los 15 MB", + "PACKAGE": "Paquete", + "URL": "URL", + "DEPLOYED": "Desplegada", + "ROLES": "Roles", + "INSTANCEDETAILS": "Detalles de instancia", + "IPADDRESS": "Dirección IP", + "MGMT": "Mgmt", + "NETNAME": "Nombre neto", + "USER": "Usuaria", + "PORT": "Puerto", + "USERNAME": "Nombre de usuario", + "PASSWORD": "Contraseña", + "NODATAERROR": "Se produjo un error al recuperar la información", + "FREEZE": "Congelar", + "UNFREEZE": "Descongelar", + "CLONE": "Clon", + "CLONECONFIRMPOPUPMESSAGE": "Estás seguro de querer clonar", + "CLONESUCCESSFULLY": "Paquete clonado exitosamente", + "DROPFILES": "Simplemente arrastre y suelte archivos aquí o haga clic aquí para cargar archivos", + "DROPFILESVALIDATION": "Por favor seleccione un archivo para procesar", + "METRICS": "Métrica", + "NOOFHOURS": "No de horas", + "MANDATORYCHECK": "Los campos obligatorios están marcados con un asterisco (*)", + "K8VERSION": "Versión K8", + "ENTER": "Entrar", + "SWITCHPROJECT": "Cambiar proyecto", + "CURRENTPROJECT": "Proyecto actual", + "SUBMIT": "Entrar", + "REFRESH": "Actualizar", + "OPEN": "Abierta", + "UPLOADCONFIG": "Subir configuración", + "FILEUPLOADLABEL": "O cargar desde el archivo", + "CONFIG": "Config", + "YAMLCONFIG": "Yaml Config", + "CHOOSEFILE": "Elija el archivo", + "INVALIDCONFIG": "Configuración inválida", + "PAGE": { + "DASHBOARD": { + "DASHBOARD": "Tablero", + "RECENTUSERLOG": "Registro de usuario reciente", + "LOGS": "Troncos", + "FAILEDINSTANCES": "Instancias fallidas", + "NOINSTANCES": "Keine Instanzen verfügbar", + "UPTIME": "Tiempodeactividad", + "RUNNINGINSTANCES": "Corriendo Instancias", + "NETSLICETEMPLATE": "Plantilla NetSlice", + "NETSLICEINSTANCE": "NetSlice Instancias", + "USERS": "Usuarios", + "PROJECTS": "Proyectos", + "USERSETTINGS": "Usuarios Ajustes", + "LOGOUT": "Cerrar sesión" + }, + "LOGIN": { + "USERNAME": "Nombre de usuario", + "PASSWORD": "Contraseña", + "SIGNUP": "Regístrate", + "ACCOUNTCREATEMESSAGE": "¿No tienes una cuenta?", + "LOGIN": "iniciar sesión", + "PASSWORDVALIDMESSAGE": "se requiere contraseña", + "USERNAMEVALIDMESSAGE": "Se requiere nombre de usuario", + "SIGNINMSG": "Inicia sesión para iniciar tu sesión.", + "PASSWORDMINLENGTHVALIDMESSAGE": "La contraseña debe tener 8 caracteres y contiene al menos un carácter en mayúscula, minúscula, numérico y especial", + "USERNAMEMINLENGTHVALIDMESSAGE": "El nombre de usuario debe tener al menos 5 caracteres" + }, + "INSTANCEINSTANTIATE": { + "NEWINSTANCE": "Nueva instancia", + "NSNAME": "Nombre de Ns", + "DESCRIPTION": "Descripción", + "NSID": "Nsd Id", + "SSHKEY": "SSH Key", + "VIMACCOUNT": "Cuenta VIM", + "SSHKEYMSG": "Pega tu llave aquí" + }, + "NSMETRIC": { + "INSTANCESMETRIC": "Instancia métrica", + "METRICERROR": "Datos no disponibles en métricas" + }, + "USERSETTINGS": { + "LANGUAGE": "Idioma" + }, + "VIM": { + "CREATEDSUCCESSFULLY": "VIM Creada Exitosamente", + "LOACTIONINFO": "Escriba el nombre de la ubicación y haga clic en el botón Intro para seleccionar la ubicación de la lista" + }, + "VIMDETAILS": { + "NEWVIM": "Nuevo VIM", + "VIMACCOUNTDETAILS": "VIM Account detalles", + "NAME": "Nombre", + "VIMUSERNAME": "VIM Nombre de usuario", + "VIMURL": "VIM URL", + "VIMTYPE": "Tipo", + "TENANTNAME": "Tenant Nombre", + "DESCRIPTION": "Descripción", + "SCHEMATYPE": "Tipo de esquema", + "SCHEMAVERSION": "Versión de esquema", + "CONFIGPARAMETERS": "CONFIGURAR PARÁMETROS", + "SDNCONTROLLER": "SDN Controladora", + "SDNPORTMAPPING": "SDN La asignación de puertos", + "VIMNETWORKNAME": "VIM Nombre de red", + "SECURITYGROUPS": "Grupos de seguridad", + "AVAILABILITYZONE": "Zona de disponibilidad", + "REGIONALNAME": "Nombre de región", + "INSECURE": "Insegura", + "USEEXISTINGFLAVOURS": "Usa sabores existentes", + "USEINTERNALENDPOINT": "Usar punto final interno", + "APIVERSION": "Versión API ", + "PROJECTDOMAINID": "Proyecto dominio id", + "PROJECTDOMAINNAME": "Proyecto dominio name", + "USERDOMAINID": "Usuaria dominio id", + "USERDOMAINUSER": "Usuaria dominio nombre", + "KEYPAIR": "Par de claves", + "DATAPLANEPHYSICALNET": "Plano de datos physical net", + "USEFLOATINGIP": "Utilizar flotante ip", + "DATAPLANENETVLANRANGE": "Plano de datos net vlan range", + "MICROVERSION": "Microversión", + "BACKTOVIMACCOUNTS": "Atrás a VimAccounts", + "VIMPASSWORD": "VIM Contraseña", + "ADDITIONALCONFIG": "Adicional configuración", + "ADDITIONALCONFIGPLACEHOLDER": "{'key1': [...], 'key2': {}, 'key3': ''}", + "NEWVIMACCOUNT": "Nueva VIM Cuenta", + "ORGNAME": "Orgnombre", + "VCENTERIP": "Vcenter ip", + "VCENTERPORT": "Vcenter Puerto", + "ADMINUSERNAME": "Administración nombre de usuario", + "VCENTERUSER": "Vcenter usuaria", + "ADMINPASSWORD": "Administración contraseña", + "VCENTERPASSWORD": "Vcenter contraseña", + "NSXMANAGER": "Nsx gerente", + "VROPSSITE": "Vrops sitio", + "NSXUSER": "Nsx usuaria", + "VROPSUSER": "Vrops usuaria", + "NSXPASSWORD": "Nsx contraseña", + "VROPSPASSWORD": "Vrops contraseña", + "VPCCIDRBLOCK": "VPC cidr bloquear", + "FLAVORIINFO": "Flavor informacion", + "VIM_TYPE": "VIM Tipo", + "VIMLOCATION": "VIM Ubicación", + "SUBSCRIPTIONID": "ID de suscripción", + "RESOURCEGROUP": "Grupo de recursos", + "VNETNAME": "Nombre de red virtual", + "FLAVORSPATTERN": "Patrón de sabores" + }, + "WIMACCOUNTS": { + "CREATEDSUCCESSFULLY": "WIM Creado Exitosamente", + "WIMDETAILS": "Detalles de WIM", + "NEWWIM": "Nuevo WIM", + "SCHEMAVERSION": "Versión de esquema", + "RO": "RO", + "ROACCOUNT": "Cuenta RO", + "USERNAME": "Nombre de usuario de WIM", + "PASSWORD": "Contraseña WIM" + }, + "NSINSTANCE": { + "NEWNSINSTANCE": "Nueva NS", + "CREATEDSUCCESSFULLY": "NS Ejemplo Creado Exitosamente" + }, + "VNFINSTANCE": { + "ADDVNFINSTANCE": "Agregar instancia VNF" + }, + "PDUINSTANCE": { + "NEWPDUINSTANCE": "Nueva PDU", + "PDUTYPE": "Tipo de PDU", + "PARAMETERS": "Parámetros de instancias de PDU", + "ADDINSTANCEPARAMS": "Agregar parámetros", + "CREATEDSUCCESSFULLY": "Instancias de PDU creadas con éxito" + }, + "NETSLICEINSTANCE": { + "CREATENETSLICEINSTANCE": "Crear NSI" + }, + "SDNCONTROLLER": { + "NEWSDNCONTROLLER": "Nuevo controlador SDN", + "REGISTEREDSDNCONTROLLER": "Controladores SDN registrados", + "RO": "RO", + "DPID": "DPID", + "CREATEDSUCCESSFULLY": "SDN registrado con éxito", + "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx", + "DETAILS": "Detalles del controlador SDN" + }, + "USERS": { + "CREATEUSER": "Crear usuario", + "NEWUSER": "Nuevo usuario", + "USERNAME": "Nombre de usuario", + "PASSWORD": "Contraseña", + "CONFPASSWORD": "confirmar Contraseña", + "EDITUSER": "editar usuario", + "NEWPASSWORD": "Nueva contraseña", + "DEFAULTPROJECT": "Proyecto predeterminado", + "PASSWORDCONFLICT": "La contraseña y la contraseña de confirmación no coinciden", + "PASSWORDMATCH": "Contraseña", + "CREATEDSUCCESSFULLY": "Usuario Creada Exitosamente", + "EDITEDSUCCESSFULLY": "Usuario editado correctamente", + "EDITCREDENTIALS": "Cambia la contraseña", + "EDITUSERNAME": "Cambie el nombre de usuario", + "PROJECTSROLES": "Roles de proyectos", + "EDITPROJECTROLEMAPPING": "Editar asignación de roles de proyecto", + "ADDMAPPINGS": "Agregar asignaciones", + "EDITPROJECTROLEERROR": "Proporcione al menos un mapeo de roles del proyecto para continuar" + }, + "TOPOLOGY": { + "SELECTELEMENT": "Seleccionar elemento", + "VL": "VL", + "VNF": "VNF", + "VNFD": "VNFD", + "CP": "CP", + "NSD": "NSD", + "NS": "NS", + "VIRTUALLINK": "Enlace virtual", + "CONNECTIONPOINT": "Punto de conexión", + "INTCONNECTIONPOINT": "Int Punto de conexión", + "LINK": "Enlazar", + "ADDINGCP": "Seleccione un punto de conexión de {{vnfdname}} para vincular {{vlname}}?", + "INFO": "Informacion", + "HELP": "Ayuda", + "HELPINFO": { + "CREATEEDGE": "Crear borde", + "CREATEEDGEFIRSTSETENCE": "Seleccione el primer vértice haciendo clic en él usando", + "CREATEEDGESECONDSETENCE": "en otro vértice (diferente al seleccionado).", + "DELETEEDGEVERTEX": "Eliminar borde/vértice", + "DELETEEDGEVERTEXSENTENCE": "Doble clic en borde / vértice.", + "SPREADEDGE": "Borde extendido", + "SPREADEDGESENTENCE": "Seleccione el vértice haciendo clic en él usando", + "EDGEINFO": "Mostrar información de borde", + "EDGEINFOSENTENCE": "Seleccione el borde haciendo clic. La información se mostrará en el lado izquierdo." + }, + "VDU": "VDU", + "INTVL": "IntVL", + "INTCP": "IntCP", + "DATAEMPTY": "Por favor cambia algo" + }, + "PROJECT": { + "NEWPROJECT": "Nuevo proyecto", + "CREATEDSUCCESSFULLY": "Proyecto Creada Exitosamente", + "UPDATEDSUCCESSFULLY": "Proyecto Actualizada Exitosamente" + }, + "NSPACKAGE": { + "ADDNSPACKAGE": "Componer un nuevo NS", + "CREATEDSUCCESSFULLY": "NS Paquetes Creada Exitosamente", + "NSCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Actualizada Exitosamente", + "CONFIRMCONNECTIONPOINT": "Confirme para agregar un punto de conexión", + "CANNOTLINKVNF": "No puedes vincular un vnf con un vnf", + "CANNOTLINKVL": "No puedes vincular un VL con un VL", + "CANNOTLINKVLVNF": "No puedes vincular un VL con un vnf", + "CANNOTLINKVNFCP": "No puedes vincular un VNF con un CP", + "CANNOTLINKVLCP": "No puedes vincular un VL con un CP", + "CANNOTLINKCP": "No puedes vincular un CP con un CP", + "ADDNSD": "Enlace virtual se agrega con éxito", + "ADDVNFD": "VNFD se agrega con éxito", + "ADDNS": "El enlace de conexión se agregó con éxito", + "DELETENSD": "Se eliminó con éxito el enlace virtual", + "DELETEVNFD": "Eliminado con éxito el VNF", + "DELETENS": "Se eliminó correctamente el punto de conexión", + "DELETELINK": "Se eliminó el enlace correctamente", + "MGMTNETWORK": "Mgmt Network", + "VIMNETWORKNAME": "Vim Network Name", + "MEMBER-VNF-INDEX": "member-vnf-index", + "VNFD-ID-REF": "vnfd-id-ref", + "VLD-ID": "vld-id", + "VNFD-CP-REF": "vnfd-punto de conexión-ref" + }, + "EDITPACKAGES": { + "UPDATEDSUCCESSFULLY": "Descriptor actualizado exitosamente" + } + }, + "VNFPACKAGE": { + "ADDVNFPACKAGE": "Componer un nuevo VNF", + "CREATEDSUCCESSFULLY": "VNF Paquetes Creada Exitosamente", + "VNFCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Actualizada Exitosamente", + "INVALIDSELECTION": "Selección invalida", + "YOUCANNOTDELETELINK": "No puedes eliminar el enlace", + "CANNOTLINKVDUANDINTCP": "No puedes vincular vdu con int_cp", + "CANNOTLINKINTCPANDVDU": "No puedes vincular int_cp con vdu", + "CANNOTLINKCPANDVNFVL": "No puedes vincular cp con vnf_vl", + "CANNOTLINKVNFVLANDCP": "No puedes vincular vnf_vl con cp", + "CANNOTLINKINTCPANDCP": "No puedes vincular intcp con cp", + "CANNOTLINKCPANDINTCP": "No puedes vincular cp con int_cp", + "CANNOTLINKVDUANDVDU": "No puedes vincular un vdu con un vdu" + } + }, + "NETSLICE": { + "CREATEDSUCCESSFULLY": "Netslice Creada Exitosamente", + "TEMPLATECREATEDSUCCESSFULLY": "Netslice Modelo Created Successfully", + "UPDATEDSUCCESSFULLY": "Plantilla actualizada con éxito" + }, + "NETSLICETEMPLATE": { + "NETSLICETEMPLATEDETAILS": "Red Rebanadas Modelo Detalles" + }, + "NSTINSTANCEINSTANTIATE": { + "NEWINSTANCE": "Nueva instancia", + "NSNAME": "Nombre de Ns", + "DESCRIPTION": "Descripción", + "NSTID": "Nsd Id", + "SSHKEY": "SSH Key", + "VIMACCOUNT": "Cuenta VIM", + "SSHKEYMSG": "Pega tu llave aquí ..." + }, + "NSPRIMITIVE": { + "PRIMITIVE": "Primitiva", + "PRIMITIVEPARAMETERS": "Primitiva Parámetros", + "ADDPRIMITIVEPARAMS": "Añadir Parámetros primitivos", + "EXECUTEDSUCCESSFULLY": "Ejecutada NS Configuración primitiva" + }, + "ROLES": { + "CREATEROLE": "Crear rol", + "ROLE": "Papel", + "PERMISSIONS": "Permisos", + "YAMLPERMISSIONS": "YAML Permisos", + "CREATEDSUCCESSFULLY": "Rol creado con éxito", + "UPDATEDSUCCESSFULLY": "Rol actualizado exitosamente", + "ROLEJSONERROR": "Los permisos de rol deben proporcionarse de manera clave-valor", + "ROLEKEYERROR": "El valor de '{{roleKey}}' en los permisos de un rol debe ser booleano", + "EDITROLE": "Editar rol", + "PREVIEW": "Avance", + "TEXTVIEW": "Vista de texto" + }, + "K8S": { + "MENUK8S": "K8s", + "MENUK8SCLUSTER": "Clusters K8s", + "MENUK8SREPO": "K8s Repos", + "REGISTERK8CLUSTER": "Grupos de K8 registrados", + "ADDK8CLUSTER": "Agregar clúster K8s", + "K8SCLUSTERDETAILS": "Detalles del clúster K8s", + "REGISTERK8REPO": "Repositorio K8 registrado", + "ADDK8REPO": "Agregar repositorio K8s", + "K8SREPODETAILS": "Detalles del repositorio de K8s", + "CREATEDSUCCESSFULLY": "K8 creados con éxito", + "NEWK8SCLUSTER": "Nuevo clúster K8s", + "NAME": "Nombre", + "K8SVERSION": "Versión K8s", + "VIMACCOUNT": "Cuenta Vim", + "DESCRIPTION": "Descripción", + "NETS": "Nets", + "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}", + "CREDENTIALS": "Cartas credenciales", + "NEWK8SREPO": "Nuevo repositorio K8s", + "TYPE": "Tipo", + "URL": "URL" + } + }, + "HTTPERROR": { + "401": "Acceso denegado", + "400": "Por favor revise la solicitud e intente nuevamente", + "404": "El servicio esperado no está disponible. Vuelve a intentarlo más tarde.", + "500": "Error del servidor. Vuelve a intentarlo más tarde", + "502": "Bad Gateway, por favor intente nuevamente más tarde", + "503": "El servicio no está disponible temporalmente. Vuelve a intentarlo más tarde", + "504": "Error de tiempo de espera de la puerta de enlace. Vuelva a intentarlo más tarde", + "409": "Por favor, inténtelo de nuevo más tarde" + }, + "PAGENOTFOUND": { + "OOPS": "¡Uy!", + "NOTFOUND": "404 No encontrado", + "CONTENT": "La página no se puede encontrar o no está autorizada, puede que ya no sea relevante o se haya cambiado su nombre.", + "MEAN": "Mientras tanto, puede volver a", + "HOME": "Hogar" + }, + "DOMVALIDATIONS": { + "INVALIDURL": "Ingrese una URL válida", + "INVALIDIPADDRESS": "Ingrese una dirección IP válida", + "INVALIDPORTADDRESS": "Ingrese una dirección de puerto válida", + "INVALIDDPID": "Ingrese un DPID válido", + "INVALIDJSON": "Ingrese un formato JSON válido", + "INVALIDYAML": "Ingrese un formato YAML válido" + }, + "GRAFANA": { + "METRICSERROR": "No es una métrica válida" + } +} \ No newline at end of file diff --git a/src/assets/i18n/pt.json b/src/assets/i18n/pt.json new file mode 100644 index 0000000..3c948ac --- /dev/null +++ b/src/assets/i18n/pt.json @@ -0,0 +1,479 @@ +{ + "OSM": "OSM", + "APPVERSION": "Versão da aplicação", + "OSMVERSION": "Versão OSM", + "OSMSOURCEMANO": "Código aberto MANO", + "ADMIN": "Admin", + "ENTRIES": "Entradas", + "COMPOSE": "Componha um", + "CREATE": "Crio", + "SELECT": "Selecione", + "CANCEL": "Cancelar", + "SAVE": "Salve", + "COUNT": "contagem", + "IMAGE": "Imagem", + "IPPROFILEREF": "Ref do perfil IP", + "ACTION": "Açao", + "ADD": "Adicionar", + "EDIT": "Editar", + "APPLY": "Aplique", + "FORCE": "Força", + "DOWNLOAD": "Baixar", + "CONTENT": "Conteúdo", + "DELETE": "Excluir", + "FORCEDELETE": "Forçar exclusão", + "RENAME": "Renomear", + "INFO": "Info", + "NSPACKAGES": "Pacotes NS", + "VNFPACKAGES": "Pacotes VNF", + "INSTANCES": "Instâncias", + "INSTANTIATE": "Instanciar", + "NSINSTANCES": "Instâncias NS", + "VNFINSTANCES": "Instâncias VNF", + "PDUINSTANCES": "Instâncias da PDU", + "VIMACCOUNTS": "Contas VIM", + "WIMACCOUNTS": "Contas WIM", + "SDNCONTROLLER": "Controlador SDN", + "NETSLICE": "Netslice", + "PROJECT": "Projeto", + "DOMAIN": "Domínio", + "MODIFIED": "Modificada", + "PACKAGES": "Pacotes", + "NODATAMSG": "Sem dados disponíveis na tabela", + "SHORTNAME": "Nome curto", + "IDENTIFIER": "Identificador", + "DESCRIPTION": "Descrição", + "VENDOR": "Fornecedor", + "VERSION": "Versão", + "ACTIONS": "Ações", + "NAME": "Nome", + "USAGESTATE": "UsageState", + "MODIFICATIONDATE": "Modificação de data", + "CREATEDDATE": "Data de criação", + "OPERATIONALSTATUS": "Estado operacional", + "OPERATIONALSTATE": "Estado operacional", + "CONFIGSTATUS": "Status da configuração", + "DETAILEDSTATUS": "Status detalhado", + "NSDNAME": "Nome nsd", + "NSTNAME": "Nst name", + "TYPE": "Tipo", + "VNFD": "VNFD", + "VNF": "VNF", + "MEMBERINDEX": "Índice de membros", + "NS": "NS", + "CREATEDAT": "Criado em", + "CREATED": "Criada", + "ALL": "Todos", + "ID": "Identidade", + "OPERATIONSTATE": "Estado da operação", + "STARTTIME": "Hora de início", + "STATUSENTEREDTIME": "Horário de entrada do status", + "HISTORYOFOPERATIONS": "História das Operações", + "UPDATE": "Atualizar", + "READONLYMODE": "Modo somente leitura", + "CURRENTLY": "Atualmente", + "ON": "Em", + "OFF": "Fora", + "IN": "em", + "FILES": "arquivos", + "NEW": "Nova", + "RECENTLY": "Recentemente", + "TOPOLOGY": "Topologia", + "PLEASEWAIT": "Por favor, espere", + "LOADING": "Carregando", + "RESOURCEORCHESTRATOR": "Orquestrador de Recursos", + "VIEW": "Visão", + "DROP": "Solta", + "HERE": "Aqui", + "MAPVIEW": "Visão do mapa", + "LISTVIEW": "Exibição de lista", + "OK": "Está bem", + "DELETEDSUCCESSFULLY": "Apagado com sucesso", + "SESSIONEXPIRY": "Sessão expirada, faça o login novamente", + "DELETECONFIRMPOPUPMESSAGE": "Tem certeza de que deseja excluir", + "DELETELOADERMESSAGE": "Aguarde enquanto a exclusão está em andamento", + "VALUE": "Valor", + "PERFORMACTION": "Executar a ação", + "EXECUTE": "Executar", + "EXECNSPRIMITIVE": "Exec NS Primitive", + "PRIMITIVETYPE": "Tipo primitivo", + "VNFPRIMITIVE": "Primitivo de nível VNF", + "NSPRIMITIVE": "NS Level Primitive", + "DESCRIPTOR": "Descritora", + "ERROR": "Alguma coisa deu errado. Por favor tente outra vez", + "SHOWGRAPH": "Mostrar gráfico", + "UPDATESHOWGRAPH": "Atualizar e mostrar gráfico", + "CREATEPACKAGE": "Criar novo pacote", + "GZFILETYPEERRROR": "Carregue apenas o arquivo tar.gz e o tamanho não deve exceder 15 MB", + "YAMLFILETYPEERRROR": "Carregar apenas arquivo YAML e o tamanho não deve exceder 15 MB", + "JSONFILETYPEERRROR": "Carregar apenas arquivo JSON e o tamanho não deve exceder 15 MB", + "PUBFILETYPEERRROR": "Carregar apenas arquivo PUB e o tamanho não deve exceder 15 MB", + "PACKAGE": "Pacote", + "URL": "URL", + "DEPLOYED": "Deployed", + "ROLES": "Funções", + "INSTANCEDETAILS": "Detalhes da Instância", + "IPADDRESS": "Endereço de IP", + "MGMT": "Mgmt", + "NETNAME": "Nome líquido", + "USER": "Do utilizador", + "PORT": "Porta", + "USERNAME": "Nome de usuário", + "PASSWORD": "Senha", + "NODATAERROR": "Ocorreu um erro ao recuperar as informações", + "FREEZE": "Congelar", + "UNFREEZE": "Descongelar", + "CLONE": "Clone", + "CLONECONFIRMPOPUPMESSAGE": "Tem certeza de que deseja clonar", + "CLONESUCCESSFULLY": "Pacote clonado com sucesso", + "DROPFILES": "Basta arrastar e soltar arquivos aqui ou clique aqui para fazer upload de arquivos", + "DROPFILESVALIDATION": "Selecione um arquivo para processar", + "METRICS": "Métricas", + "NOOFHOURS": "Não de horas", + "MANDATORYCHECK": "Os campos obrigatórios estão marcados com um asterisco (*)", + "K8VERSION": "Versão K8", + "ENTER": "Entrar", + "SWITCHPROJECT": "Switch Project", + "CURRENTPROJECT": "Projeto atual", + "SUBMIT": "Enviar", + "REFRESH": "Atualizar", + "OPEN": "Aberto", + "UPLOADCONFIG": "Upload Config", + "FILEUPLOADLABEL": "Ou carregue do arquivo", + "CONFIG": "Config", + "YAMLCONFIG": "Yaml Config", + "CHOOSEFILE": "Escolher arquivo", + "INVALIDCONFIG": "Configuração inválida", + "PAGE": { + "DASHBOARD": { + "DASHBOARD": "painel de controle", + "RECENTUSERLOG": "Registro recente do usuário", + "LOGS": "Logs", + "FAILEDINSTANCES": "Instâncias com falha", + "NOINSTANCES": "Keine Instanzen verfügbar", + "UPTIME": "Tempo de atividade", + "RUNNINGINSTANCES": "Instâncias em execução", + "NETSLICETEMPLATE": "Modelo de fatia líquida", + "NETSLICEINSTANCE": "Instâncias de fatia líquida", + "USERS": "Comercial", + "PROJECTS": "Projetos", + "USERSETTINGS": "Configurações do usuário", + "LOGOUT": "Sair" + }, + "LOGIN": { + "USERNAME": "Nome de usuário", + "PASSWORD": "Senha", + "SIGNUP": "Inscrever-se", + "ACCOUNTCREATEMESSAGE": "Não possui uma conta?", + "LOGIN": "entrar", + "PASSWORDVALIDMESSAGE": "Senha requerida", + "USERNAMEVALIDMESSAGE": "Nome de usuário é requerido", + "SIGNINMSG": "Faça login para iniciar sua sessão", + "PASSWORDMINLENGTHVALIDMESSAGE": "A senha deve ter 8 caracteres e conter pelo menos um caractere maiúsculo, minúsculo, numérico e especial", + "USERNAMEMINLENGTHVALIDMESSAGE": "O nome de usuário deve ter pelo menos 5 caracteres" + }, + "INSTANCEINSTANTIATE": { + "NEWINSTANCE": "Nova Instância", + "NSNAME": "Ns Name", + "DESCRIPTION": "Descrição", + "NSID": "ID Nsd", + "SSHKEY": "Chave SSH", + "VIMACCOUNT": "Conta VIM", + "SSHKEYMSG": "Cole sua chave aqui" + }, + "NSMETRIC": { + "INSTANCESMETRIC": "Métrica de Instâncias", + "METRICERROR": "Dados não disponíveis em métricas" + }, + "USERSETTINGS": { + "LANGUAGE": "Língua" + }, + "VIM": { + "CREATEDSUCCESSFULLY": "VIM criado com sucesso", + "LOACTIONINFO": "Digite o nome do local e clique no botão Enter para selecionar o local na lista" + }, + "VIMDETAILS": { + "NEWVIM": "Novo VIM", + "VIMACCOUNTDETAILS": "Detalhes da conta VIM", + "NAME": "Nome", + "VIMUSERNAME": "Nome de usuário do VIM", + "VIMURL": "URL do VIM", + "VIMTYPE": "Tipo", + "TENANTNAME": "Nome do inquilino", + "DESCRIPTION": "Descrição", + "SCHEMATYPE": "Tipo de esquema", + "SCHEMAVERSION": "Versão do esquema", + "CONFIGPARAMETERS": "PARÂMETROS CONFIG", + "SDNCONTROLLER": "Controlador SDN", + "SDNPORTMAPPING": "Mapeamento de porta SDN", + "VIMNETWORKNAME": "Nome da rede VIM", + "SECURITYGROUPS": "Grupos de Segurança", + "AVAILABILITYZONE": "Zona de disponibilidade", + "REGIONALNAME": "Nome da região", + "INSECURE": "Insegura", + "USEEXISTINGFLAVOURS": "Use sabores existentes", + "USEINTERNALENDPOINT": "Usar terminal interno", + "APIVERSION": "Versão da API", + "PROJECTDOMAINID": "ID do domínio do projeto", + "PROJECTDOMAINNAME": "Nome de domínio do projeto", + "USERDOMAINID": "ID do domínio do usuário", + "USERDOMAINUSER": "Nome de domínio do usuário", + "KEYPAIR": "Par de chaves", + "DATAPLANEPHYSICALNET": "Rede física do plano de dados", + "USEFLOATINGIP": "Use ip flutuante", + "DATAPLANENETVLANRANGE": "Dataplane net vlan range", + "MICROVERSION": "Microversão", + "BACKTOVIMACCOUNTS": "Voltar para VimAccounts", + "VIMPASSWORD": "Senha do VIM", + "ADDITIONALCONFIG": "Configuração adicional", + "ADDITIONALCONFIGPLACEHOLDER": "{'key1':[...],'key2':{},'key3':''}", + "NEWVIMACCOUNT": "Nova conta VIM", + "ORGNAME": "Orgnome", + "VCENTERIP": "Vcenter ip", + "VCENTERPORT": "Porta Vcenter", + "ADMINUSERNAME": "Nome de usuário do administrador", + "VCENTERUSER": "Usuário do Vcenter", + "ADMINPASSWORD": "senha do administrador", + "VCENTERPASSWORD": "Senha do Vcenter", + "NSXMANAGER": "Gerente Nsx", + "VROPSSITE": "Site Vrops", + "NSXUSER": "Usuário Nsx", + "VROPSUSER": "Usuário Vrops", + "NSXPASSWORD": "Senha Nsx", + "VROPSPASSWORD": "Senha Vrops", + "VPCCIDRBLOCK": "Bloco cidr VPC", + "FLAVORIINFO": "Informação do sabor", + "VIM_TYPE": "Tipo VIM", + "VIMLOCATION": "Localização do VIM", + "SUBSCRIPTIONID": "ID de Inscrição", + "RESOURCEGROUP": "Grupo de Recursos", + "VNETNAME": "Nome da VNet", + "FLAVORSPATTERN": "Padrão de sabores" + }, + "WIMACCOUNTS": { + "CREATEDSUCCESSFULLY": "WIM criado com sucesso", + "WIMDETAILS": "Detalhes do WIM", + "NEWWIM": "Novo WIM", + "SCHEMAVERSION": "Versão do esquema", + "RO": "RO", + "ROACCOUNT": "Conta RO", + "USERNAME": "Nome de usuário WIM", + "PASSWORD": "Senha WIM" + }, + "NSINSTANCE": { + "NEWNSINSTANCE": "Nova NS", + "CREATEDSUCCESSFULLY": "Instância NS criada com êxito" + }, + "VNFINSTANCE": { + "ADDVNFINSTANCE": "Adicionar instância VNF" + }, + "PDUINSTANCE": { + "NEWPDUINSTANCE": "Nova PDU", + "PDUTYPE": "Tipo de PDU", + "PARAMETERS": "Parâmetros de instâncias da PDU", + "ADDINSTANCEPARAMS": "Adicionar parâmetros", + "CREATEDSUCCESSFULLY": "Instâncias da PDU criadas com êxito" + }, + "NETSLICEINSTANCE": { + "CREATENETSLICEINSTANCE": "Criar NSI" + }, + "SDNCONTROLLER": { + "NEWSDNCONTROLLER": "Novo controlador SDN", + "REGISTEREDSDNCONTROLLER": "Controladores SDN registrados", + "RO": "RO", + "DPID": "DPID", + "CREATEDSUCCESSFULLY": "SDN Registrado com Sucesso", + "DPIDPLACEHOLDER": "xx:xx:xx:xx:xx:xx:xx:xx", + "DETAILS": "Detalhes do Controlador SDN" + }, + "USERS": { + "CREATEUSER": "Criar usuário", + "NEWUSER": "Novo usuário", + "USERNAME": "Nome de Usuário", + "PASSWORD": "Senha", + "CONFPASSWORD": "Confirme a Senha", + "EDITUSER": "Editar usuário", + "NEWPASSWORD": "Nova senha", + "DEFAULTPROJECT": "Projeto Padrão", + "PASSWORDCONFLICT": "Senha e confirmação de senha não correspondem", + "PASSWORDMATCH": "Correspondência de senha", + "CREATEDSUCCESSFULLY": "Usuário criado com sucesso", + "EDITEDSUCCESSFULLY": "Edição do Usuário com Sucesso", + "EDITCREDENTIALS": "Mudar senha", + "EDITUSERNAME": "Mudar nome de usuário", + "PROJECTSROLES": "Funções dos Projetos", + "EDITPROJECTROLEMAPPING": "Editar mapeamento de função do projeto", + "ADDMAPPINGS": "Adicionar mapeamentos", + "EDITPROJECTROLEERROR": "Forneça pelo menos um mapeamento de função do projeto para continuar" + }, + "TOPOLOGY": { + "SELECTELEMENT": "Selecionar elemento", + "VL": "VL", + "VNF": "VNF", + "VNFD": "VNFD", + "CP": "CP", + "NSD": "NSD", + "NS": "NS", + "VIRTUALLINK": "Link virtual", + "CONNECTIONPOINT": "Ponto de conexão", + "INTCONNECTIONPOINT": "Ponto de conexão int", + "LINK": "Ligação", + "ADDINGCP": "Por favor, selecione um ponto de conexão {{vnfdname}} para vincular {{vlname}}?", + "INFO": "Info", + "HELP": "Socorro", + "HELPINFO": { + "CREATEEDGE": "Criar aresta", + "CREATEEDGEFIRSTSETENCE": "Selecione o primeiro vértice clicando nele usando", + "CREATEEDGESECONDSETENCE": "em outro vértice (diferente do selecionado).", + "DELETEEDGEVERTEX": "Excluir aresta / vértice", + "DELETEEDGEVERTEXSENTENCE": "Clicar duas vezes na aresta / vértice.", + "SPREADEDGE": "Espalhe a borda", + "SPREADEDGESENTENCE": "Selecione o vértice clicando nele usando", + "EDGEINFO": "Mostrar informações da aresta", + "EDGEINFOSENTENCE": "Selecione a aresta clicando. A informação será mostrada no lado esquerdo." + }, + "VDU": "VDU", + "INTVL": "IntVL", + "INTCP": "IntCP", + "DATAEMPTY": "Por favor mude algo" + }, + "PROJECT": { + "NEWPROJECT": "Novo projeto", + "CREATEDSUCCESSFULLY": "Projeto criado com sucesso", + "UPDATEDSUCCESSFULLY": "Projeto atualizado com sucesso" + }, + "NSPACKAGE": { + "ADDNSPACKAGE": "Componha um novo NS", + "CREATEDSUCCESSFULLY": "Pacote NS criado com sucesso", + "NSCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Atualizado com sucesso", + "CONFIRMCONNECTIONPOINT": "Confirme para adicionar o ponto de conexão", + "CANNOTLINKVNF": "Você não pode vincular um vnf a um vnf", + "CANNOTLINKVL": "Você não pode vincular uma VL a uma VL", + "CANNOTLINKVLVNF": "Você não pode vincular um VL a um vnf", + "CANNOTLINKVNFCP": "Você não pode vincular um VNF a um CP", + "CANNOTLINKVLCP": "Você não pode vincular uma VL a um CP", + "CANNOTLINKCP": "Você não pode vincular um CP a um CP", + "ADDNSD": "Link virtual adicionado com sucesso", + "ADDVNFD": "VNFD é adicionado com sucesso", + "ADDNS": "Link de conexão adicionado com sucesso", + "DELETENSD": "O link virtual foi excluído com sucesso", + "DELETEVNFD": "O VNF foi excluído com sucesso", + "DELETENS": "Excluído com êxito o ponto de conexão", + "DELETELINK": "O link foi excluído com sucesso", + "MGMTNETWORK": "Mgmt Network", + "VIMNETWORKNAME": "Vim Network Name", + "MEMBER-VNF-INDEX": "member-vnf-index", + "VNFD-ID-REF": "vnfd-id-ref", + "VLD-ID": "vld-id", + "VNFD-CP-REF": "vnfd-ponto de conexão-ref" + }, + "EDITPACKAGES": { + "UPDATEDSUCCESSFULLY": "Atualizado com sucesso" + } + }, + "VNFPACKAGE": { + "ADDVNFPACKAGE": "Componha um novo VNF", + "CREATEDSUCCESSFULLY": "Pacote VNF criado com sucesso", + "VNFCOMPOSE": { + "UPDATEDSUCCESSFULLY": "Atualizado com sucesso", + "INVALIDSELECTION": "Seleção inválida", + "YOUCANNOTDELETELINK": "Você não pode excluir o link", + "CANNOTLINKVDUANDINTCP": "Você não pode vincular o vdu ao int_cp", + "CANNOTLINKINTCPANDVDU": "Você não pode vincular int_cp ao vdu", + "CANNOTLINKCPANDVNFVL": "Você não pode vincular o cp ao vnf_vl", + "CANNOTLINKVNFVLANDCP": "Você não pode vincular vnf_vl ao cp", + "CANNOTLINKINTCPANDCP": "Você não pode vincular o intcp ao cp", + "CANNOTLINKCPANDINTCP": "Você não pode vincular o cp ao int_cp", + "CANNOTLINKVDUANDVDU": "Você não pode vincular um vdu a um vdu" + } + }, + "NETSLICE": { + "CREATEDSUCCESSFULLY": "Netslice criado com sucesso", + "TEMPLATECREATEDSUCCESSFULLY": "Modelo Netslice criado com sucesso", + "UPDATEDSUCCESSFULLY": "Modelo atualizado com sucesso" + }, + "NETSLICETEMPLATE": { + "NETSLICETEMPLATEDETAILS": "Detalhes do modelo de fatias de rede" + }, + "NSTINSTANCEINSTANTIATE": { + "NEWINSTANCE": "Nova Instância", + "NSNAME": "Ns Name", + "DESCRIPTION": "Descrição", + "NSTID": "Nst Id", + "SSHKEY": "Chave SSH", + "VIMACCOUNT": "Conta VIM", + "SSHKEYMSG": "Cole sua chave aqui ..." + }, + "NSPRIMITIVE": { + "PRIMITIVE": "Primitiva", + "PRIMITIVEPARAMETERS": "Parâmetros primitivos", + "ADDPRIMITIVEPARAMS": "Adicionar Parâmetros Primitivos", + "EXECUTEDSUCCESSFULLY": "Configuração primitiva do NS executada" + }, + "ROLES": { + "CREATEROLE": "Criar função", + "ROLE": "Função", + "PERMISSIONS": "Permissões", + "YAMLPERMISSIONS": "YAML Permissões", + "CREATEDSUCCESSFULLY": "Função criada com sucesso", + "UPDATEDSUCCESSFULLY": "Função atualizada com sucesso", + "ROLEJSONERROR": "As permissões de função devem ser fornecidas de maneira com valor-chave", + "ROLEKEYERROR": "O valor de '{{roleKey}}' nas permissões de uma função deve ser booleano", + "EDITROLE": "Editar função", + "PREVIEW": "Pré-visualização", + "TEXTVIEW": "Visualização de texto" + }, + "K8S": { + "MENUK8S": "K8s", + "MENUK8SCLUSTER": "Clusters do K8s", + "MENUK8SREPO": "Repos do K8s", + "REGISTERK8CLUSTER": "Clusters K8s registrados", + "ADDK8CLUSTER": "Adicionar cluster do K8s", + "K8SCLUSTERDETAILS": "Detalhes do cluster K8s", + "REGISTERK8REPO": "Repositório registrado do K8s", + "ADDK8REPO": "Adicionar repositório K8s", + "K8SREPODETAILS": "Detalhes do Repositório do K8s", + "CREATEDSUCCESSFULLY": "K8s criado com sucesso", + "NEWK8SCLUSTER": "Novo Cluster K8s", + "NAME": "Nome", + "K8SVERSION": "Versão do K8s", + "VIMACCOUNT": "Conta Vim", + "DESCRIPTION": "Descrição", + "NETS": "Nets", + "NETSPLACEHOLDER": "example: {'net1': 'osm-ext'}", + "CREDENTIALS": "Credenciais", + "NEWK8SREPO": "Novo Repositório do K8s", + "TYPE": "Tipo", + "URL": "URL" + } + }, + "HTTPERROR": { + "401": "Acesso negado", + "400": "Verifique a solicitação e tente novamente", + "404": "Serviço esperado não disponível, tente novamente mais tarde", + "500": "Erro no servidor, tente novamente mais tarde", + "502": "Gateway incorreto. Tente novamente mais tarde", + "503": "Serviço temporariamente indisponível. Tente novamente mais tarde", + "504": "Erro de tempo limite do gateway. Tente novamente mais tarde", + "409": "Por favor, tente novamente mais tarde" + }, + "PAGENOTFOUND": { + "OOPS": "Opa!", + "NOTFOUND": "404 não encontrado", + "CONTENT": "A página não pode ser encontrada ou não autorizada, pode não ser mais relevante ou seu nome foi alterado", + "MEAN": "Enquanto isso, você pode voltar para", + "HOME": "Casa" + }, + "DOMVALIDATIONS": { + "INVALIDURL": "Digite um URL válido", + "INVALIDIPADDRESS": "Digite um endereço IP válido", + "INVALIDPORTADDRESS": "Digite um endereço PORT válido", + "INVALIDDPID": "Digite um DPID válido", + "INVALIDJSON": "Digite um formato JSON válido", + "INVALIDYAML": "Digite um formato YAML válido" + }, + "GRAFANA": { + "METRICSERROR": "Métricas não válidas" + } +} \ No newline at end of file diff --git a/src/assets/images/CP-VNF.svg b/src/assets/images/CP-VNF.svg new file mode 100644 index 0000000..26163da --- /dev/null +++ b/src/assets/images/CP-VNF.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/CP.svg b/src/assets/images/CP.svg new file mode 100644 index 0000000..7ed1b03 --- /dev/null +++ b/src/assets/images/CP.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/INTCP.svg b/src/assets/images/INTCP.svg new file mode 100644 index 0000000..773134a --- /dev/null +++ b/src/assets/images/INTCP.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/INTVL.svg b/src/assets/images/INTVL.svg new file mode 100644 index 0000000..33fcce3 --- /dev/null +++ b/src/assets/images/INTVL.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/TICK.svg b/src/assets/images/TICK.svg new file mode 100644 index 0000000..4675aad --- /dev/null +++ b/src/assets/images/TICK.svg @@ -0,0 +1,29 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/VDU.svg b/src/assets/images/VDU.svg new file mode 100644 index 0000000..7dc6540 --- /dev/null +++ b/src/assets/images/VDU.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/VL.svg b/src/assets/images/VL.svg new file mode 100644 index 0000000..6361c01 --- /dev/null +++ b/src/assets/images/VL.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/VNFD.svg b/src/assets/images/VNFD.svg new file mode 100644 index 0000000..86b7fc8 --- /dev/null +++ b/src/assets/images/VNFD.svg @@ -0,0 +1,26 @@ + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/images/login_background.jpg b/src/assets/images/login_background.jpg new file mode 100644 index 0000000..dc1411d Binary files /dev/null and b/src/assets/images/login_background.jpg differ diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000..7de447c Binary files /dev/null and b/src/assets/images/logo.png differ diff --git a/src/assets/images/map-icon.png b/src/assets/images/map-icon.png new file mode 100644 index 0000000..e2e9f75 Binary files /dev/null and b/src/assets/images/map-icon.png differ diff --git a/src/assets/images/page-not-found.jpg b/src/assets/images/page-not-found.jpg new file mode 100644 index 0000000..794c0fc Binary files /dev/null and b/src/assets/images/page-not-found.jpg differ diff --git a/src/assets/js/tar.js b/src/assets/js/tar.js new file mode 100644 index 0000000..058d1ee --- /dev/null +++ b/src/assets/js/tar.js @@ -0,0 +1,432 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +var Tar = +/******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) { +/******/ return installedModules[moduleId].exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ i: moduleId, +/******/ l: false, +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.l = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // identity function for calling harmony imports with the correct context +/******/ __webpack_require__.i = function(value) { return value; }; +/******/ +/******/ // define getter function for harmony exports +/******/ __webpack_require__.d = function(exports, name, getter) { +/******/ if(!__webpack_require__.o(exports, name)) { +/******/ Object.defineProperty(exports, name, { +/******/ configurable: false, +/******/ enumerable: true, +/******/ get: getter +/******/ }); +/******/ } +/******/ }; +/******/ +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function getDefault() { return module['default']; } : +/******/ function getModuleExports() { return module; }; +/******/ __webpack_require__.d(getter, 'a', getter); +/******/ return getter; +/******/ }; +/******/ +/******/ // Object.prototype.hasOwnProperty.call +/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(__webpack_require__.s = 2); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports) { + +/* + * tar-js + * MIT (c) 2011 T. Jameson Little + */ + +(function () { + "use strict"; + + var lookup = [ + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', + 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', + 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', + 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', + 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', + 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', + 'w', 'x', 'y', 'z', '0', '1', '2', '3', + '4', '5', '6', '7', '8', '9', '+', '/' + ]; + function clean(length) { + var i, buffer = new Uint8Array(length); + for (i = 0; i < length; i += 1) { + buffer[i] = 0; + } + return buffer; + } + + function extend(orig, length, addLength, multipleOf) { + var newSize = length + addLength, + buffer = clean((parseInt(newSize / multipleOf) + 1) * multipleOf); + + buffer.set(orig); + + return buffer; + } + + function pad(num, bytes, base) { + num = num.toString(base || 8); + return "000000000000".substr(num.length + 12 - bytes) + num; + } + + function stringToUint8 (input, out, offset) { + var i, length; + + out = out || clean(input.length); + + offset = offset || 0; + for (i = 0, length = input.length; i < length; i += 1) { + out[offset] = input.charCodeAt(i); + offset += 1; + } + + return out; + } + + function uint8ToBase64(uint8) { + var i, + extraBytes = uint8.length % 3, // if we have 1 byte left, pad 2 bytes + output = "", + temp, length; + + function tripletToBase64 (num) { + return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F]; + }; + + // go through the array every three bytes, we'll deal with trailing stuff later + for (i = 0, length = uint8.length - extraBytes; i < length; i += 3) { + temp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]); + output += tripletToBase64(temp); + } + + // this prevents an ERR_INVALID_URL in Chrome (Firefox okay) + switch (output.length % 4) { + case 1: + output += '='; + break; + case 2: + output += '=='; + break; + default: + break; + } + + return output; + } + + module.exports.clean = clean; + module.exports.pad = pad; + module.exports.extend = extend; + module.exports.stringToUint8 = stringToUint8; + module.exports.uint8ToBase64 = uint8ToBase64; +}()); + + +/***/ }), +/* 1 */ +/***/ (function(module, exports, __webpack_require__) { + +/* + * tar-js + * MIT (c) 2011 T. Jameson Little + */ + +(function () { + "use strict"; + +/* +struct posix_header { // byte offset + char name[100]; // 0 + char mode[8]; // 100 + char uid[8]; // 108 + char gid[8]; // 116 + char size[12]; // 124 + char mtime[12]; // 136 + char chksum[8]; // 148 + char typeflag; // 156 + char linkname[100]; // 157 + char magic[6]; // 257 + char version[2]; // 263 + char uname[32]; // 265 + char gname[32]; // 297 + char devmajor[8]; // 329 + char devminor[8]; // 337 + char prefix[155]; // 345 + // 500 +}; +*/ + + var utils = __webpack_require__(0), + headerFormat; + + headerFormat = [ + { + 'field': 'fileName', + 'length': 100 + }, + { + 'field': 'fileMode', + 'length': 8 + }, + { + 'field': 'uid', + 'length': 8 + }, + { + 'field': 'gid', + 'length': 8 + }, + { + 'field': 'fileSize', + 'length': 12 + }, + { + 'field': 'mtime', + 'length': 12 + }, + { + 'field': 'checksum', + 'length': 8 + }, + { + 'field': 'type', + 'length': 1 + }, + { + 'field': 'linkName', + 'length': 100 + }, + { + 'field': 'ustar', + 'length': 8 + }, + { + 'field': 'owner', + 'length': 32 + }, + { + 'field': 'group', + 'length': 32 + }, + { + 'field': 'majorNumber', + 'length': 8 + }, + { + 'field': 'minorNumber', + 'length': 8 + }, + { + 'field': 'filenamePrefix', + 'length': 155 + }, + { + 'field': 'padding', + 'length': 12 + } + ]; + + function formatHeader(data, cb) { + var buffer = utils.clean(512), + offset = 0; + + headerFormat.forEach(function (value) { + var str = data[value.field] || "", + i, length; + + for (i = 0, length = str.length; i < length; i += 1) { + buffer[offset] = str.charCodeAt(i); + offset += 1; + } + + offset += value.length - i; // space it out with nulls + }); + + if (typeof cb === 'function') { + return cb(buffer, offset); + } + return buffer; + } + + module.exports.structure = headerFormat; + module.exports.format = formatHeader; +}()); + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + +/* + * tar-js + * MIT (c) 2011 T. Jameson Little + */ + +(function () { + "use strict"; + + var header = __webpack_require__(1), + utils = __webpack_require__(0), + recordSize = 512, + blockSize; + + function Tar(recordsPerBlock) { + this.written = 0; + blockSize = (recordsPerBlock || 20) * recordSize; + this.out = utils.clean(blockSize); + } + + Tar.prototype.append = function (filepath, input, opts, callback) { + var data, + checksum, + mode, + mtime, + uid, + gid, + headerArr; + + if (typeof input === 'string') { + input = utils.stringToUint8(input); + } else if (input.constructor !== Uint8Array.prototype.constructor) { + throw 'Invalid input type. You gave me: ' + input.constructor.toString().match(/function\s*([$A-Za-z_][0-9A-Za-z_]*)\s*\(/)[1]; + } + + if (typeof opts === 'function') { + callback = opts; + opts = {}; + } + + opts = opts || {}; + + mode = opts.mode || parseInt('777', 8) & 0xfff; + mtime = opts.mtime || Math.floor(+new Date() / 1000); + uid = opts.uid || 0; + gid = opts.gid || 0; + + data = { + fileName: filepath, + fileMode: utils.pad(mode, 7), + uid: utils.pad(uid, 7), + gid: utils.pad(gid, 7), + fileSize: utils.pad(input.length, 11), + mtime: utils.pad(mtime, 11), + checksum: ' ', + type: opts.type || '0', + ustar: 'ustar ', + owner: opts.owner || '', + group: opts.group || '' + }; + + // calculate the checksum + checksum = 0; + Object.keys(data).forEach(function (key) { + var i, value = data[key], length; + + for (i = 0, length = value.length; i < length; i += 1) { + checksum += value.charCodeAt(i); + } + }); + + data.checksum = utils.pad(checksum, 6) + "\u0000 "; + + headerArr = header.format(data); + + var i, offset, length; + + this.out.set(headerArr, this.written); + + this.written += headerArr.length; + + // If there is not enough space in this.out, we need to expand it to + // fit the new input. + if (this.written + input.length > this.out.length) { + this.out = utils.extend(this.out, this.written, input.length, blockSize); + } + + this.out.set(input, this.written); + + // to the nearest multiple of recordSize + this.written += input.length + (recordSize - (input.length % recordSize || recordSize)); + + // make sure there's at least 2 empty records worth of extra space + if (this.out.length - this.written < recordSize * 2) { + this.out = utils.extend(this.out, this.written, recordSize * 2, blockSize); + } + + if (typeof callback === 'function') { + callback(this.out); + } + + return this.out; + }; + + Tar.prototype.clear = function () { + this.written = 0; + this.out = utils.clean(blockSize); + }; + + module.exports = Tar; +}()); + + +/***/ }) +/******/ ]); \ No newline at end of file diff --git a/src/assets/scss/app.scss b/src/assets/scss/app.scss new file mode 100644 index 0000000..bc8a216 --- /dev/null +++ b/src/assets/scss/app.scss @@ -0,0 +1,688 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** Styles for the application **/ +@import "../../assets/scss/mixins/mixin"; +@import "../../assets/scss/variable"; +$customnavbar-padding-x: ($spacer / 0.5) !default; +* { + outline: 0; +} +button[type=submit]:focus, .sidebar-body button[type=button]:focus { + @include box-shadow(0, 0, 0, 0.2rem, lighten($primary, 50%) !important); +} +.btn-danger:focus{ + @include box-shadow(0, 0, 0, 0.2rem, lighten($danger, 30%) !important); +} +body, +.list-overflow, +.scroll-box, +.smarttable-style, +.modal-body-custom-height, +.layout-wrapper, .CodeMirror-vscrollbar, .ng-sidebar, .runninginstances .popover-body { + &::-webkit-scrollbar { + @include wh-value(10px, null); + } + &::-webkit-scrollbar-thumb { + background-clip: content-box; + @include border(all, 3, solid, transparent); + @include roundedCorners(7); + @include box-shadow(0, 0, 0, 10px, rgba($black, 0.8), inset); + } + &::-webkit-scrollbar-button { + @include wh-value(0, 0); + @include flexbox(none, null, null, null, null, null); + } + &::-webkit-scrollbar-corner { + @include background(null, transparent, null, null, null); + } +} +body { + @include font-family("Roboto"); + @include background(null, $theme-bg-color, null, null, null); + overflow-x: hidden; + .osm-logo { + @include wh-value(100px, auto); + } + .bg-light { + @include background(null, $theme-bg-color !important, null, null, null); + } + a { + color: $primary; + &:hover, + &:focus { + text-decoration: none; + } + } + .badge { + @include line-height(normal); + &.badge-pill { + @include padding-percentage-value(0.2em, 0.6em, 0.2em, 0.6em); + } + } + button { + outline: none; + @include box-shadow(0, 0, 0, 0, transparent); + &:hover, + &:focus, + &:active { + outline: none; + @include box-shadow(0, 0, 0, 0, transparent !important); + } + &.btn-primary, + &.btn-default, + &.btn-warning, + &.btn-outline-primary:hover, + &.btn-outline-warning:hover { + color: $white; + &:hover, + &:focus, + &:not(:disabled):not(.disabled):active { + color: $white; + @include background(null, $primary, null, null, null); + border-color: $primary; + } + &:disabled { + cursor: not-allowed; + } + } + } + .row { + margin-left: 0; + margin-right: 0; + } + .navbar { + @include padding-percentage-value( + $navbar-padding-y, + $customnavbar-padding-x, + $navbar-padding-y, + $customnavbar-padding-x + ); + } + .form-control { + @include roundedCorners(4); + @include font(null, 12px, null); + &::placeholder { + color: $gray-400; + } + } + .modal-dialog { + max-width: 600px; + } + .header-style { + @include font(null, 1.2rem, 700); + color: $primary; + @include line-height(1.25); + } + .cursor-default { + cursor: default; + } + .cursor-pointer { + cursor: pointer; + } + .mr-top-5 { + @include margin-value-percentage(5px, auto, auto, auto); + } + .padLeft0 { + padding-left: 0px; + } + .padRight0 { + padding-right: 0px; + } + .mandatory-label { + @include font(null, 10px, null); + } + .dropzone { + min-height: 50px; + @include flexbox(table, null, null, null, null, null); + @include wh-value(100%, 50px); + @include border(all, 1, dashed, $secondary); + cursor: pointer; + .text-wrapper { + @include padding-value(5, 5, 5, 5); + @include flexbox(table-cell, null, null, null, null, null); + vertical-align: middle; + } + .file-drop-title { + @include font(null, 16px, null); + } + } + .close { + opacity: 1 !important; + } + .roles-section { + .card { + .bg-secondary { + @include background(null, $gray-400 !important, null, null, null); + } + } + } + .card { + margin-bottom: 1rem; + } + .custom-card { + @include border(top, 3, solid, $primary); + @include roundedCorners(3); + .custom-card-body { + @include padding-value(15, 15, 15, 15); + } + } + table-cell-default-editor select-editor select { + @include wh-value(null, calc(2rem + 8px) !important); + @include padding-value(0, 10, 0, 10); + } + .CodeMirror { + min-height: 400px !important; + } + .table-layout-fixed { + table-layout: fixed; + word-wrap: break-word; + } + .border-radius-default { + @include roundedCorners(3); + } + /** Model Popup-Design **/ + .modal-body-custom-height { + max-height: 65vh; + overflow-y: auto; + } + /** Hide input clear icon in IE */ + input::-ms-clear { + @include flexbox(none, null, null, null, null, null); + } + /** Overwrite the tooltip z-index */ + .tooltip { + z-index: 1010; + } + /** Popover Header **/ + .popover-header { + color: $primary; + @include background(null, $theme-bg-color, null, null, null); + } + /** Vim Show running instance Details **/ + .runninginstances{ + width:200px; + .popover-body{ + max-height: 200px; + overflow-y: scroll; + } + } + /****************************************************************************/ + /************************** Smart table custom design ***********************/ + /****************************************************************************/ + ng2-smart-table { + @include font(null, 15px, null); + color: $gray-700; + .form-control { + @include wh-value(null, auto); + } + &.dataTables_empty td { + text-align: center; + } + ng2-smart-table-title { + * { + @include font(null, 12px, null); + } + a { + color: $gray-700 !important; + @include flexbox(block, null, null, null, null, null); + text-decoration: none; + &::after { + content: "\f0dc" !important; + @include font-family("Font Awesome 5 Free"); + float: right; + color: $gray-500; + @include wh-value(0, 0); + } + &.asc::after { + content: "\f0de" !important; + @include font-family("Font Awesome 5 Free"); + float: right; + color: $gray-500; + } + &.desc::after { + content: "\f0dd" !important; + @include font-family("Font Awesome 5 Free"); + float: right; + color: $gray-500; + } + &:hover { + text-decoration: none !important; + } + &.sort.desc::after { + transform: none !important; + margin-bottom: 0; + } + &.sort.asc::after, + &.sort.desc::after { + content: ""; + @include flexbox(inline-block, null, null, null, null, null); + @include wh-value(0, 0); + @include border(all, 0, solid, transparent !important); + margin-bottom: 0 !important; + } + } + span { + color: $gray-700; + } + } + ng2-smart-table-cell { + word-break: break-word; + table-cell-view-mode { + @include font(null, 12px, null); + .icon-label { + @include font(null, 20px, null); + @include flexbox(inline-block, null, null, null, null, null); + @include wh-value(100px, 0); + text-align: center; + cursor: default; + } + } + } + .ng2-smart-filter { + @include wh-value(null, calc(2rem + 2px) !important); + @include font(null, 12px, null); + margin-top: 6px; + } + table.list-data { + tr td, + tr th { + @include padding-value(2, 10, 2, 10); + vertical-align: middle !important; + } + tbody { + tr.selected { + background: none !important; + } + } + } + default-table-filter { + select-filter { + select.form-control { + @include flexbox(inline-block, null, null, null, null, null); + @include wh-value(null, calc(1.5rem + 2px) !important); + vertical-align: middle; + background: $white + url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='%23343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") + no-repeat right 0.75rem center; + background-size: 8px 10px; + @include border(all, 1, solid, $gray-200); + @include roundedCorners(2); + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + &::-ms-expand { + visibility: hidden; + } + } + } + select-filter { + select { + @include roundedCorners(4); + } + } + input-filter { + input[type="text"] { + @include position_value(relative, null, null, null, null); + } + &:after { + @include position_value(relative, -26px, null, null, 100%); + content: "\f002"; + @include font("Font Awesome 5 Free", 10px, null); + @include padding-value(0, 0, 0, 2); + color: $gray-500; + } + } + } + ng2-smart-table-pager { + @include flexbox(null, null, row-reverse, null, null, null); + @include padding-value(5, 20, 5, 20); + .ng2-smart-pagination { + .ng2-smart-page-item { + @include font(null, 10px, null); + a { + &:hover { + text-decoration: none; + } + } + .ng2-smart-page-link { + @include font(null, 12px !important, null); + &.page-link { + text-align: center; + vertical-align: middle; + color: $primary; + @include border(all, 1, solid, $primary !important); + &:hover { + @include background(null, $primary !important, null, null, null); + color: $white; + } + } + } + span.ng2-smart-page-link.page-link { + color: $white; + @include background(null, $primary !important, null, null, null); + @include border(all, 1, solid, $primary !important); + } + } + } + } + } + /****************************************************************************/ + /*********************** Button styles under list class *********************/ + /****************************************************************************/ + .list { + &.action { + button.btn.btn-primary { + @include padding-value(2, 8, 2, 8); + } + } + button:focus { + outline: 0; + @include box-shadow(0, 0, 0, 0, transparent); + } + button.btn.btn-primary { + color: $primary; + @include background(null, $white, null, null, null); + &:not(.active:hover) { + @include background(null, $white, null, null, null); + } + &:active { + color: $primary; + @include background(null, $white, null, null, null); + } + &.action-button { + color: $white; + @include background(null, $primary !important, null, null, null); + &:hover { + @include background(null, $primary, null, null, null); + } + } + } + .dropdown-menu { + @include border(all, 1, solid, $primary); + @include padding-value(0, 0, 0, 0); + button.btn.btn-primary { + @include background(null, transparent, null, null, null); + @include padding-value(8, 8, 8, 8); + @include roundedCorners(0); + &:hover { + @include background(null, $primary, null, null, null); + color: $white; + } + &:not(:last-child) { + @include border(bottom, 1, solid, $primary); + } + } + } + } + /****************************************************************************/ + /*********************** Custom tabel design in topology ********************/ + /****************************************************************************/ + .custom-table { + td:first-child { + @include font(null, null, bold); + text-align: right; + } + th, + td { + @include padding-value(5, 7, 5, 7); + @include font(null, 10px, null); + @include line-height(15px); + } + } + /****************************************************************************/ + /************************** Ng select custom design *************************/ + /****************************************************************************/ + .ng-select { + &.is-invalid .ng-select-container { + @include border(all, 1, solid, $red); + } + .ng-select-container { + @include border(all, 1, solid, $gray-200); + .ng-value-container .ng-placeholder { + color: $gray-80; + } + } + } + /****************************************************************************/ + /******************** Custom nav section for default status *****************/ + /****************************************************************************/ + .list-utilites-actions { + @include flexbox(flex, null, row, null, center, null); + nav.custom-items-config { + @include position_value(relative, null, null, null, null); + @include roundedCorners(3); + span { + @include font(null, 13px, 600); + @include flexbox(inline-block, null, null, null, null, null); + @include position_value(relative, null, null, null, null); + text-decoration: none; + text-align: center; + @include margin-value(0, 0, 0, 10); + &:first-child { + @include margin-value(0, 0, 0, 0); + } + i { + @include font(null, 14px, null); + @include margin-value(0, 5, 0, 0); + } + } + } + } + /****************************************************************************/ + /************************* File upload custom design ************************/ + /****************************************************************************/ + .custom-file-label { + color: $primary; + @include roundedCorners(4); + @include border(all, 1, solid, $primary); + overflow: hidden; + @include margin-value(0, 0, 0, 0); + text-overflow: ellipsis; + white-space: nowrap; + padding-right: 80px; + &::after { + color: $white; + @include background(null, $primary, null, null, null); + } + } + /****************************************************************************/ + /************************* Notifier Container Design ************************/ + /****************************************************************************/ + .notifier__container { + ul { + @include margin-value(0, 0, 0, 0); + } + } + /***************************************************************************/ + /************************* Topology Common Design **************************/ + /****************************************************************************/ + .ns-composer-form, + .vnf-composer-form, + .ns-instance-form { + @include font(null, 12px, null); + .ns-svg, + .vnf-svg { + @include wh-value(30px, 25px); + } + .svg-container { + min-height: 60vh; + } + .form-control { + @include font(null, 10px, null); + } + .scroll-box { + max-height: 285px; + overflow-y: scroll; + } + .border-all { + @include border(all, 1, solid, $primary); + } + .list-group { + &.inside-svg { + .list-group-item { + @include padding-value(3.2, 8, 3.2, 8); + } + } + &.dragable { + .list-group-item { + cursor: move; + @include padding-value(4.8, 4.8, 4.8, 4.8); + @include margin-value(0, 0, 5, 0); + @include background(null, $gray-200, null, null, null); + @include flexbox(flex, null, null, null, center, null); + border: none; + .span-overflow-text { + @include wh-value(90%, null); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + @include line-height(25px); + } + } + } + } + .drag-icon { + color: $gray-600; + @include font(null, 15px, null); + } + .ctrl { + cursor: move; + } + svg { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + -o-user-select: none; + user-select: none; + image.node:hover, + circle.node:hover { + opacity: 0.7 !important; + } + image.active, + circle.active { + opacity: 0.7 !important; + } + path.link { + stroke: $dark-gray; + stroke-width: 2px; + fill: none; + &:hover { + stroke-width: 4px; + } + .dragline { + pointer-events: none; + } + } + .node_text { + text-anchor: middle; + pointer-events: none; + } + :not(.ctrl) { + cursor: pointer; + } + } + fieldset { + @include border(all, 1, solid, $primary); + legend { + @include padding-value(0, 5, 0, 5); + @include font(null, 15px, null); + color: $primary; + &.vl-legend, + &.element-legend { + @include wh-value(55%, null); + } + &.vnfd-legend { + @include wh-value(25%, null); + } + } + } + .btn-icon { + @include wh-value(36px, 36px); + text-align: center; + @include margin-value(0, 10, 10, 0); + } + .topology-btn { + color: $primary; + border-color: $primary; + &:hover, + &.pinned { + color: $white !important; + @include background(null, $primary !important, null, null, null); + } + } + .badgegroup { + @include flexbox(flex, flex-end, row, center, center, null); + } + } + .ns-topology-sidebar-container, + .vnf-topology-sidebar-container, + .ns-instance-topology-sidebar-container { + @include position_value(absolute !important, 0px, null, null, 0px); + .ng-sidebar { + @include wh-value(27%, null); + @include background(null, $white, null, null, null); + @include border(all, 1, solid, $gray-300); + .sidebar-header { + @include background(null, $modalheader-gray, null, null, null); + @include padding-value(5, 10, 5, 10); + @include border(bottom, 1, solid, $gray-300); + @include flexbox(flex, space-between, null, center, center, null); + .topology_title { + color: $primary; + } + } + .sidebar-body { + @include padding-value(10, 5, 10, 5); + } + } + .ng-sidebar__content { + button { + @include position_value(absolute, 45%, null, null, 0px); + @include background(null, $primary, null, null, null); + } + .detail-sidebar { + @include flexbox(inline-block, null, null, null, null, null); + @include position_value(relative, null, null, null, null); + animation: push 0.5s infinite linear; + } + } + @keyframes push { + 0% { + right: 0; + } + 50% { + right: -0.2em; + } + 70% { + right: -0.3em; + } + 100% { + right: 0; + } + } + } +} +/****************************************************************************/ +/************************** MEDIA QUERIES ***********************************/ +/****************************************************************************/ +@media (max-width: map-get($grid-breakpoints, md)) { + .smarttable-style { + overflow-x: auto; + white-space: nowrap; + } +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_animation.scss b/src/assets/scss/mixins/_animation.scss new file mode 100644 index 0000000..ff1d0d5 --- /dev/null +++ b/src/assets/scss/mixins/_animation.scss @@ -0,0 +1,50 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for animation property + * example for animation: @include animation(rotate 1s linear); + * example for keyframes: @include keyframes(rotate) { + 0% { @include rotate(0); } + 100% { @include rotate(359); } + } + */ + +// @mixin for animation properties +@mixin animation ($animation) { + -webkit-animation: #{$animation}; + -moz-animation: #{$animation}; + -ms-animation: #{$animation}; + -o-animation: #{$animation}; + animation: #{$animation}; +} + +// @mixin for keyframes properties +@mixin keyframes ($animation) { + @-webkit-keyframes #{$animation} { + @content; + } + @-moz-keyframes #{$animation} { + @content; + } + @-o-keyframes #{$animation} { + @content; + } + @keyframes #{$animation} { + @content; + } +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_background.scss b/src/assets/scss/mixins/_background.scss new file mode 100644 index 0000000..4eefcef --- /dev/null +++ b/src/assets/scss/mixins/_background.scss @@ -0,0 +1,30 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for background property + * example: @include background(url, orange, 20px, repeat, center); + */ + +// @mixin for background properties +@mixin background($url, $color, $size, $repeat, $position) { + background-image: $url; + background-color: $color; + background-size : $size; + background-repeat: $repeat; + background-position: $position; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_border.scss b/src/assets/scss/mixins/_border.scss new file mode 100644 index 0000000..7ec370e --- /dev/null +++ b/src/assets/scss/mixins/_border.scss @@ -0,0 +1,43 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for border + * example: @include border(top, 1, solid, #000); + */ + +// @mixin for border size and color +@mixin border($side, $size, $type, $color){ + @if ($side == top) { + border-top: $size+px $type $color; + } @else if ($side == right) { + border-right: $size+px $type $color; + } @else if ($side == left) { + border-left: $size+px $type $color; + } @else if ($side == bottom ) { + border-bottom: $size+px $type $color; + } @else if($side == all ){ + border: $size+px $type $color; + }@else { + @if ($size == thin){ + border: $size $type $color; + } + @else { + border: $size+px $type $color; + } + } +} diff --git a/src/assets/scss/mixins/_box-shadow.scss b/src/assets/scss/mixins/_box-shadow.scss new file mode 100644 index 0000000..d520e84 --- /dev/null +++ b/src/assets/scss/mixins/_box-shadow.scss @@ -0,0 +1,34 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for box-shadow + * example: @include box-shadow(1px, 2px, 2px, 2px, #000); + */ + +// @mixin for box shadow +@mixin box-shadow($hoff: false, $voff: false, $blur: false, $spread: false, $color: false, $inset: false) { + @if $inset { + -webkit-box-shadow:inset $hoff $voff $blur $spread $color; + -moz-box-shadow:inset $hoff $voff $blur $spread $color; + box-shadow:inset $hoff $voff $blur $spread $color; + } @else { + -webkit-box-shadow: $hoff $voff $blur $spread $color; + -moz-box-shadow: $hoff $voff $blur $spread $color; + box-shadow: $hoff $voff $blur $spread $color; + } +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_custom.scss b/src/assets/scss/mixins/_custom.scss new file mode 100644 index 0000000..c7424de --- /dev/null +++ b/src/assets/scss/mixins/_custom.scss @@ -0,0 +1,108 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains custom @mixin functions + */ + +// @mixin for container width and height +@mixin wh-value($width, $height) { + width: $width; + height: $height; +} + +// @mixin for padding values +@mixin padding-value($top, $right, $bottom, $left) { + padding: $top+px $right+px $bottom+px $left+px; +} + +// @mixin for any padding values +@mixin padding-percentage-value($top: null, $right: null, $bottom: null, $left: null) { + padding: $top $right $bottom $left; +} + +// @mixin for margin values +@mixin margin-value($top, $right, $bottom, $left) { + margin: $top+px $right+px $bottom+px $left+px; +} + +// @mixin for margin values in percentage +@mixin margin-value-percentage($top: null, $right: null, $bottom: null, $left: null) { + margin: $top $right $bottom $left; +} + +// @mixin for center-align element/container +@mixin align-center($topbottom, $width) { + margin: $topbottom auto; + width: $width; +} + +// @mixin for center-align with top and bottom margin element/container +@mixin tband-align-center($topbottom, $width, $bottommargin) { + margin: $topbottom auto $bottommargin; + width: $width; +} + +// @mixin for transform style +@mixin transform($x, $y, $z) +{ + transform: translate3d($x+px, $y+px, $z+px); + -webkit-transform: translate3d($x+px, $y+px, $z+px); +} + +// @mixin for font-family setting +@mixin font-family($font){ + font-family: $font; +} + +// @mixin for font-style setting +@mixin font-style($font-style){ + font-style: $font-style; +} + +// Mixin for font & its attributes +@mixin font($family, $size, $weight) { + font-family: $family; + font-size: $size; + font-weight: $weight; +} + +// @mixin for line-height setting +@mixin line-height($line-height){ + line-height: $line-height; +} + +// @mixin for letter-spacing setting +@mixin letter-spacing($letter-spacing){ + letter-spacing: $letter-spacing; +} + +// @mixin to manipulate placeholder attribute in input element +@mixin placeholder { + ::-webkit-input-placeholder {@content} + :-moz-placeholder {@content} + ::-moz-placeholder {@content} + :-ms-input-placeholder {@content} +} + +// mixins for user-select +@mixin user-select($select) { + @each $pre in -webkit-, -moz-, -ms-, -o- { + #{$pre + user-select}: #{$select}; + } + #{user-select}: #{$select}; + } diff --git a/src/assets/scss/mixins/_flex.scss b/src/assets/scss/mixins/_flex.scss new file mode 100644 index 0000000..faf870e --- /dev/null +++ b/src/assets/scss/mixins/_flex.scss @@ -0,0 +1,47 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin function for flex properties + * example: @include flexbox(flex, flex-start, row-reverse, center, center, flex-end); + * 1. display: flex | inline-flex + * 2. justify-content : flex-start | flex-end | center | space-between | space-around + * 3. flex-direction: row | row-reverse | column | column-reverse + * 4. align-content: flex-start | flex-end | center | space-between | space-around | stretch + * 5. align-items: flex-start | flex-end | center | baseline | stretch + * 6. align-self: auto | flex-start | flex-end | center | baseline | stretch + */ + +@mixin flexbox($display: null, $justify: null, $direction: null, $aligncontent: null, $alignitems: null, $alignself: null) { +display: $display; +justify-content: $justify; +flex-direction: $direction; +align-content: $aligncontent; +align-items: $alignitems; +align-self: $alignself; +} + +/** To set flexible length for items + * flex-grow: how much an item will grow relative to the rest of the flexible items + flex-shrink: how much an item will shrink relative to the rest of the flexible items + flex-basis: The length of the item. Legal values: "auto", "inherit", or a number followed by "%", "px", "em" + */ +@mixin flex($flex-grow: null, $flex-shrink: null, $flex-basis: null){ + flex-grow: $flex-grow; + flex-shrink: $flex-shrink; + flex-basis: $flex-basis; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_font-weight.scss b/src/assets/scss/mixins/_font-weight.scss new file mode 100644 index 0000000..2210f08 --- /dev/null +++ b/src/assets/scss/mixins/_font-weight.scss @@ -0,0 +1,43 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for font-weight + * example: @include fontWeight(600); (OR) @include fontWeight(semi-bold); + */ + +// @mixin for font weight +@mixin fontWeight($weight){ + $weights: ( + thin: 100, + extra-light: 200, + light: 300, + regular: 400, + medium: 500, + semi-bold: 600, + bold: 700, + extra-bold: 800, + ultra-bold: 900 + ); + + $output: $weight; + @if map-has-key($weights, $weight) { + $output: map-get($weights, $weight); + } + + font-weight: $output; + } \ No newline at end of file diff --git a/src/assets/scss/mixins/_position.scss b/src/assets/scss/mixins/_position.scss new file mode 100644 index 0000000..420f93d --- /dev/null +++ b/src/assets/scss/mixins/_position.scss @@ -0,0 +1,33 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for offset position + * @param {String} $position - Either `relative`, `absolute` or `fixed` + * @param {Length} $top [null] - Top offset + * @param {Length} $right [null] - Right offset + * @param {Length} $bottom [null] - Bottom offset + * @param {Length} $left [null] - Left offset + */ + +@mixin position_value($position, $top: null, $right: null, $bottom: null, $left: null) { + position: $position; + top: $top; + right: $right; + bottom: $bottom; + left: $left; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_rem.scss b/src/assets/scss/mixins/_rem.scss new file mode 100644 index 0000000..960132a --- /dev/null +++ b/src/assets/scss/mixins/_rem.scss @@ -0,0 +1,42 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for font + * example: @include rem("font-size", 14); + */ + +@mixin rem($property, $values...) { + $n: length($values); + $i: 1; + $pxlist: (); + $remlist: (); + @while $i <=$n { + $itemVal: (nth($values, $i)); + @if $itemVal !="auto" { + $pxlist: append($pxlist, $itemVal + px); + $remlist: append($remlist, ($itemVal / 16) + rem); + } + @else { + $pxlist: append($pxlist, auto); + $remlist: append($remlist, auto); + } + $i: $i+1; + } + #{$property}: $pxlist; + #{$property}: $remlist; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_rounded-corners.scss b/src/assets/scss/mixins/_rounded-corners.scss new file mode 100644 index 0000000..dc8f77c --- /dev/null +++ b/src/assets/scss/mixins/_rounded-corners.scss @@ -0,0 +1,96 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for border radius + * example: @include roundedCorners(10); + */ + +// Rounded Corner has equal radius +@mixin roundedCorners($size) { + border-radius: $size + px; +} + +// Rounded Corner for percentage values +@mixin roundedCornersPercentage($size) { + border-radius: $size; +} + +// Rounded Corner for Top left/right +@mixin roundedTop($size) { + border-radius: $size + px $size + px 0 0; +} + +// Rounded Corner for Top Left alone +@mixin roundedTopLeft($size) { + border-radius: $size + px 0 0 0; +} + +// Rounded Corner for Top Right alone +@mixin roundedTopRight($size) { + border-radius: 0 $size + px 0 0; +} + +// Rounded Corner for Bottom left/right +@mixin roundedBottom($size) { + border-radius: 0 0 $size + px $size + px; +} + +// Rounded Corner for Bottom Left alone +@mixin roundedBottomLeft($size) { + border-radius: 0 0 0 $size + px; +} + +// Rounded Corner for Bottom Right alone +@mixin roundedBottomRight($size) { + border-radius: 0 0 $size + px 0; +} + +// Rounded Corner for Left Top/Bottom +@mixin roundedLeft($size) { + border-radius: $size + px 0 0 $size + px; +} + +// Rounded Corner for Right Top/Bottom +@mixin roundedRight($size) { + border-radius: 0 $size + px $size + px 0; +} + +// Shorthand for all four corners rounded equally +@mixin circularCorners($size) { + border-radius: $size; +} + +// Border bottom left radius +@mixin roundedBottomLeftRadius($sive) { + border-bottom-left-radius: $sive + px; +} + +// Border bottom right radius +@mixin roundedBottomRightRadius($sive) { + border-bottom-right-radius: $sive + px; +} + +// Border top left radius +@mixin roundedTopLeftRadius($sive) { + border-top-left-radius: $sive + px; +} + +// Border top right radius +@mixin roundedTopRightRadius($sive) { + border-top-right-radius: $sive + px; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/_transform.scss b/src/assets/scss/mixins/_transform.scss new file mode 100644 index 0000000..927ddae --- /dev/null +++ b/src/assets/scss/mixins/_transform.scss @@ -0,0 +1,31 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for transform + */ + +// @mixin for 3d transform +@mixin transform_style($txsize, $tysize, $tzsize) { + transform: translate3d($txsize, $tysize, $tzsize); +} + +// @mixin for rotate transform +@mixin rotate($deg){ + transform: rotate($deg+deg); + -webkit-transform: rotate($deg+deg); +} diff --git a/src/assets/scss/mixins/_transition.scss b/src/assets/scss/mixins/_transition.scss new file mode 100644 index 0000000..743c8fb --- /dev/null +++ b/src/assets/scss/mixins/_transition.scss @@ -0,0 +1,29 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @ file contains @mixin functions for transition property + * example: @include transition(background, 1s, ease-in-out, 0); + */ + +// @mixin for transition properties +@mixin transition($property: null, $duration: null, $timing-function: null, $delay: null) { + transition-property: $property; + transition-duration: $duration; + transition-timing-function: $timing-function; + transition-delay: $delay; +} \ No newline at end of file diff --git a/src/assets/scss/mixins/mixin.scss b/src/assets/scss/mixins/mixin.scss new file mode 100644 index 0000000..e5488e1 --- /dev/null +++ b/src/assets/scss/mixins/mixin.scss @@ -0,0 +1,30 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** All mixins are imported here */ +@import '_animation'; +@import '_background'; +@import '_border'; +@import '_box-shadow'; +@import '_custom'; +@import '_flex'; +@import '_font-weight'; +@import '_position'; +@import '_rem'; +@import '_rounded-corners'; +@import '_transform'; +@import '_transition'; \ No newline at end of file diff --git a/src/assets/scss/style.scss b/src/assets/scss/style.scss new file mode 100644 index 0000000..d39843b --- /dev/null +++ b/src/assets/scss/style.scss @@ -0,0 +1,46 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/*Roboto Fonts*/ +$roboto-font-path: "~roboto-fontface/fonts" !default; +@import "~roboto-fontface/css/roboto/sass/roboto-fontface-regular"; +/*Custom mixin*/ +@import "mixins/mixin.scss"; +/*Theme setup color*/ +@import "variable"; +/*bootstrap styles*/ +@import "~bootstrap/scss/bootstrap"; +/*Custom theme styles*/ +@import "app.scss"; +/*Code Mirror styles*/ +@import "~codemirror/lib/codemirror"; +@import "~codemirror/addon/fold/foldgutter"; +@import "~codemirror/theme/neat"; +@import "~codemirror/theme/material"; +@import "~codemirror/addon/dialog/dialog"; +@import "~codemirror/addon/display/fullscreen"; +/*ng-select styles*/ +@import "~@ng-select/ng-select/themes/default.theme.css"; +/*Angular notifier styles*/ +@import "~angular-notifier/styles/core.scss"; +@import "~angular-notifier/styles/themes/theme-material.scss"; +@import "~angular-notifier/styles/themes/theme-material.scss"; +@import "~angular-notifier/styles/types/type-success.scss"; +@import "~angular-notifier/styles/types/type-error.scss"; +@import "~angular-notifier/styles/types/type-warning.scss"; +@import "~angular-notifier/styles/types/type-default.scss"; +@import "~angular-notifier/styles/types/type-info.scss"; \ No newline at end of file diff --git a/src/assets/scss/variable.scss b/src/assets/scss/variable.scss new file mode 100644 index 0000000..6a274ce --- /dev/null +++ b/src/assets/scss/variable.scss @@ -0,0 +1,265 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +// Custom Variables +$themecolor: #2962ff; +$theme-light: #fff; + +/*Topbar Colors*/ + +$topbar: $theme-light; +$topbar-height: 64px; +$topbar-navlink-padding: 0px 15px; +$topbar-navlink-font-size: 0.875rem; +$topbar-navlink-height: 64px; +$topbar-navbrand-padding: 0 10px 0 10px; +/*Sidebar Colors*/ + +$sidebar: $theme-light; +$sidebar-text: #fff; +$sidebar-icons: #fff; +$sidebar-width-full: 100px; +$sidebar-width-mini: 65px; +/*Boxed layout width*/ + +$boxed-width: 1200px; +/*Shadow*/ + +$shadow: 1px 0px 20px rgba(0, 0, 0, 0.08); +/*transitions*/ + +$transitions: 0.2s ease-in; +/*Dark transparent bg*/ + +$transparent-dark-bg: rgba(0, 0, 0, 0.05); +$lft: left; +$rgt: right; +$card-alt: #e4e9ef; +%square { + border-radius: 0px; +} + +%rotate45 { + transform: rotate(45deg); + -ms-transform: rotate(45deg); + -webkit-transform: rotate(45deg); + -o-transform: rotate(45deg); + -moz-transform: rotate(45deg); +} + +/*******************************/ + +// Bootstrap overrides +/*******************************/ + +/** + * Table Of Content + * + * 1. Color system + * 2. Options + * 3. Body + * 4. Typography + * 5. Breadcrumbs + * 6. Cards + * 7. Dropdowns + * 8. Buttons + * 9. Typography + * 10. Progress bars + * 11. Tables + * 12. Forms + * 14. Component + */ + +// +// Color system +// +$primary: #054c8c; +$secondary: #065fac; +$theme-bg-color: #eef5f9; +$breadcrumb-after-color: #002a6a; + +$white: #fff !default; +$gray-100: #f6fafe !default; +$gray-200: #e9ecef !default; +$gray-300: #dee2e6 !default; +$gray-400: #ced4da !default; +$gray-500: #afb5c1 !default; +$gray-600: #6c757d !default; +$gray-700: #4f5467 !default; +$gray-800: #343a40 !default; +$gray-900: #212529 !default; +$gray-80: #cccccc !default; +$gray-97: #f7f7f7 !default; +$medium-pink: #fb6ca4 !default; +$black-coral: #5a5c69 !default; +$cerise-pink: #e4397c !default; +$pure-red: #ff0000 !default; +$denim: #1467b3 !default; +$black: #000 !default; +$blue: #137eff !default; +$dark-gray: #aaaaaa; +$indigo: #6610f2 !default; +$purple: #8b5edd !default; +$pink: #e83e8c !default; +$red: #dd4b39 !default; +$orange: #fb8c00 !default; +$yellow: #f39c12 !default; +$green: #00a65a !default; +$teal: #20c997 !default; +$cyan: #4fc3f7 !default; +$grayish-red: #c1bfbf !default; +$white-smoke: #f1f1f1 !default; +$text-muted: $gray-500 !default; +$colors: ( + blue: $blue, + indigo: $indigo, + purple: $purple, + pink: $pink, + red: $red, + orange: $orange, + yellow: $yellow, + green: $green, + teal: $teal, + cyan: $cyan, + white: $white, + gray: $gray-600, + gray-dark: $gray-800 +); +$primary: $blue !default; +$secondary: $gray-400 !default; +$success: $green !default; +$info: $blue !default; +$warning: $yellow !default; +$danger: $red !default; +$light: $gray-100 !default; +$dark: $gray-800 !default; +$cyan: $cyan !default; +$orange: $orange !default; +$theme-colors: () !default; +$theme-colors: map-merge( + ( + "primary": $primary, + "secondary": $secondary, + "success": $success, + "info": $info, + "warning": $warning, + "danger": $danger, + "light": $light, + "dark": $dark, + "cyan": $cyan, + "orange": $orange, + "purple": $purple + ), + $theme-colors +); +$modalheader-gray: #f8f9fa; +// +// Quickly modify global styling by enabling or disabling optional features. +$enable-caret: true !default; +$enable-rounded: true !default; +$enable-shadows: false !default; +$enable-gradients: false !default; +$enable-transitions: true !default; +$enable-hover-media-query: false !default; +$enable-grid-classes: true !default; +$enable-print-styles: true !default; +// Body +// +// Settings for the element. +$main-body-bg: #fff !default; +$body-bg: #f2f4f5; +$body-color: #6a7a8c !default; +$grid-gutter-width: 20px !default; +// Typography +// +// Font, line-height, and color for body text, headings, and more. +$font-size-base: 0.875rem; +$font-family-open-sans: "Open Sans"; +$font-weight-light: 300 !default; +$font-weight-normal: 400 !default; +$font-weight-medium: 500 !default; +$font-weight-bold: 700 !default; +$h1-font-size: 36px !default; +$h2-font-size: 30px !default; +$h3-font-size: 24px !default; +$h4-font-size: 18px !default; +$h5-font-size: 16px !default; +$h6-font-size: 14px !default; +$headings-margin-bottom: (1rem / 2) !default; +$headings-font-weight: 400 !default; +$headings-color: inherit !default; +// Breadcrumbs +$breadcrumb-bg: $body-bg; +$breadcrumb-margin-bottom: 1.5rem; +// Cards +$card-border-width: 0px !default; +$card-border-color: transparent !default; +$card-border-radius: 0px !default; +// Dropdowns +$dropdown-item-padding-x: 1rem !default; +$dropdown-item-padding-y: 0.65rem !default; +$dropdown-border-color: $gray-200; +$dropdown-divider-bg: $gray-100; +// Buttons +$btn-secondary-border: $gray-300; +// Progress bars +$progress-bg: $gray-100; +// Tables +$table-bg-accent: $gray-100; +$table-bg-hover: $gray-100; +$table-hover-bg: $gray-100 !default; +$table-cell-padding: 1rem !default; +$table-bg-level: -10 !default; +$table-bg-level2: 1 !default; +$table-bg-level3: -5 !default; +// Components +$component-active-color: $white !default; +$component-active-bg: $themecolor !default; +$badge-pill-padding-x: 0.2em !default; +$badge-pill-padding-y: 1em !default; +// Forms +$input-group-addon-bg: $gray-100; +$input-border-color: $gray-200; +$input-group-addon-border-color: $gray-200; +$input-btn-focus-color: rgba(0, 0, 0, 0.25) !default; +$input-focus-border-color: rgba(0, 0, 0, 0.25) !default; +$custom-control-indicator-active-bg: rgba(0, 0, 0, 35%) !default; +$input-btn-focus-box-shadow: transparent !default; +$custom-select-focus-box-shadow: transparent !default; +$custom-select-border-width: 1px !default; +// +// Define common padding and border radius sizes and more. +$border-width: 1px !default; +$border-color: rgba(0, 0, 0, 0.1) !default; +$border-radius: 2px !default; +$border-radius-lg: 2px !default; +$border-radius-sm: 1px !default; +// Progress bars +$progress-height: 5px !default; +//Tabs +$nav-tabs-link-active-bg: $white !default; +// Grid breakpoints +// +// Define the minimum dimensions at which your layout will change, +// adapting to different screen sizes, for use in media queries. +$grid-breakpoints: ( + xs: 0, + sm: 576px, + md: 768px, + lg: 992px, + xl: 1600px +) !default; \ No newline at end of file diff --git a/src/directive/GoToTopDirective.ts b/src/directive/GoToTopDirective.ts new file mode 100644 index 0000000..67cdc96 --- /dev/null +++ b/src/directive/GoToTopDirective.ts @@ -0,0 +1,55 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Directive for go to top button. + */ +import { Directive, HostListener } from '@angular/core'; +import { SharedService } from 'SharedService'; + +/** + * Creating Directive for handling go to top button + * @Directive appGottoTop selector + */ +@Directive({ + selector: '[appGottoTop]' +}) +/** Exporting a class @exports GoToTopDirective */ +export class GoToTopDirective { + /** To set scroll top position @private */ + private topPosToStartShowing: number = 100; + + /** Contains all methods related to shared @private */ + private sharedService: SharedService; + + constructor(sharedService: SharedService) { + this.sharedService = sharedService; + } + /** + * to listen the scroll event in DOM @public + */ + @HostListener('window:scroll') public enableGotoTop(): void { + const scrollPosition: number = Math.max(window.pageYOffset, document.documentElement.scrollTop, document.body.scrollTop); + if (scrollPosition >= this.topPosToStartShowing) { + this.sharedService.showGotoTop = true; + } else { + this.sharedService.showGotoTop = false; + } + } + +} diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts new file mode 100644 index 0000000..6592b10 --- /dev/null +++ b/src/environments/environment.prod.ts @@ -0,0 +1,84 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file environment variables + * This file can be replaced during build by using the `fileReplacements` array. + * `npm run build` replaces `environment.ts` with `environment.prod.ts`. + * The list of file replacements can be found in `angular.json`. + */ + +import { version } from 'PACKAGEJSON'; + +/** OSM_Admin URL @constant */ +const OSM_ADMIN_ENDPOINT: string = 'osm/admin/v1/'; +/** OSM_NS LCM URL @constant */ +const OSM_NSLCM_ENDPOINT: string = 'osm/nslcm/v1/'; +/** OSM_NST URL @constant */ +const OSM_NST_ENDPOINT: string = 'osm/nst/v1/'; +/** OSM_NSI LCM URL @constant */ +const OSM_NSILCM_ENDPOINT: string = 'osm/nsilcm/v1/'; +/** OSM_VNFD PACKAGES URL @constant */ +const OSM_VNFDPACKAGE_ENDPOINT: string = 'osm/vnfpkgm/v1/'; +/** OSM_PDU URL @constant */ +const OSM_PDU_ENDPOINT: string = 'osm/pdu/v1/'; +/** OSM_NSD URL @constant */ +const OSM_NSD_ENDPOINT: string = 'osm/nsd/v1/'; +/** Assets root path @constant */ +const ASSETS_PATH: string = 'assets/'; +/** OSM Version @constant */ +const OSM_VERSION: string = 'osm/version'; +/** Grafana End-Point @constant */ +// tslint:disable-next-line: no-http-string +const GRAFANA_ENDPOINT: string = 'http://' + window.location.hostname + ':3000'; + +/** Exporting a const @exports environment */ +// tslint:disable-next-line: typedef +export const environment = { + production: true, + packageSize: 15, + paginationNumber: 10, //Possible values are 10, 25, 50, 100 + packageVersion: version, + // tslint:disable-next-line: no-http-string + MAPLATLONGAPI_URL: 'http://photon.komoot.de/api/?q={value}&limit=5', + GENERATETOKEN_URL: OSM_ADMIN_ENDPOINT + 'tokens', + PROJECTS_URL: OSM_ADMIN_ENDPOINT + 'projects', + USERS_URL: OSM_ADMIN_ENDPOINT + 'users', + ROLES_URL: OSM_ADMIN_ENDPOINT + 'roles', + VIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'vim_accounts', + WIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'wim_accounts', + SDNCONTROLLER_URL: OSM_ADMIN_ENDPOINT + 'sdns', + K8SCLUSTER_URL: OSM_ADMIN_ENDPOINT + 'k8sclusters', + K8REPOS_URL: OSM_ADMIN_ENDPOINT + 'k8srepos', + NETWORKSLICETEMPLATE_URL: OSM_NST_ENDPOINT + 'netslice_templates', + NETWORKSLICETEMPLATECONTENT_URL: OSM_NST_ENDPOINT + 'netslice_templates_content', + NSDINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'ns_instances', + VNFINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'vnfrs', + NSINSTANCESCONTENT_URL: OSM_NSLCM_ENDPOINT + 'ns_instances_content', + NSHISTORYOPERATIONS_URL: OSM_NSLCM_ENDPOINT + 'ns_lcm_op_occs', + NETWORKSLICEINSTANCESCONTENT_URL: OSM_NSILCM_ENDPOINT + 'netslice_instances_content', + NSTHISTORYOPERATIONS_URL: OSM_NSILCM_ENDPOINT + '/nsi_lcm_op_occs', + NSDESCRIPTORSCONTENT_URL: OSM_NSD_ENDPOINT + 'ns_descriptors_content', + NSDESCRIPTORS_URL: OSM_NSD_ENDPOINT + 'ns_descriptors', + VNFPACKAGESCONTENT_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages_content', + VNFPACKAGES_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages', + PDUINSTANCE_URL: OSM_PDU_ENDPOINT + 'pdu_descriptors', + PERMISSIONS_CONFIG_FILE: ASSETS_PATH + 'config/rolePermissions.json', + GRAFANA_URL: GRAFANA_ENDPOINT + '/d', + DOMAIN_URL: OSM_ADMIN_ENDPOINT + 'domains', + OSM_VERSION_URL: OSM_VERSION +}; diff --git a/src/environments/environment.ts b/src/environments/environment.ts new file mode 100644 index 0000000..dbc2c98 --- /dev/null +++ b/src/environments/environment.ts @@ -0,0 +1,84 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file environment variables + * This file can be replaced during build by using the `fileReplacements` array. + * `npm run build` replaces `environment.ts` with `environment.prod.ts`. + * The list of file replacements can be found in `angular.json`. + */ + +import { version } from 'PACKAGEJSON'; + +/** OSM Admin URL @constant */ +const OSM_ADMIN_ENDPOINT: string = 'osm/admin/v1/'; +/** OSM NS LCM URL @constant */ +const OSM_NSLCM_ENDPOINT: string = 'osm/nslcm/v1/'; +/** OSM NST URL @constant */ +const OSM_NST_ENDPOINT: string = 'osm/nst/v1/'; +/** OSM NSI LCM URL @constant */ +const OSM_NSILCM_ENDPOINT: string = 'osm/nsilcm/v1/'; +/** OSM VNFD PACKAGES URL @constant */ +const OSM_VNFDPACKAGE_ENDPOINT: string = 'osm/vnfpkgm/v1/'; +/** OSM PDU URL @constant */ +const OSM_PDU_ENDPOINT: string = 'osm/pdu/v1/'; +/** OSM NSD URL @constant */ +const OSM_NSD_ENDPOINT: string = 'osm/nsd/v1/'; +/** Assets root path @constant */ +const ASSETS_PATH: string = 'assets/'; +/** OSM Version @constant */ +const OSM_VERSION: string = 'osm/version'; +/** Grafana End-Point @constant */ +// tslint:disable-next-line: no-http-string +const GRAFANA_ENDPOINT: string = 'http://' + window.location.hostname + ':3000'; + +/** Exporting a const @exports environment */ +// tslint:disable-next-line: typedef +export const environment = { + production: false, + packageSize: 15, + paginationNumber: 10, //Possible values are 10, 25, 50, 100 + packageVersion: version, + // tslint:disable-next-line: no-http-string + MAPLATLONGAPI_URL: 'http://photon.komoot.de/api/?q={value}&limit=5', + GENERATETOKEN_URL: OSM_ADMIN_ENDPOINT + 'tokens', + PROJECTS_URL: OSM_ADMIN_ENDPOINT + 'projects', + USERS_URL: OSM_ADMIN_ENDPOINT + 'users', + ROLES_URL: OSM_ADMIN_ENDPOINT + 'roles', + VIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'vim_accounts', + WIMACCOUNTS_URL: OSM_ADMIN_ENDPOINT + 'wim_accounts', + SDNCONTROLLER_URL: OSM_ADMIN_ENDPOINT + 'sdns', + K8SCLUSTER_URL: OSM_ADMIN_ENDPOINT + 'k8sclusters', + K8REPOS_URL: OSM_ADMIN_ENDPOINT + 'k8srepos', + NETWORKSLICETEMPLATE_URL: OSM_NST_ENDPOINT + 'netslice_templates', + NETWORKSLICETEMPLATECONTENT_URL: OSM_NST_ENDPOINT + 'netslice_templates_content', + NSDINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'ns_instances', + VNFINSTANCES_URL: OSM_NSLCM_ENDPOINT + 'vnfrs', + NSINSTANCESCONTENT_URL: OSM_NSLCM_ENDPOINT + 'ns_instances_content', + NSHISTORYOPERATIONS_URL: OSM_NSLCM_ENDPOINT + 'ns_lcm_op_occs', + NETWORKSLICEINSTANCESCONTENT_URL: OSM_NSILCM_ENDPOINT + 'netslice_instances_content', + NSTHISTORYOPERATIONS_URL: OSM_NSILCM_ENDPOINT + 'nsi_lcm_op_occs', + NSDESCRIPTORSCONTENT_URL: OSM_NSD_ENDPOINT + 'ns_descriptors_content', + NSDESCRIPTORS_URL: OSM_NSD_ENDPOINT + 'ns_descriptors', + VNFPACKAGESCONTENT_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages_content', + VNFPACKAGES_URL: OSM_VNFDPACKAGE_ENDPOINT + 'vnf_packages', + PDUINSTANCE_URL: OSM_PDU_ENDPOINT + 'pdu_descriptors', + PERMISSIONS_CONFIG_FILE: ASSETS_PATH + 'config/rolePermissions.json', + GRAFANA_URL: GRAFANA_ENDPOINT + '/d', + DOMAIN_URL: OSM_ADMIN_ENDPOINT + 'domains', + OSM_VERSION_URL: OSM_VERSION +}; diff --git a/src/favicon.ico b/src/favicon.ico new file mode 100644 index 0000000..c588094 Binary files /dev/null and b/src/favicon.ico differ diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..ea9b726 --- /dev/null +++ b/src/index.html @@ -0,0 +1,34 @@ + + + + + + OSM + + + + + + + + + + + diff --git a/src/karma.conf.js b/src/karma.conf.js new file mode 100644 index 0000000..7dda620 --- /dev/null +++ b/src/karma.conf.js @@ -0,0 +1,48 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +// Karma configuration file, see link for more information +// https://karma-runner.github.io/1.0/config/configuration-file.html + +module.exports = function (config) { + config.set({ + basePath: '', + frameworks: ['jasmine', '@angular-devkit/build-angular'], + plugins: [ + require('karma-jasmine'), + require('karma-chrome-launcher'), + require('karma-jasmine-html-reporter'), + require('karma-coverage-istanbul-reporter'), + require('@angular-devkit/build-angular/plugins/karma') + ], + client: { + clearContext: false // leave Jasmine Spec Runner output visible in browser + }, + coverageIstanbulReporter: { + dir: require('path').join(__dirname, '../coverage/osm'), + reports: ['html', 'lcovonly', 'text-summary'], + fixWebpackSourcePaths: true + }, + reporters: ['progress', 'kjhtml'], + port: 9876, + colors: true, + logLevel: config.LOG_INFO, + autoWatch: true, + browsers: ['Chrome'], + singleRun: false + }); +}; diff --git a/src/main.ts b/src/main.ts new file mode 100644 index 0000000..fd921a3 --- /dev/null +++ b/src/main.ts @@ -0,0 +1,32 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Main for the application. + */ +import { enableProdMode } from '@angular/core'; +import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; + +import { AppModule } from './app/AppModule'; +import { environment } from './environments/environment'; + +if (environment.production) { + enableProdMode(); +} + +platformBrowserDynamic().bootstrapModule(AppModule) + .catch((err: Error): void => { console.error(err); }); diff --git a/src/models/CommonModel.ts b/src/models/CommonModel.ts new file mode 100644 index 0000000..e3d44e2 --- /dev/null +++ b/src/models/CommonModel.ts @@ -0,0 +1,207 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +import { HttpHeaders } from '@angular/common/http'; + +/** + * @file Model for Commonly used information. + */ +/** + * handle count @enum + */ +export enum CONSTANTNUMBER { + randomNumber = 4, + osmapviewlong = 77.673, + osmapviewlat = 19.166, + chennailong = 80.2809, + chennailat = 13.0781, + bangalorelong = 77.5868, + bangalorelat = 12.9718, + mumbailong = 72.8342, + mumbailat = 18.9394, + tirvandrumlong = 76.9544, + tirvandrumlat = 8.5009, + oneMB = 1048576, + paginationDefaultValue = 10, + splitLongitude = 1, + splitLatitude = 2 +} +/** + * handle count @enum + */ +export enum CONFIGCONSTANT { + operationalStateFirstStep = 'init', + operationalStateSecondStep = 'running', + operationalStateThirdStep = 'failed', + configStateFirstStep = 'init', + configStateSecondStep = 'configured', + configStateThirdStep = 'failed', + historyStateFirstStep = 'PROCESSING', + historyStateSecondStep = 'COMPLETED', + historyStateThirdStep = 'FAILED', + wimOperationalStateFirstStep = 'PROCESSING', + wimOperationalStateStateSecondStep = 'ENABLED', + wimOperationalStateThirdStep = 'ERROR', + vimOperationalStateFirstStep = 'PROCESSING', + vimOperationalStateStateSecondStep = 'ENABLED', + vimOperationalStateThirdStep = 'ERROR', + sdnOperationalStateFirstStep = 'PROCESSING', + sdnOperationalStateStateSecondStep = 'ENABLED', + sdnOperationalStateThirdStep = 'ERROR', + k8OperationalStateFirstStep = 'PROCESSING', + k8OperationalStateStateSecondStep = 'ENABLED', + k8OperationalStateThirdStep = 'ERROR' +} +/** Interface for Post options */ +export interface POSTAPIRESOURCE { + apiURLHeader: APIURLHEADER; + payload?: object; +} +/** Interface for ApiURL Header */ +export interface APIURLHEADER { + url: string; + httpOptions?: APIHEADERS; +} +/** Interface for the Get Method with response type */ +export interface GETAPIURLHEADER { + headers: HttpHeaders; + responseType: string; +} +/** Interface for Httpoptions Header */ +interface APIHEADERS { + headers: HttpHeaders; +} +/** Interface for the Error */ +export interface ERRORDATA { + error: ERRORDETAILSDATA; +} +/** Interface for the Error Details */ +interface ERRORDETAILSDATA { + detail: string; + code?: string; + status?: number; + text?: Function; +} +/** Handle the URL params */ +export interface URLPARAMS { + page: string; + id: string; + titleName?: string; + forceDeleteType?: boolean; + name?: string; + memberIndex?: object; + nsConfig?: object; + projectID?: string; + username?: string; +} +/** Handle the Delete params */ +export interface DELETEPARAMS { + identifier: string; + name?: string; + shortName: string; + projectName?: string; + userName?: string; + username?: string; + page?: string; + id?: string; +} + +/** Interface for the Delete Details */ +export interface MODALCLOSERESPONSEDATA { + message: string; +} + +/** Interface for the modal closer */ +export interface MODALCLOSERESPONSEWITHCP { + message: string; + connection_point?: string; +} + +/** Interface for local storage settings */ +export interface LOCALSTORAGE { + id_token?: string; + project_id?: string; + expires?: string; + username?: string; + project?: string; + project_name?: string; + id?: string; + admin?: boolean; + isAdmin?: string; + token_state?: string; +} +/** Interface for Tar settings */ +export interface TARSETTINGS { + name?: string; + 'type'?: string; + readAsString?: Function; + buffer: ArrayBuffer; +} +/** Interface for Package information */ +export interface PACKAGEINFO { + id?: string; + packageType?: string; + descriptor: string; +} + +/** Interface For the Pagination pager in ng-smarttable */ +export interface PAGERSMARTTABLE { + display: boolean; + perPage: number; +} +/** Interface for breadcrumb item */ +export interface BREADCRUMBITEM { + title: string; + url: string; +} +/** Interface For the Pagination pager in ng-smarttable */ +export interface SMARTTABLECLASS { + // tslint:disable-next-line: no-reserved-keywords + class: string; +} +/** Constants of the VIM Types */ +export const VIM_TYPES: TYPESECTION[] = [ + { value: 'openstack', title: 'Openstack' }, + { value: 'aws', title: 'AWS' }, + { value: 'vmware', title: 'VMware vCD' }, + { value: 'openvim', title: 'OpenVIM' }, + { value: 'opennebula', title: 'OpenNebula' }, + { value: 'azure', title: 'Azure' } +]; +/** Constants of the SDN Types */ +export const SDN_TYPES: TYPESECTION[] = [ + { value: 'arista', title: 'Arista' }, + { value: 'floodlightof', title: 'Floodlight openflow' }, + { value: 'odlof', title: 'OpenDaylight openflow' }, + { value: 'onosof', title: 'ONOS openflow' }, + { value: 'onos_vpls', title: 'ONOS vpls' } +]; +/** Constants of the WIM Types */ +export const WIM_TYPES: TYPESECTION[] = [ + { value: 'arista', title: 'Arista' }, + { value: 'dynpac', title: 'DynPac' }, + { value: 'floodlightof', title: 'Floodlight openflow' }, + { value: 'odlof', title: 'OpenDaylight openflow' }, + { value: 'onosof', title: 'ONOS openflow' }, + { value: 'onos_vpls', title: 'ONOS vpls' }, + { value: 'tapi', title: 'TAPI' } +]; +/** Interface for List, Add WIM & SDN Types */ +export interface TYPESECTION { + value: string; + title: string; +} diff --git a/src/models/K8sModel.ts b/src/models/K8sModel.ts new file mode 100644 index 0000000..4e83483 --- /dev/null +++ b/src/models/K8sModel.ts @@ -0,0 +1,127 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for K8s related information. + */ + +/** Interface for K8SCLUSTERDATA */ +export interface K8SCLUSTERDATA { + credentials: Credentials; + description: string; + k8s_version: number; + name: string; + namespace: string; + nets: Nets; + schema_version: string; + vim_account: string; + _admin: Admin; + _id: string; +} +/** Interface for K8SCLUSTERDATA */ +export interface K8SREPODATA { + description: string; + name: string; + schema_version: string; + 'type': string; + url: string; + vim_account: string; + _admin: Admin; + _id: string; +} +/** Interface for the Credentials */ +interface Credentials{ + apiVersion: string; + clusters: Clusters[]; + contexts: Contexts[]; + 'current-context': string; + kind: string; + preferences: {}; + users: Users[]; +} +/** Interface for the Clusters */ +interface Clusters { + cluster: Cluster; + name: string; +} +/** Interface for the Cluster */ +interface Cluster { + 'certificate-authority-data': string; + server: string; +} +/** Interface for the Contexts */ +interface Contexts{ + context: Context; + name: string; +} +/** Interface for the Contexts */ +interface Context { + cluster: string; + user: string; +} +/** Interface for the Users */ +interface Users{ + name: string; + user: User; +} +/** Interface for the Users */ +interface User { + 'client-certificate-data': string; + 'client-key-data': string; +} +/** Interface for the K8SCLUSTERDATA nets */ +interface Nets{ + net1: string; +} +/** Interface for the K8SCLUSTERDATA _admin */ +interface Admin{ + created: string; + current_operation: number; + 'helm-chart': HelmChart; + 'juju-bundle': JujuBundle; + operationalState: string; + modified: string; +} +/** Interface for the K8SCLUSTERDATA _admin Helm chart */ +interface HelmChart { + created: boolean; + id: string; +} +/** Interface for the K8SCLUSTERDATA _admin Juju Bundle */ +interface JujuBundle { + error_msg: string; +} +/** Interface for the K8SCLUSTERDATA Return to Display */ +export interface K8SCLUSTERDATADISPLAY{ + name: string; + identifier: string; + operationalState: string; + version: number; + created: string; + modified: string; + pageType: string; +} +/** Interface for the K8SCLUSTERDATA Return to Display */ +export interface K8SREPODATADISPLAY { + name: string; + identifier: string; + url: string; + 'type': string; + created: string; + modified: string; + pageType: string; +} diff --git a/src/models/MenuModel.ts b/src/models/MenuModel.ts new file mode 100644 index 0000000..dd77e0d --- /dev/null +++ b/src/models/MenuModel.ts @@ -0,0 +1,261 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for Commonly used information. + */ +/** Constants of the Menu child active class */ +const childActiveClass: string[] = ['active']; +/** Constants of the Menu Items */ +export const MENU_ITEMS: MENUITEMS[] = [ + { + liClass: 'round-edge-top-3', + anchorTagClass: 'link round-edge-top-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-th-large', + menuName: 'PAGE.DASHBOARD.DASHBOARD', + isChildExists: false + }, + { + liClass: 'header-menu', + anchorTagClass: 'heading text-uppercase', + menuName: 'PROJECT', + isChildExists: false + }, + { + liClass: 'round-edge-top-3', + anchorTagClass: 'parentlink round-edge-top-3 mr-top-5', + clickFunction: 'packages', + routerLink: '/packages', + routerLinkActive: ['menu-open', 'parentactive'], + routerLinkActiveOptions: false, + icon: 'fas fa-box', + menuName: 'PACKAGES', + isChildExists: true, + ulClass: 'sidebar-submenu', + childItems: [ + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/packages/ns', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-box-open', + menuName: 'NSPACKAGES', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/packages/vnf', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-box-open', + menuName: 'VNFPACKAGES', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/packages/netslice', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-layer-group', + menuName: 'PAGE.DASHBOARD.NETSLICETEMPLATE', + isChildExists: false + } + ] + }, + { + liClass: 'mt-1 round-edge-bottom-3 border-bottom-none', + anchorTagClass: 'parentlink round-edge-bottom-3 border-bottom-none', + clickFunction: 'instances', + routerLink: '/instances', + routerLinkActive: ['menu-open', 'parentactive'], + routerLinkActiveOptions: false, + icon: 'fa fa-paper-plane', + menuName: 'INSTANCES', + isChildExists: true, + ulClass: 'sidebar-submenu', + childItems: [ + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/instances/ns', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-sitemap', + menuName: 'NSINSTANCES', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/instances/vnf', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-hdd', + menuName: 'VNFINSTANCES', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/instances/pdu', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-hdd', + menuName: 'PDUINSTANCES', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/instances/netslice', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-layer-group', + menuName: 'PAGE.DASHBOARD.NETSLICEINSTANCE', + isChildExists: false + } + ] + }, + { + liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5', + anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/sdn/details', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-globe', + menuName: 'SDNCONTROLLER', + isChildExists: false + }, + { + liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5', + anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/vim', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: false, + icon: 'fas fa-server', + menuName: 'VIMACCOUNTS', + isChildExists: false + }, + { + liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5', + anchorTagClass: 'parentlink round-edge-top-3 round-edge-bottom-3', + clickFunction: 'k8s', + routerLink: '/k8s', + routerLinkActive: ['menu-open', 'parentactive'], + routerLinkActiveOptions: false, + icon: 'fas fa-asterisk', + menuName: 'PAGE.K8S.MENUK8S', + isChildExists: true, + ulClass: 'sidebar-submenu', + childItems: [ + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/k8s/cluster', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-project-diagram', + menuName: 'PAGE.K8S.MENUK8SCLUSTER', + isChildExists: false + }, + { + liClass: '', + anchorTagClass: 'link', + routerLink: '/k8s/repo', + routerLinkActive: childActiveClass, + routerLinkActiveOptions: false, + icon: 'fas fa-flag', + menuName: 'PAGE.K8S.MENUK8SREPO', + isChildExists: false + } + ] + }, + { + liClass: 'round-edge-top-3 round-edge-bottom-3 mr-top-5', + anchorTagClass: 'link round-edge-top-3 round-edge-bottom-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/wim/details', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-sitemap', + menuName: 'WIMACCOUNTS', + isChildExists: false + }, + { + liClass: 'header-menu', + anchorTagClass: 'heading text-uppercase', + menuName: 'ADMIN', + isChildExists: false + }, + { + liClass: 'mt-1 round-edge-top-3', + anchorTagClass: 'link round-edge-top-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/projects', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-folder', + menuName: 'PAGE.DASHBOARD.PROJECTS', + isChildExists: false + }, + { + liClass: 'mt-1 mb-1', + anchorTagClass: 'link individual', + clickFunction: 'nosubmenu', + routerLink: '/users/details', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-users', + menuName: 'PAGE.DASHBOARD.USERS', + isChildExists: false + }, + { + liClass: 'round-edge-bottom-3', + anchorTagClass: 'link round-edge-bottom-3 individual', + clickFunction: 'nosubmenu', + routerLink: '/roles', + routerLinkActive: ['parentactive'], + routerLinkActiveOptions: true, + icon: 'fas fa-user-tag', + menuName: 'ROLES', + isChildExists: false + } +]; + +/** Interface for Post options */ +export interface MENUITEMS { + ulClass?: string; + liClass: string; + anchorTagClass: string; + clickFunction?: string; + routerLink?: string; + routerLinkActive?: string[]; + routerLinkActiveOptions?: boolean; + icon?: string; + menuName: string; + isChildExists: boolean; + childItems?: MENUITEMS[]; +} diff --git a/src/models/NSDModel.ts b/src/models/NSDModel.ts new file mode 100644 index 0000000..95331a2 --- /dev/null +++ b/src/models/NSDModel.ts @@ -0,0 +1,168 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for NSD related information. + */ + +import { VNFDAdminDetails } from './VNFDModel'; + +/** Interface for NSData */ +export interface NSData { + shortName: string; + identifier: string; + description: string; + vendor: string; + version: string; + page?: string; + name?: string; + projectName?: string; + userName?: string; + username?: string; +} + +/** Interface for the nscompose descriptors content */ +export interface NSDDetails { + 'connection-point': CONNECTIONPOINT[]; + 'constituent-vnfd': CONSTITUENTVNFD[]; + description: string; + id: string; + logo: string; + name: string; + 'short-name': string; + vendor: string; + version: string; + vld: VLD[]; + _admin: VNFDAdminDetails; + _id: string; + 'constituent-vnfr-ref': string[]; +} + +/** Interface for the connection-point */ +export interface CONNECTIONPOINT { + name: string; + 'vld-id-ref': string; +} + +/** Interface for the constituent-vnfd */ +export interface CONSTITUENTVNFD { + 'member-vnf-index': number; + 'vnfd-id-ref': string; +} + +/** Interface for the vld */ +export interface VLD { + id: string; + 'mgmt-network': boolean; + name: string; + 'short-name'?: string; + 'type': string; + 'vnfd-connection-point-ref'?: VNFDCONNECTIONPOINTREF[]; + 'vim-network-name': string; +} + +/** Interface for VNFDCONNECTIONPOINTREF */ +export interface VNFDCONNECTIONPOINTREF { + 'member-vnf-index-ref': number; + 'vnfd-connection-point-ref': string; + 'vnfd-id-ref': string; +} +/** Interface Nodes Creation */ +export interface COMPOSERNODES { + id: string; + reflexive: Boolean; + 'type': string; + name?: string; + nodeIndex?: number; + selectorId?: string; + x?: number; + y?: number; + fx?: number; + fy?: number; +} + +/** Interface for the Tick */ +export interface Tick { + target: TickPath; + source: TickPath; + left: boolean; + right: boolean; +} + +/** Interface for the Path */ +export interface TickPath { + x: number; + y: number; + id: string; + 'type'?: string; +} + +/** Interface for the NSD */ +interface NSD { + 'constituent-vnfd': CONSTITUENTVNFD[]; + description: string; + id: string; + name: string; + 'short-name': string; + vendor: string; + version: string; + vld: VLD[]; + _admin: VNFDAdminDetails; + _id: string; +} +/** Interface for the GRAPHDETAILS */ +export interface GRAPHDETAILS { + width: number; + height: number; + nodeHeight: number; + nodeWidth: number; + textX: number; + textY: number; + radius: number; + distance: number; + strength: number; + forcex: number; + forcey: number; + sourcePaddingYes: number; + sourcePaddingNo: number; + targetPaddingYes: number; + targetPaddingNo: number; + alphaTarget: number; + imageX: number; + imageY: number; + shiftKeyCode: number; +} + +/** Interface for the NS Create params */ +export interface NSCREATEPARAMS { + nsName: string; + nsDescription: string; + nsdId: string; + vimAccountId: string; + vld: string; + ssh_keys: string[]; +} + +/** Interface for the NSI Create params */ +export interface NSICREATEPARAMS { + nsName: string; + nsDescription: string; + nstId: string; + vimAccountId: string; + 'netslice-vld': string; + ssh_keys: string[]; +} diff --git a/src/models/NSInstanceModel.ts b/src/models/NSInstanceModel.ts new file mode 100644 index 0000000..72cd42b --- /dev/null +++ b/src/models/NSInstanceModel.ts @@ -0,0 +1,282 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for NS Instance related information. + */ + +import { CONSTITUENTVNFD, VLD, VNFDCONNECTIONPOINTREF } from 'NSDModel'; +import { VNFDAdminDetails } from 'VNFDModel'; + +/** Interface for NSInstanceDetails */ +export interface NSInstanceDetails { + 'orchestration-progress': JSON; + 'constituent-vnfr-ref': string[]; + 'operational-events': string[]; + admin: Admin; + 'ssh-authorized-key': string; + _admin: _Admin; + 'admin-status': string; + 'operational-status': string; + 'datacenter': string; + nsd: NSD; + name: string; + 'name-ref': string; + 'short-name': string; + id: string; + 'nsd-name-ref': string; + description: string; + 'detailed-status': string; + 'config-status': string; + 'resource-orchestrator': string; + 'nsd-ref': string; + vld: VLD[]; + instantiate_params: InstantiateParam; + additionalParamsForNs: AdditionalParamForN; + _id?: string; +} + +/** Interface for Admin */ +interface Admin { + deployed: DeployedAdmin; +} + +/** Interface for DeployedAdmin */ +interface DeployedAdmin { + RO: ROAdmin; +} + +/** Interface for ROAdmin */ +interface ROAdmin { + 'nsr_status': string; +} + +/** Interface for _Admin */ +// tslint:disable-next-line:class-name +interface _Admin { + 'projects_write': string[]; + deployed: DeployedAdmin; + nslcmop: string; + nsState: string; + modified: number; + projects_read: string[]; + created: string; +} + +/** Interface for Deployed_Admin */ +interface DeployedAdmin { + VCA: string[]; + RO: ROAdmin; +} + +/** Interface for RO_Admin */ +interface ROAdmin { + 'nsr_status': string; + 'nsr_id': string; + 'nsd_id': string; + vnfd: VNFD[]; +} + +/** Interface for VNFD */ +interface VNFD { + 'member-vnf-index': number; + id: string; +} + +/** Interface for NSD */ +export interface NSD { + description: string; + vld: NSDVLD[]; + _admin: VNFDAdminDetails; + name: string; + version: string; + _id: string; + 'short-name': string; + id: string; + 'constituent-vnfd': CONSTITUENTVNFD[]; + vendor: string; + vdur: string[]; + 'connection-point': CONNECTIONPOINT[]; +} + +/** Interface for _AdminDetails */ +// tslint:disable-next-line:class-name +export interface _AdminDetails { + usageState: string; + projects_write: string[]; + projects_read: string[]; + operationalState: string; + modified: string; + storage: Storage; + onboardingState: string; + userDefinedData: JSON; + created: number; +} + +/** Interface for Storage */ +interface Storage { + path: string; + 'pkg-dir': string; + zipfile: string; + folder: string; + descriptor: string; + fs: string; +} + +/** Interface for NSDVLD */ +export interface NSDVLD { + 'vim-id': string; + 'status-detailed': string; + name: string; + status: string; + 'vim-network-name': string; + id: string; + 'type': string; + 'vnfd-connection-point-ref': VNFDCONNECTIONPOINTREF[]; + 'short-name': string; +} + +/** Interface for InstantiateParam */ +interface InstantiateParam { + nsdId: string; + nsName: string; + nsDescription: string; + vimAccountId: string; +} + +/** Interface for AdditionalParamForN */ +interface AdditionalParamForN { + _id: string; + 'ns-instance-config-ref': string; + 'crete-time': string; +} + +/** interface for the History nsdInstanceData */ +export interface NSDInstanceData { + id?: string; + lcmOperationType?: string; + operationState?: string; + startTime?: number; + statusEnteredTime?: number; + identifier: string; + name: string; + NsdName: string; + OperationalStatus: string; + ConfigStatus: string; + DetailedStatus: string; + state?: string; + memberIndex?: object; + nsConfig?: object; +} + +/** Interface for the nsInfo */ +export interface NSINFO { + nsInstanceID: string; + nsName: string; + nsOperationalStatus: string; + nsConfigStatus: string; + nsDetailedStatus: string; + nsResourceOrchestrator: string; +} + +/** Interface for the NSINSTANCENODES */ +export interface NSINSTANCENODES { + id?: string; + nodeTypeRef?: string; + name?: string; + 'type'?: string; + vnfdCP?: VNFDCONNECTIONPOINTREF[]; + vimNetworkName?: string; + shortName?: string; + cp?: CONNECTIONPOINT[]; + vdur?: string[]; + vld?: NSDVLD[]; + nsID?: string; + vnfdID?: string; + vimID?: string; + vndfrID?: string; + ipAddress?: string; + memberIndex?: string; + vnfdRef?: string; + vndfCPRef?: string; + selectorId?: string; +} + +/** Interface for the connection-point */ +export interface CONNECTIONPOINT { + 'connection-point-id': string; + name: string; + id: string; +} + +/** Interface for Exec NS Primitive */ +export interface NSPrimitive { + 'primitive': string; + 'primitive_params': NSPrimitiveParams[]; + 'member_vnf_index': string; +} + +/** Interface for Exec NS Primitive Params */ +export interface NSPrimitiveParams { + primitive_params_name: string; + primitive_params_value: string; +} + +/** Interface Nodes Creation */ +export interface COMPOSERNODES { + id: string; + reflexive: Boolean; + nodeTypeRef: string; + name?: string; + nodeIndex?: number; + selectorId?: string; + x?: number; + y?: number; + fx?: number; + fy?: number; + shortName?: string; + vimNetworkName?: string; + 'type'?: string; + vnfdRef?: string; + memberIndex?: string; + vimID?: string; + vndfrID?: string; + ipAddress?: string; + nsID?: string; + vnfdID?: string; +} + +/** Interface for the Virtual Link Info */ +export interface VLINFO { + id: string; + name: string; + 'type': string; + shortName: string; + vimNetworkName: string; +} + +/** Interface for the VNFR Info */ +export interface VNFRINFO{ + vimID: string; + _id: string; + ip: string; + nsrID: string; + id: string; + vnfdRef: string; + vnfdId: string; + memberIndex: string; +} diff --git a/src/models/NSTopologyModel.ts b/src/models/NSTopologyModel.ts new file mode 100644 index 0000000..7a1dc62 --- /dev/null +++ b/src/models/NSTopologyModel.ts @@ -0,0 +1,57 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for NS topology related information. + */ + +/** Interface for the GRAPHDETAILS */ +export interface GRAPHDETAILS { + width: number; + height: number; + nodeHeight: number; + nodeWidth: number; + textX: number; + textY: number; + radius: number; + distance: number; + strength: number; + forcex: number; + forcey: number; + sourcePaddingYes: number; + sourcePaddingNo: number; + targetPaddingYes: number; + targetPaddingNo: number; + alphaTarget: number; + imageX: number; + imageY: number; + shiftKeyCode: number; +} +/** Interface for the Path */ +export interface TickPath { + x: number; + y: number; + id: string; + 'type'?: string; +} +/** Interface for the Tick */ +export interface Tick { + target: TickPath; + source: TickPath; + left: boolean; + right: boolean; +} diff --git a/src/models/NetworkSliceModel.ts b/src/models/NetworkSliceModel.ts new file mode 100644 index 0000000..eda0b92 --- /dev/null +++ b/src/models/NetworkSliceModel.ts @@ -0,0 +1,113 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for Network Slice Template related information. + */ + +/** Interface for MetricModel */ +export interface NetworkSliceModel { + 'netslice-subnet': NetsliceSubnet[]; + id: string; + 'SNSSAI-identifier': SNSSAIIdentifier; + 'quality-of-service': QualityOfService; + name: string; + _id: string; + _admin: ADMIN; + 'netslice-vld': NetsliceVld[]; +} + +/** Interface for NetsliceSubnet */ +interface NetsliceSubnet { + description : string; + id: string; + 'is-shared-nss': string; + 'nsd-ref': string; +} + +/** Interface for SNSSAIIdentifier */ +interface SNSSAIIdentifier { + 'slice-service-type': string; +} + +/** Interface for SNSSAIIdentifier */ +interface QualityOfService { + id: number; +} + +/** Interface for Admin */ +interface ADMIN { + operationalState: string; + created: string; + projects_write: string[]; + projects_read: string[]; + usageState: string; + modified: string; + onboardingState: string; + userDefinedData: {}; + storage : Storage; +} + +/** Interface for Storage */ +interface Storage { + fs: string; + folder: string; + descriptor: string; + path: string; +} + +/** Interface for NetsliceVld */ +interface NetsliceVld { + name: string; + id: string; + 'nss-connection-point-ref': NssConnectionPointRef[]; + 'mgmt-network': boolean; + // tslint:disable-next-line:no-reserved-keywords + type: string; +} + +/** Interface for NssConnectionPointRef */ +interface NssConnectionPointRef { + 'nss-ref': string; + 'nsd-connection-point-ref': string; +} + +/** Interface for NetworkSliceData */ +export interface NetworkSliceData { + name: string; + identifier: string; + usageState: string; +} + +/** Interface for Network Slice instance Data */ +export interface NSTInstanceDetails { + name: string; + id: string; + 'nst-ref': string; + 'operational-status': string; + 'config-status': string; + 'detailed-status': string; +} +/** interface for the Network Slice instance Data in datasource Table */ +export interface NSTInstanceData { + name: string; + identifier: string; + NstName: string; + OperationalStatus: string; + ConfigStatus: string; + DetailedStatus: string; +} diff --git a/src/models/PDUInstanceModel.ts b/src/models/PDUInstanceModel.ts new file mode 100644 index 0000000..b628bdb --- /dev/null +++ b/src/models/PDUInstanceModel.ts @@ -0,0 +1,51 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for PDU Instance related information. + */ + +/** Interface for PDUInstanceDetails */ +export interface PDUInstanceDetails { + description: string; + interfaces: PDUInterfaces[]; + name: string; + 'type': string; + vim_accounts: string[]; + _admin: ADMIN; + _id: string; + identifier?: string; +} + +/** Interface for PDU interfaces */ +export interface PDUInterfaces { + 'ip-address': string; + mgmt: boolean; + name: string; + 'vim-network-name': string; +} + +/** Interface for Admin */ +interface ADMIN { + created: string; + modified: string; + onboardingState: string; + operationalState: string; + projects_write: string[]; + projects_read: string[]; + usageState: string; +} diff --git a/src/models/ProjectModel.ts b/src/models/ProjectModel.ts new file mode 100644 index 0000000..878bb47 --- /dev/null +++ b/src/models/ProjectModel.ts @@ -0,0 +1,44 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for project related information. + */ + +/** Interface for ProjectDetails */ +export interface ProjectDetails { + _admin?: Admin; + _id?: string; + name?: string; + id?: string; +} + +/** Interface for Admin */ +interface Admin { + created: number; + modified: number; + projects_read?: string[]; +} +/** Interface for ProjectDetails in smarttable */ +export interface ProjectData { + projectName: string; + modificationDate: string; + creationDate: string; + page?: string; + id?: string; + project?: string; +} diff --git a/src/models/RoleModel.ts b/src/models/RoleModel.ts new file mode 100644 index 0000000..3629b6c --- /dev/null +++ b/src/models/RoleModel.ts @@ -0,0 +1,57 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for role related information. + */ + +/** Interface for ProjectDetails */ +export interface RoleDetails { + _admin?: Admin; + _id?: string; + name?: string; + id?: string; + permissions?: {}; +} + +/** Interface for Admin */ +interface Admin { + created: number; + modified: number; +} +/** Interface for Role data in smarttable */ +export interface RoleData { + name: string; + identifier: string; + modified: string; + created: string; + permissions: {}; +} +/** Interface for Role configuration from role config file */ +export interface RoleConfig { + rolePermissions: PermissionGroup[]; +} +/** Interface for Role permission group */ +export interface PermissionGroup { + title: string; + permissions: Permission[]; +} +/** Interface for Role permission group */ +export interface Permission { + operation: string; + value: string | boolean; +} diff --git a/src/models/SDNControllerModel.ts b/src/models/SDNControllerModel.ts new file mode 100644 index 0000000..2b5ab87 --- /dev/null +++ b/src/models/SDNControllerModel.ts @@ -0,0 +1,75 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model For SDN Controller model Information. + */ + +/** Interface for SDNControllerModel */ +export interface SDNControllerModel { + dpid: string; + ip: string; + name: string; + password: string; + port: string; + schema_version: string; + 'type': string; + user: string; + version: string; + _admin: ADMIN; + _id: string; +} + +/** Interface for _ADMIN */ +interface ADMIN { + created: number; + current_operation: boolean; + deployed: Deployed; + 'detailed-status': string; + modified: number; + operationalState: string; + operations: Operation[]; + projects_read: string[]; + projects_write: string[]; +} + +/** Interface for Deployed */ +interface Deployed { + RO: string; +} + +/** Interface for Operations */ +interface Operation { + 'detailed-status': string; + lcmOperationType: string; + operationParams: string; + operationState: string; + startTime: number; + statusEnteredTime: number; + worker: string; +} + +/** Interface for SDNControllerList */ +export interface SDNControllerList { + name: string; + id?: string; + identifier: string; + 'type': string; + operationalState: string; + ip: string; + port: string; +} diff --git a/src/models/UserModel.ts b/src/models/UserModel.ts new file mode 100644 index 0000000..83dd08b --- /dev/null +++ b/src/models/UserModel.ts @@ -0,0 +1,68 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Model for user related information. + */ + +/** Interface for UserDetails */ +export interface UserDetails { + userDetail: UserDetail[]; +} + +/** Interface for UserDetail */ +export interface UserDetail { + username: string; + password?: string; + _id?: string; + projects: string[]; + _admin?: Admin; + modified: string; + created: string; + identifier: string; + projectListName?: string; + project_role_mappings?: ProjectRoleMappings[]; +} + +/** Interface for user role mappings */ +export interface UserRoleMap { + project_role_mappings?: ProjectRoleMappings[]; +} + +/** Interface for Admin */ +interface Admin { + salt: string; + created: number; + modified: number; +} +/** Interface for UserDetail */ +export interface UserData { + username: string; + projects: string; + modified: string; + created: string; + identifier: string; +} + +/** Interface for Project Roles Mappings */ +export interface ProjectRoleMappings { + project?: string; + project_name?: string; + role?: string; + role_name?: string; +} diff --git a/src/models/VNFDModel.ts b/src/models/VNFDModel.ts new file mode 100644 index 0000000..908f552 --- /dev/null +++ b/src/models/VNFDModel.ts @@ -0,0 +1,274 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for VNFD related information. + */ + +/** Interface for Project */ +export interface ProjectModel { + project_id: string; + project?: string; + project_name?: string; + expires: number; + _id: string; + id: string; + issued_at: number; + remote_port: number; + username: string; + remote_host: string; + admin: boolean; +} + +/** Interface for ProjectDetails */ +export interface ProjectDetails { + _admin: AdminDetails; + name: string; + _id: string; +} + +/** Interface for AdminDetails */ +interface AdminDetails { + modified: string; + created: string; +} + +/** Interface for VNFD NODE Details */ +export interface VNFDNODE { + nodeTypeRef?: string; + 'connection-point'?: CONNECTIONPOINT[]; + description?: string; + id: string; + 'internal-vld'?: InternalVLD[]; + version?: string; + name?: string; + 'mgmt-interface'?: MGMT; + _id?: string; + vdu?: VDU[]; + _admin?: VNFDAdminDetails; + 'short-name'?: string; + shortName?: string; + vendor?: string; + 'type'?: string; + 'cloud-init-file'?: string; + count?: number; + vduID?: string; + 'interface'?: VNFDInterface[]; + 'vm-flavor'?: VMFlavor; + intVLID?: string; + 'internal-connection-point'?: VLDInternalConnectionPoint[]; + 'monitoring-param'?: MonitoringParam[]; + 'ip-profile-ref'?: string; + 'id-ref'?: string; + 'ip-address'?: string; + reflexive?: boolean; + image?: string; +} + +/** Interface for VNFDDetails */ +export interface VNFDDetails { + 'connection-point': CONNECTIONPOINT[]; + description: string; + id: string; + 'internal-vld': InternalVLD[]; + version: string; + name: string; + 'mgmt-interface': MGMT; + _id: string; + vdu: VDU[]; + _admin: VNFDAdminDetails; + 'short-name': string; + vendor: string; +} + +/** Interface for MGMT */ +interface MGMT { + cp: string; +} + +/** Interface for VDU */ +export interface VDU { + nodeTypeRef?: string; + 'cloud-init-file'?: string; + count?: number; + description?: string; + id?: string; + image?: string; + 'interface'?: VNFDInterface[]; + 'internal-connection-point'?: VDUInternalConnectionPoint[]; + name?: string; + 'vm-flavor'?: VMFlavor; + vduInterface?: string; + 'monitoring-param'?: MonitoringParam[]; +} + +/** Interface for VMFlavor */ +interface VMFlavor { + 'storage-gb'?: string; + 'memory-mb'?: string; + 'vcpu-count'?: string; +} + +/** Interface for VNFDInterface */ +export interface VNFDInterface { + 'external-connection-point-ref'?: string; + 'internal-connection-point-ref'?: string; + 'mgmt-interface'?: boolean; + name?: string; + 'type'?: string; + position?: boolean; + 'virtual-interface'?: VirtualInterface; +} + +/** Interface for VDU Internal Connection Point */ +export interface VDUInternalConnectionPoint { + id: string; + name?: string; + 'short-name'?: string; + 'type'?: string; +} + +/** Interface for VirutalInterface */ +interface VirtualInterface { + 'type': string; +} + +/** Interface for the connection-point */ +export interface CONNECTIONPOINT { + nodeTypeRef?: string; + 'connection-point-id'?: string; + name?: string; + id: string; + 'type'?: string; +} + +/** Interface for Internal VLD */ +export interface InternalVLD { + nodeTypeRef?: string; + id?: string; + 'internal-connection-point'?: VLDInternalConnectionPoint[]; + 'ip-profile-ref'?: string; + name?: string; + 'short-name'?: string; + 'type'?: string; + 'shortName'?: string; + 'ipProfileRef'?: string; +} + +/** Interface for VLD Internal Connection Point */ +export interface VLDInternalConnectionPoint { + nodeTypeRef?: string; + 'ip-address'?: string; + 'id-ref'?: string; + 'shortName'?: string; +} + +/** Interface for monitoring params */ +export interface MonitoringParam { + id: string; + 'nfvi-metric'?: string; + 'interface-name-ref'?: string; +} + +/** Interface for _AdminDetails */ +// tslint:disable-next-line:class-name +export interface VNFDAdminDetails { + created: number; + modified: string; + onboardingState: string; + operationalState: string; + projects_read: string[]; + projects_write: string[]; + storage: Storage; + 'type': string; + usageState: string; + userDefinedData: JSON; +} + +/** Interface for Storage */ +interface Storage { + descriptor: string; + folder: string; + fs: string; + path: string; + 'pkg-dir': string; + zipfile: string; +} + +/** Interface for VNFData */ +export interface VNFData { + name?: string; + id?: string; + shortName: string; + identifier: string; + description: string; + vendor: string; + version: string; + 'type'?: string; +} + +/** Interface for the Tick */ +export interface Tick { + target: TickPath; + source: TickPath; + left: boolean; + right: boolean; +} + +/** Interface for the Path */ +export interface TickPath { + x: number; + y: number; + id: string; + 'type'?: string; +} + +/** Interface Nodes Creation */ +export interface COMPOSERNODES { + id: string; + reflexive?: boolean; + 'type'?: string; + name?: string; + nodeTypeRef?: string; + x?: number; + y?: number; + fx?: number; + fy?: number; +} + +/** Interface for the GRAPHDETAILS */ +export interface GRAPHDETAILS { + width: number; + height: number; + nodeHeight: number; + nodeWidth: number; + textX: number; + textY: number; + radius: number; + distance: number; + strength: number; + forcex: number; + forcey: number; + sourcePaddingYes: number; + sourcePaddingNo: number; + targetPaddingYes: number; + targetPaddingNo: number; + alphaTarget: number; + imageX: number; + imageY: number; + shiftKeyCode: number; +} diff --git a/src/models/VNFInstanceModel.ts b/src/models/VNFInstanceModel.ts new file mode 100644 index 0000000..37f3bf3 --- /dev/null +++ b/src/models/VNFInstanceModel.ts @@ -0,0 +1,81 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for VNF Instance related information. + */ + +/** Interface for VNFInstanceDetails */ +export interface VNFInstanceDetails { + id: string; + 'ip-address': string; + 'vnfd-id': string; + 'created-time': string; + 'vim-account-id': string; + vdur: VDUR[]; + 'vnfd-ref': string; + 'member-vnf-index-ref': string; + _id: string; + additionalParamsForVnf: string; + _admin: Admin; + 'connection-point': ConnectionPoint[]; + 'nsr-id-ref': string; +} + +/** Interface for VDUR */ +interface VDUR { + 'ip-address': string; + 'vim-id': string; + 'internal-connection-point': string[]; + name: string; + 'vdu-id-ref': string; + 'status-detailed': string; + 'count-index': number; + interfaces: VDURInterface[]; + _id: string; + status: string; +} + +/** Interface for VDURInterface */ +interface VDURInterface { + 'mac-address': string; + name: string; + 'ns-vld-id': string; + 'mgmt-vnf': string; + 'ip-address': string; +} + +/** Interface for _Admin */ +interface Admin { + created: number; + projects_read: string[]; + modified: string; + projects_write: string[]; +} + +/** Interface for ConnectionPoint */ +interface ConnectionPoint { + id: string; + name: string; + 'connection-point-id': string; +} +/** interface for the History nsdInstanceData */ +export interface VNFInstanceData { + identifier: string; + VNFD?: string; + VNFID?: string; +} diff --git a/src/models/VimAccountModel.ts b/src/models/VimAccountModel.ts new file mode 100644 index 0000000..ea1cb71 --- /dev/null +++ b/src/models/VimAccountModel.ts @@ -0,0 +1,136 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model for VimAccount Details related information. + */ + +import { NSInstanceDetails } from 'NSInstanceModel'; + +/** Interface for VimAccountDetails */ +export interface VimAccountDetails { + description: string; + 'vim_tenant_name': string; + schema_version: string; + schema_type: string; + config: CONFIG; + _id: string; + vim_password: string; + _admin: ADMIN; + vim_url: string; + vim_user: string; + vim_type: string; + name: string; +} + +/** Interface for _ADMIN */ +interface ADMIN { + projects_write: string[]; + deployed: Deployed; + operationalState: string; + modified: string; + projects_read: string[]; + 'detailed-status': string; + created: string; +} + +/** Interface for Deployed */ +interface Deployed { + 'RO-account': string; + RO: string; +} + +/** Interface for Config */ +export interface CONFIG { + sdn_controller?: string; + use_floating_ip?: string; + location?: string; + sdn_port_mapping?: string; + vim_network_name?: string; + security_groups?: string; + availabilityZone?: string; + region_name?: string; + insecure?: string; + use_existing_flavors?: string; + use_internal_endpoint?: string; + additional_conf?: string; + APIversion?: string; + project_domain_id?: string; + project_domain_name?: string; + user_domain_id?: string; + user_domain_name?: string; + keypair?: string; + dataplane_physical_net?: string; + microversion?: string; + vpc_cidr_block?: string; + flavor_info?: string; + orgname?: string; + vcenter_ip?: string; + vcenter_port?: string; + admin_username?: string; + vcenter_user?: string; + admin_password?: string; + vcenter_password?: string; + nsx_manager?: string; + vrops_site?: string; + nsx_user?: string; + vrops_user?: string; + nsx_password?: string; + vrops_password?: string; + subscription_id?: string; + resource_group?: string; + vnet_name?: string; + flavors_pattern?: string; +} + +/** Interface for VIMData */ +export interface VIMData { + name?: string; + identifier: string; + 'type': string; + operationalState: string; + description: string; + page?: string; + instancesData?: NSInstanceDetails[]; +} +/** Interface for VIMLOCATION */ +export interface VIMLOCATION { + features: FEATURES[]; + 'type': string; +} +/** Interface for FEATURES */ +export interface FEATURES { + geometry: GEOMETRY; + 'type': string; + properties: PROPERTIES; +} +/** Interface for GEOMETRY */ +interface GEOMETRY { + coordinates: []; +} +/** Interface for PROPERTIES */ +interface PROPERTIES { + extent: []; + country: string; + name: string; + state: string; +} +/** Interface for the VIMLOCATIONDATA */ +export interface VIMLOCATIONDATA { + label: string; + value: string; +} diff --git a/src/models/WIMAccountModel.ts b/src/models/WIMAccountModel.ts new file mode 100644 index 0000000..190dfcd --- /dev/null +++ b/src/models/WIMAccountModel.ts @@ -0,0 +1,80 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Model For WIM Account Details Information. + */ + +/** Interface for WIMAccountModel */ +export interface WIMAccountModel { + config: {}; + description: string; + name: string; + password: string; + schema_version: string; + user: string; + wim_type: string; + wim_url: string; + _admin: ADMIN; + _id: string; +} + +/** Interface for _ADMIN */ +interface ADMIN { + created: number; + current_operation: boolean; + deployed: Deployed; + 'detailed-status': string; + modified: number; + operationalState: string; + operations: Operation[]; + projects_read: string[]; + projects_write: string[]; +} + +/** Interface for Deployed */ +interface Deployed { + 'RO-account': string; + RO: string; +} + +/** Interface for Operations */ +interface Operation { + 'detailed-status': string; + lcmOperationType: string; + operationParams: string; + operationState: string; + startTime: number; + statusEnteredTime: number; + worker: string; +} + +/** Interface for WIMAccountData */ +export interface WIMAccountData { + name?: string; + identifier: string; + 'type': string; + operationalState: string; + description: string; + page?: string; +} + +/** Interface for WIM Row Values */ +export interface WIMValue { + name: string; + identifier: string; +} diff --git a/src/polyfills.ts b/src/polyfills.ts new file mode 100644 index 0000000..5167690 --- /dev/null +++ b/src/polyfills.ts @@ -0,0 +1,84 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * This file includes polyfills needed by Angular and is loaded before the app. + * You can add your own extra polyfills to this file. + * + * This file is divided into 2 sections: + * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. + * 2. Application imports. Files imported after ZoneJS that should be loaded before your main + * file. + * + * The current setup is for so-called "evergreen" browsers; the last versions of browsers that + * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), + * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. + * + * Learn more in https://angular.io/guide/browser-support + */ + +/*************************************************************************************************** + * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. + */ +import '@angular/localize/init'; + +/*************************************************************************************************** + * BROWSER POLYFILLS + */ + +/** IE10 and IE11 requires the following for NgClass support on SVG elements */ +// import 'classlist.js'; // Run `npm install --save classlist.js`. + +/** + * Web Animations `@angular/platform-browser/animations` + * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. + * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). + */ +import 'web-animations-js'; // Run `npm install --save web-animations-js`. + +/** + * By default, zone.js will patch all possible macroTask and DomEvents + * user can disable parts of macroTask/DomEvents patch by setting following flags + * because those flags need to be set before `zone.js` being loaded, and webpack + * will put import in the top of bundle, so user need to create a separate file + * in this directory (for example: zone-flags.ts), and put the following flags + * into that file, and then add the following code before importing zone.js. + * import './zone-flags.ts'; + * + * The flags allowed in zone-flags.ts are listed here. + * + * The following flags will work for all browsers. + * + * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame + * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick + * (window as any).__zone_symbol__BLACK_LISTED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames + * + * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js + * with the following flag, it will bypass `zone.js` patch for IE/Edge + * + * (window as any).__Zone_enable_cross_context_check = true; + * + */ + +/*************************************************************************************************** + * Zone JS is required by default for Angular itself. + */ +import 'zone.js/dist/zone'; // Included with Angular CLI. + +/*************************************************************************************************** + * APPLICATION IMPORTS + */ diff --git a/src/services/AcessGuardService.ts b/src/services/AcessGuardService.ts new file mode 100644 index 0000000..42d36a5 --- /dev/null +++ b/src/services/AcessGuardService.ts @@ -0,0 +1,43 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Auth gaurd + */ +import { Injectable } from '@angular/core'; +import { CanLoad, Route } from '@angular/router'; +import { Observable } from 'rxjs'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable() +export class AcessGuardService implements CanLoad { + /** + * check if module can be loaded + */ + public canLoad(route: Route): Observable | Promise | boolean { + // Need to get the Role and valid here for authorization + if (localStorage.getItem('role') === 'Admin') { + return true; + } else { + return false; + } + } +} diff --git a/src/services/AuthGuardService.ts b/src/services/AuthGuardService.ts new file mode 100644 index 0000000..0c8d1e4 --- /dev/null +++ b/src/services/AuthGuardService.ts @@ -0,0 +1,61 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Auth gaurd + */ +import { Injectable } from '@angular/core'; +import { ActivatedRouteSnapshot, CanActivate, Router, RouterStateSnapshot } from '@angular/router'; +import { AuthenticationService } from 'AuthenticationService'; +import { Observable } from 'rxjs'; +import { map, take } from 'rxjs/operators'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable() +export class AuthGuardService implements CanActivate { + /** Holds teh instance of AuthService class of type AuthService @private */ + private router: Router; + /** Holds teh instance of Router class of type Router @private */ + private authService: AuthenticationService; + + constructor(router: Router, authService: AuthenticationService) { + this.router = router; + this.authService = authService; + } + + /** + * Returns Observable if authorized @public + */ + public canActivate(next: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable { + return this.authService.isLoggedIn + .pipe( + take(1), + map((isLoggedIn: boolean) => { + if (!isLoggedIn) { + this.router.navigate(['/login']).catch(() => { + //TODO: Handle error notification + }); + } + return true; + }) + ); + } +} diff --git a/src/services/AuthInterceptorService.ts b/src/services/AuthInterceptorService.ts new file mode 100644 index 0000000..ede10a8 --- /dev/null +++ b/src/services/AuthInterceptorService.ts @@ -0,0 +1,126 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file HttpInterceptor file + */ +import { + HttpErrorResponse, HttpHandler, HttpHeaderResponse, HttpInterceptor, HttpProgressEvent, + HttpRequest, HttpResponse, HttpSentEvent, HttpUserEvent +} from '@angular/common/http'; +import { Injectable, Injector } from '@angular/core'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { AuthenticationService } from 'AuthenticationService'; +import * as HttpStatus from 'http-status-codes'; +import { Observable, throwError } from 'rxjs'; +import { catchError, retry } from 'rxjs/operators'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable() +export class AuthInterceptorService implements HttpInterceptor { + /** Holds header options @private */ + private clonedReq: HttpRequest<{}>; + + /** To inject services @private */ + private injector: Injector; + + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + + /** Contains tranlsate instance @private */ + private translateService: TranslateService; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + /** create the instance of the component */ + constructor(injector: Injector) { + this.injector = injector; + this.notifierService = this.injector.get(NotifierService); + this.authService = this.injector.get(AuthenticationService); + this.translateService = this.injector.get(TranslateService); + } + + /** + * intercept logic + * @param req + * @param next + */ + public intercept(req: HttpRequest<{}>, next: HttpHandler): Observable | HttpUserEvent | any> { + const idToken: string = localStorage.getItem('id_token'); + const excludedUrl: string[] = ['osm/admin/v1/tokens', 'assets/i18n/', 'osm/version']; + if (excludedUrl.some((x: string): boolean => { return req.url.includes(x); })) { return next.handle(req); } + if (idToken.length > 0) { + this.setHeader(req, idToken); + return next.handle(this.clonedReq).pipe( + catchError((err: HttpErrorResponse) => { + this.errorRes(err, req, next); + return throwError(err); + }) + ); + } else { + //TODO: Handle error via notification service + } + } + + /** Set header options @public */ + // tslint:disable-next-line:no-any + public setHeader(req: HttpRequest, idToken: string): void { + if (req.body !== null && req.body.byteLength !== null) { + this.clonedReq = req.clone({ + setHeaders: { Authorization: 'Bearer ' + idToken, 'Cache-Control': 'no-cache', Pragma: 'no-cache' } + }); + } else { + this.clonedReq = req.clone({ + setHeaders: { Authorization: 'Bearer ' + idToken, 'Content-Type': 'charset=UTF-8', + 'Cache-Control': 'no-cache', Pragma: 'no-cache' } + }); + } + } + + /** Handles error response @public */ + public errorRes(err: HttpErrorResponse, req: HttpRequest<{}>, next: HttpHandler): Observable<{}> { + if (err instanceof HttpErrorResponse) { + switch (err.status) { + case HttpStatus.UNAUTHORIZED || HttpStatus.FORBIDDEN: + this.handleError(err); + break; + default: return throwError(err); + } + } else { return throwError(err); } + } + + /** Method to handle 401 & 403 error */ + private handleError(err: HttpErrorResponse): void { + if (err.error.detail === 'Expired Token or Authorization HTTP header' || + err.error.detail === 'Invalid Token or Authorization HTTP header') { + this.notifierService.hideAll(); + this.authService.logoutResponse(); + if (this.authService.handle401) { + this.notifierService.notify('error', this.translateService.instant('SESSIONEXPIRY')); + this.authService.handle401 = false; + } + } + } +} diff --git a/src/services/AuthenticationService.ts b/src/services/AuthenticationService.ts new file mode 100644 index 0000000..728d4ac --- /dev/null +++ b/src/services/AuthenticationService.ts @@ -0,0 +1,195 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Auth service + */ +import { HttpHeaders } from '@angular/common/http'; +import { Injectable, Injector } from '@angular/core'; +import { Router } from '@angular/router'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { Idle } from '@ng-idle/core'; +import { APIURLHEADER, ERRORDATA } from 'CommonModel'; +import { environment } from 'environment'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { isNullOrUndefined } from 'util'; +import { ProjectModel } from '../models/VNFDModel'; +import { RestService } from './RestService'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable() +export class AuthenticationService { + /** + * Get method for Observable loggedIn + */ + get isLoggedIn(): Observable { + return this.loggedIn.asObservable(); + } + + /** + * Get method for Observable Username + */ + get username(): Observable { + return this.userName.asObservable(); + } + + /** Get method for project name */ + get ProjectName(): Observable { + return this.projectName$.asObservable(); + } + /** To inject services @public */ + public injector: Injector; + + /** Instance for modal service @public */ + public modalService: NgbModal; + + /** Handle 401 response for multiple API calls */ + public handle401: boolean = true; + + /** contains return URL link @public */ + public returnUrl: string; + + /** Holds the username in condition of type BehaviorSubject @public */ + public userName: BehaviorSubject = new BehaviorSubject(''); + + /** Holds the projectname in condition of type BehaviorSubject @public */ + public projectName$: BehaviorSubject = new BehaviorSubject(''); + + /** Holds the instance of router class @private */ + private router: Router; + + /** Holds the logged in condition of type BehaviorSubject @private */ + private loggedIn: BehaviorSubject = new BehaviorSubject(false); + + /** Hold Rest Service Objects */ + private restService: RestService; + + /** Holds auth payloads @private */ + private payLoad: {}; + + /** Holds header options for auth service @private */ + private httpOptions: HttpHeaders; + + /** handle idle time out service @private */ + private idle: Idle; + + /** create the instance of the component */ + constructor(injector: Injector) { + this.injector = injector; + this.router = this.injector.get(Router); + this.restService = this.injector.get(RestService); + this.modalService = this.injector.get(NgbModal); + this.idle = this.injector.get(Idle); + if (localStorage.getItem('id_token') !== null) { + this.loggedIn.next(true); + } else { + this.loggedIn.next(false); + } + this.userName.next(localStorage.getItem('username')); + } + + /** + * Send request and authenticate the user + * @param user of type User + */ + public login(username: string, password: string): Observable<{}> { + this.setHeader(); + this.setPayLoad(username, password); + const apiURLHeader: APIURLHEADER = { + url: environment.GENERATETOKEN_URL, + httpOptions: { headers: this.httpOptions } + }; + return this.restService.postResource(apiURLHeader, this.payLoad) + .pipe(map((data: ProjectModel) => { + if (data) { + this.setLocalStorage(data); + this.idle.watch(true); + this.loggedIn.next(true); + this.handle401 = true; + this.userName.next(data.username); + return this.loggedIn; + } + }, (error: ERRORDATA) => { this.restService.handleError(error, 'post'); } + )); + } + + /** Set headers for auth session @public */ + public setHeader(): void { + this.httpOptions = new HttpHeaders({ + 'Content-Type': 'application/json; charset=UTF-8', + Accept: 'application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }); + } + + /** Set payloads for auth session @public */ + public setPayLoad(username: string, password: string): void { + this.payLoad = JSON.stringify({ + username, + password + }); + } + + /** set local storage on auth process @public */ + public setLocalStorage(data: ProjectModel): void { + localStorage.setItem('id_token', data.id); + localStorage.setItem('expires', data.expires.toString()); + localStorage.setItem('username', data.username); + localStorage.setItem('isAdmin', (data.admin) ? 'true' : 'false'); + localStorage.setItem('project_id', data.project_id); + localStorage.setItem('project', data.project_name); + localStorage.setItem('token_state', data.id); + this.projectName$.next(data.project_name); + } + /** Destory tokens API response handling @public */ + public logoutResponse(): void { + this.loggedIn.next(false); + const langCode: string = localStorage.getItem('languageCode'); + const redirecturl: string = isNullOrUndefined(localStorage.getItem('returnUrl')) ? '/' : localStorage.getItem('returnUrl'); + localStorage.clear(); + localStorage.setItem('languageCode', langCode); + localStorage.setItem('returnUrl', redirecturl); + localStorage.setItem('token_state', null); + this.idle.stop(); + this.router.navigate(['login']).catch(); + } + /** + * Logout the user & clearing the token. + */ + public logout(): void { + this.returnUrl = this.router.url; + localStorage.setItem('returnUrl', this.returnUrl); + this.modalService.dismissAll(); + this.destoryToken(); + } + /** Destory tokens on logout @private */ + private destoryToken(): void { + const tokenID: string = localStorage.getItem('id_token'); + if (tokenID !== null) { + const deletingURl: string = environment.GENERATETOKEN_URL + '/' + tokenID; + this.restService.deleteResource(deletingURl).subscribe((res: {}) => { + this.logoutResponse(); + }, (error: ERRORDATA) => { + this.restService.handleError(error, 'delete'); + }); + } + } +} diff --git a/src/services/DataService.ts b/src/services/DataService.ts new file mode 100644 index 0000000..e64c34c --- /dev/null +++ b/src/services/DataService.ts @@ -0,0 +1,40 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Data Services for user related information. + */ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; + +/** + * This file created during the angular project creation + */ +@Injectable() +/** Exporting a class @exports DataService */ +export class DataService { + /** message source @public */ + public messageSource: BehaviorSubject<{}> = new BehaviorSubject<{}>({}); + + /** current message @public */ + public currentMessage: Observable<{}> = this.messageSource.asObservable(); + /** change message function @public */ + public changeMessage(message: {}): void { + this.messageSource.next(message); + } +} diff --git a/src/services/DeviceCheckService.ts b/src/services/DeviceCheckService.ts new file mode 100644 index 0000000..98ab2fc --- /dev/null +++ b/src/services/DeviceCheckService.ts @@ -0,0 +1,52 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +import { Injectable } from '@angular/core'; +import { BehaviorSubject, Observable } from 'rxjs'; +/** + * @file Provider for Device Check Service + */ +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable({ + providedIn: 'root' +}) +/** Exporting a class @exports DeviceCheckService */ +export class DeviceCheckService { + /** Get method for Observable isMobile */ + get isMobile(): Observable { + return this.isMobile$.asObservable(); + } + /** Holds the mobile condition of type BehaviorSubject @private */ + private isMobile$: BehaviorSubject = new BehaviorSubject(false); + + /** Return the Device type @public */ + public checkDeviceType(): void { + if (navigator.userAgent.match(/Android/i) + || navigator.userAgent.match(/webOS/i) + || navigator.userAgent.match(/iPhone/i) + || navigator.userAgent.match(/iPod/i) + || navigator.userAgent.match(/BlackBerry/i) + || navigator.userAgent.match(/Windows Phone/i)) { + this.isMobile$.next(true); + } else { + this.isMobile$.next(false); + } + } +} diff --git a/src/services/ProjectService.ts b/src/services/ProjectService.ts new file mode 100644 index 0000000..c22f33a --- /dev/null +++ b/src/services/ProjectService.ts @@ -0,0 +1,114 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Project Service + */ +import { Injectable, Injector } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { AuthenticationService } from 'AuthenticationService'; +import { environment } from 'environment'; +import { ProjectData } from 'ProjectModel'; +import { BehaviorSubject, Observable, Subscription } from 'rxjs'; +import { SwitchProjectComponent } from 'SwitchProjectComponent'; +import { ProjectRoleMappings, UserDetail } from 'UserModel'; +import { ProjectModel } from 'VNFDModel'; +import { RestService } from './RestService'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable({ + providedIn: 'root' +}) +/** Exporting a class @exports ProjectService */ +export class ProjectService { + /** Get method for project list */ + get projectList(): Observable<{}[]> { + return this.projectList$.asObservable(); + } + /** To inject services @public */ + public injector: Injector; + + /** Holds all the projects details */ + public allProjectList: string[]; + + /** Observable holds logined value @public */ + public username$: Observable; + + /** Hold Rest Service Objects */ + private restService: RestService; + + /** Instance of the modal service @private */ + private modalService: NgbModal; + + /** Utilizes auth service for any auth operations @private */ + private authService: AuthenticationService; + + /** Holds the username in condition of type BehaviorSubject @private */ + private projectList$: BehaviorSubject<{}[]> = new BehaviorSubject<{}[]>([]); + + constructor(injector: Injector) { + this.injector = injector; + this.restService = this.injector.get(RestService); + this.modalService = this.injector.get(NgbModal); + this.authService = this.injector.get(AuthenticationService); + } + + /** List all the projects @public */ + public getAllProjects(): Observable<{}> { + return this.restService.getResource(environment.PROJECTS_URL); + } + + /** Get current project details from local storage @public */ + public getCurrentProjectDetails(): Observable<{}> { + const project: string = localStorage.getItem('project_id'); + return this.restService.getResource(environment.PROJECTS_URL + '/' + project); + } + + /** Returns all the projects for a particular users @public */ + public getUserProjects(): Observable<{}> { + const username: string = localStorage.getItem('username'); + return this.restService.getResource(environment.USERS_URL + '/' + username); + } + + /** Set header projects @public */ + public setHeaderProjects(): void { + this.getUserProjects().subscribe((projects: UserDetail) => { + const projectList: {}[] = projects.project_role_mappings; + projectList.filter((list: ProjectModel) => { + if (list.project === localStorage.getItem('project_id')) { + localStorage.setItem('project', list.project_name); + this.authService.projectName$.next(list.project_name); + } + }); + const projectDistinctList: {}[] = projectList.filter( + (thing: ProjectRoleMappings, i: number, arr: []) => arr + .findIndex((t: ProjectRoleMappings) => t.project_name === thing.project_name) === i + ); + this.projectList$.next(projectDistinctList); + }); + } + + /** Toggle projects on selection @public */ + public switchProjectModal(list: ProjectData): void { + const username: string = localStorage.getItem('username'); + this.modalService.open(SwitchProjectComponent, { backdrop: 'static' }) + .componentInstance.params = { projectID: list.project, username }; + } +} diff --git a/src/services/RestService.ts b/src/services/RestService.ts new file mode 100644 index 0000000..d7ded6f --- /dev/null +++ b/src/services/RestService.ts @@ -0,0 +1,144 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ + +/** + * @file Provider for REST Service + */ + +import { HttpClient, HttpHeaders } from '@angular/common/http'; +import { Injectable } from '@angular/core'; +import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; +import { TranslateService } from '@ngx-translate/core'; +import { NotifierService } from 'angular-notifier'; +import { ERRORDATA } from 'CommonModel'; +import * as HttpStatus from 'http-status-codes'; +import { Observable } from 'rxjs'; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable() +/** Exporting a class @exports RestService */ +export class RestService { + /** convenient way to modify request made by the http service both before they are sent and after they return */ + private http: HttpClient; + /** API URL. Disabled tslint since server doesn't support https protocol */ + private apiURL: string = ''; + /** Notifier service to popup notification @private */ + private notifierService: NotifierService; + /** Instance for active modal service @public */ + private activeModal: NgbModal; + /** insatnce for translate @private */ + private translateService: TranslateService; + + constructor(http: HttpClient, notifierService: NotifierService, activeModal: NgbModal, translateService: TranslateService) { + this.http = http; + this.notifierService = notifierService; + this.activeModal = activeModal; + this.translateService = translateService; + } + + /** + * Get a resource from the server which identified by a URI. + * @param apiURL The URL of the resource to be retrieved. + */ + + public getResource(apiURL: string, httpHeaders?: { headers: HttpHeaders }): Observable<{}> { + return this.http.get(apiURL, httpHeaders); + } + + /** + * Create a new resource on the server. + * @param apiURL The URL of the resource to be created. + * @param payload The request data to be sent to server. + */ + + public postResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable<{}> { + return this.http.post(apiURLHeader.url, payload, apiURLHeader.httpOptions); + } + + /** + * Modify the resource on the server. + * @param apiURL The URL of the resource to be created. + * @param payload The request data to be sent to server. + */ + + public patchResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable { + return this.http.patch(apiURLHeader.url, payload, apiURLHeader.httpOptions); + } + + /** + * Replace the resource on the server. + * @param apiName The URL of the resource to be created. + * @param payload The request data to be sent to server. + */ + + public putResource(apiURLHeader: { url: string, httpOptions?: { headers: HttpHeaders } }, payload: {}): Observable { + return this.http.put(apiURLHeader.url, payload, apiURLHeader.httpOptions); + } + + /** + * Delete a resource identified by a URL. + * @param apiURL The URL of the resource to be deleted. + */ + + public deleteResource(apiURL: string, httpHeaders?: { headers: HttpHeaders }): Observable { + return this.http.delete(apiURL, httpHeaders); + } + /** + * Handle Error response based on the status. + * @param error The error response reecieved from API call. + * @param method The http request method. + */ + // tslint:disable-next-line: cyclomatic-complexity + public handleError(err: ERRORDATA, method?: string): void { + if (err.error.status === HttpStatus.UNAUTHORIZED) { + if (method !== 'get') { + if (err.error.detail !== 'Expired Token or Authorization HTTP header' && + err.error.detail !== 'Invalid Token or Authorization HTTP header') { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('HTTPERROR.401')); + } + this.activeModal.dismissAll(); + } + } else if (err.error.status === HttpStatus.BAD_REQUEST) { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('HTTPERROR.400')); + } else if (err.error.status === HttpStatus.NOT_FOUND) { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('HTTPERROR.404')); + } else if (err.error.status === HttpStatus.CONFLICT) { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('HTTPERROR.409')); + this.activeModal.dismissAll(); + } else if (err.error.status === HttpStatus.INTERNAL_SERVER_ERROR) { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('HTTPERROR.500')); + } else if (err.error.status === HttpStatus.BAD_GATEWAY) { + this.notifierService.notify('error', this.translateService.instant('HTTPERROR.502')); + } else if (err.error.status === HttpStatus.SERVICE_UNAVAILABLE) { + this.notifierService.notify('error', this.translateService.instant('HTTPERROR.503')); + } else if (err.error.status === HttpStatus.GATEWAY_TIMEOUT) { + this.notifierService.notify('error', this.translateService.instant('HTTPERROR.504')); + } else { + this.notifierService.notify('error', err.error.detail !== undefined ? + err.error.detail : this.translateService.instant('ERROR')); + } + } +} diff --git a/src/services/SharedService.ts b/src/services/SharedService.ts new file mode 100644 index 0000000..3a138e5 --- /dev/null +++ b/src/services/SharedService.ts @@ -0,0 +1,304 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file Provider for Shared Service + */ +import { HttpErrorResponse, HttpHeaders } from '@angular/common/http'; +import { EventEmitter, Injectable, Output } from '@angular/core'; +import { FormArray, FormGroup } from '@angular/forms'; +import { Router } from '@angular/router'; +import { CONSTANTNUMBER, ERRORDATA, GETAPIURLHEADER, PACKAGEINFO, PAGERSMARTTABLE, SMARTTABLECLASS, TARSETTINGS } from 'CommonModel'; +import { environment } from 'environment'; +import * as HttpStatus from 'http-status-codes'; +import * as untar from 'js-untar'; +import * as pako from 'pako'; +import { RestService } from 'RestService'; +import { isNullOrUndefined } from 'util'; + +/** This is added globally by the tar.js library */ +// tslint:disable-next-line: no-any +declare const Tar: any; + +/** + * An Injectable is a class adorned with the @Injectable decorator function. + * @Injectable takes a metadata object that tells Angular how to compile and run module code + */ +@Injectable({ + providedIn: 'root' +}) +/** Exporting a class @exports SharedService */ +export class SharedService { + /** call the parent using event information @private */ + @Output() public dataEvent: EventEmitter<{}> = new EventEmitter<{}>(); + + /** Variables to hold regexp pattern for URL */ + // tslint:disable-next-line: max-line-length + public REGX_URL_PATTERN: RegExp = new RegExp(/^(http?|ftp|https):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.[a-zA-Z0-9]{2,15})(:((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4})))*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/); + + /** Variables to hold regexp pattern for IP Address */ + public REGX_IP_PATTERN: RegExp = new RegExp(/^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$/); + + /** Variables to hold regexp pattern for Port Number */ + // tslint:disable-next-line: max-line-length + public REGX_PORT_PATTERN: RegExp = new RegExp(/^((6553[0-5])|(655[0-2][0-9])|(65[0-4][0-9]{2})|(6[0-4][0-9]{3})|([1-5][0-9]{4})|([0-5]{0,5})|([0-9]{1,4}))$/); + + /** Variables to hold regexp pattern for DPID */ + public REGX_DPID_PATTERN: RegExp = new RegExp(/^[0-9a-fA-F]{2}(:[0-9a-fA-F]{2}){7}$/); + + /** Variable to hold regexp pattern for password */ + // tslint:disable-next-line: max-line-length + public REGX_PASSWORD_PATTERN: RegExp = new RegExp(/^.*(?=.{8,})((?=.*[!@#$%^&*()\-_=+{};:,<.>]){1})(?=.*\d)((?=.*[a-z]){1})((?=.*[A-Z]){1}).*$/); + + /** FormGroup instance added to the form @ html @public */ + public formGroup: FormGroup; + + /** Controls the go to top button on scroll @public */ + public showGotoTop: boolean; + + /** Holds OSM Version value @public */ + public osmVersion: string; + + /** express number for time manupulation -2 */ + private epochTimeMinus2: number = -2; + + /** express number for time manupulation 1000 */ + private epochTime1000: number = 1000; + + /** Random string generator length */ + private randomStringLength: number = 4; + + /** Instance of the rest service @private */ + private restService: RestService; + + /** Service holds the router information @private */ + private router: Router; + + /** Check for the root directory @private */ + private directoryCount: number = 2; + + constructor(restService: RestService, router: Router) { + this.restService = restService; + this.router = router; + } + + /** convert epoch time function @public */ + public convertEpochTime(unixtimestamp: number): string { + const monthsArr: string[] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', + 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + const date: Date = new Date(unixtimestamp * this.epochTime1000); + const year: number = date.getFullYear(); + const month: string = monthsArr[date.getMonth()]; + const day: number = date.getDate(); + const hours: number = date.getHours(); + const minutes: string = '0' + date.getMinutes(); + const seconds: string = '0' + date.getSeconds(); + return month + '-' + day + '-' + year + ' ' + hours + ':' + minutes.substr(this.epochTimeMinus2) + ':' + + seconds.substr(this.epochTimeMinus2); + } + + /** Download Files function @public */ + public downloadFiles(shortName: string, binaryData: Blob[], filetype: string): void { + const downloadLink: HTMLAnchorElement = document.createElement('a'); + downloadLink.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype })); + if (shortName !== undefined) { + if (window.navigator.msSaveOrOpenBlob) { + window.navigator.msSaveBlob(new Blob(binaryData, { type: filetype }), 'OSM_Export_' + shortName + '.tar.gz'); + } else { + downloadLink.setAttribute('download', 'OSM_Export_' + shortName + '.tar.gz'); + document.body.appendChild(downloadLink); + downloadLink.click(); + } + } + } + + /** Call this method after delete perform action is completed in the ng-smart-table data @public */ + public callData(): void { + this.dataEvent.emit(); + } + + /** Generate random string @public */ + public randomString(): string { + const chars: string = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'; + let result: string = ''; + // tslint:disable-next-line:no-increment-decrement + for (let randomStringRef: number = this.randomStringLength; randomStringRef > 0; --randomStringRef) { + result += chars[Math.floor(Math.random() * chars.length)]; + } + return result; + } + /** Function to read uploaded file String @public */ + public async getFileString(files: FileList, fileType: string): Promise { + const reader: FileReader = new FileReader(); + return new Promise((resolve: Function, reject: Function): void => { + if (this.vaildataFileInfo(files[0], fileType)) { + this.readFileContent(reader, files[0], fileType); + } else { + reject('typeError'); + } + reader.onload = (): void => { + if (reader.result === null) { + reject('contentError'); + } + resolve(reader.result); + }; + reader.onerror = (event: Event): void => { + reject('contentError'); + }; + }); + } + /** Method to handle tar and tar.gz file for shared YAML file content @public */ + public async targzFile(packageInfo: PACKAGEINFO): Promise { + return new Promise((resolve: Function, reject: Function): void => { + const httpOptions: GETAPIURLHEADER = this.getHttpOptions(); + let apiUrl: string = ''; + apiUrl = packageInfo.packageType === 'nsd' ? environment.NSDESCRIPTORS_URL + '/' + packageInfo.id + '/nsd_content' : + environment.VNFPACKAGES_URL + '/' + packageInfo.id + '/package_content'; + this.restService.getResource(apiUrl, httpOptions).subscribe((response: ArrayBuffer) => { + try { + // tslint:disable-next-line: no-any + const tar: any = new Tar(); + const originalInput: Uint8Array = pako.inflate(response, { to: 'Uint8Array' }); + untar(originalInput.buffer).then((extractedFiles: TARSETTINGS[]) => { + const getFoldersFiles: {}[] = extractedFiles; + const folderNameStr: string = extractedFiles[0].name; + getFoldersFiles.forEach((value: TARSETTINGS) => { + const getRootFolder: string[] = value.name.split('/'); + if (value.name.startsWith(folderNameStr) && + (value.name.endsWith('.yaml') || value.name.endsWith('.yml')) && + getRootFolder.length === this.directoryCount) { + tar.append(value.name, packageInfo.descriptor, { type: value.type }); + } else { + if (value.type !== 'L') { + tar.append(value.name, new Uint8Array(value.buffer), { type: value.type }); + } + } + }); + const out: Uint8Array = tar.out; + const originalOutput: Uint8Array = pako.gzip(out); + resolve(originalOutput.buffer); + }, (err: string) => { + reject(''); + }); + } catch (e) { + reject(''); + } + }, (error: HttpErrorResponse) => { + if (error.status === HttpStatus.NOT_FOUND || error.status === HttpStatus.UNAUTHORIZED) { + this.router.navigateByUrl('404', { skipLocationChange: true }).catch(); + } else { + this.restService.handleError(error, 'get'); + reject(''); + } + }); + }); + } + /** Method to check given string is JSON or not @public */ + public checkJson(jsonString: string): boolean { + jsonString = jsonString.replace(/'/g, '"'); + try { + JSON.parse(jsonString); + } catch (e) { + return false; + } + return true; + } + /** Clean the form before submit @public */ + public cleanForm(formGroup: FormGroup): void { + Object.keys(formGroup.controls).forEach((key: string) => { + if ((!isNullOrUndefined((formGroup.get(key) as FormArray | FormGroup).controls)) && key !== 'vimconfig') { + // tslint:disable-next-line: no-shadowed-variable + for (const { item, index } of (formGroup.get(key).value).map((item: {}, index: number) => ({ item, index }))) { + const newFormGroup: FormGroup = (formGroup.get(key) as FormArray).controls[index] as FormGroup; + this.cleanForm(newFormGroup); + } + } else if (formGroup.get(key).value !== undefined && formGroup.get(key).value !== null && key !== 'vimconfig') { + if (!Array.isArray(formGroup.get(key).value)) { + if (typeof formGroup.get(key).value === 'string') { + formGroup.get(key).setValue(formGroup.get(key).value.trim()); + } + } + } else if (key === 'vimconfig') { + const newFormGroup: FormGroup = formGroup.get(key) as FormGroup; + this.cleanForm(newFormGroup); + } + }); + } + /** Method to return the config of pager value for ngSmarttable @public */ + public paginationPagerConfig(): PAGERSMARTTABLE { + return { + display: true, + perPage: environment.paginationNumber + }; + } + /** Method to return the class for the table for ngSmarttable @public */ + public tableClassConfig(): SMARTTABLECLASS { + return { + class: 'table list-data' + }; + } + /** Method to return all languages name and its code @public */ + public languageCodeList(): {}[] { + return [ + { code: 'en', language: 'English' }, + { code: 'es', language: 'Spanish' }, + { code: 'pt', language: 'Portuguese' }, + { code: 'de', language: 'German' } + ]; + } + /** Fetch OSM Version @public */ + public fetchOSMVersion(): void { + this.restService.getResource(environment.OSM_VERSION_URL).subscribe((res: { version: string }) => { + const version: string[] = res.version.split('+'); + if (!isNullOrUndefined(version[0])) { + this.osmVersion = version[0]; + } else { + this.osmVersion = null; + } + }, (error: ERRORDATA) => { + this.osmVersion = null; + this.restService.handleError(error, 'get'); + }); + } + /** Method to validate file extension and size @private */ + private vaildataFileInfo(fileInfo: File, fileType: string): boolean { + const extension: string = fileInfo.name.substring(fileInfo.name.lastIndexOf('.') + 1); + const packageSize: number = CONSTANTNUMBER.oneMB * environment.packageSize; + if (extension.toLowerCase() === fileType && fileInfo.size <= packageSize) { + return true; + } + return false; + } + /** Method to read file content based on type @private */ + private readFileContent(reader: FileReader, fileInfo: File, fileType: string): void { + if (fileType === 'gz') { + reader.readAsArrayBuffer(fileInfo); + } else { + reader.readAsText(fileInfo); + } + } + /** Method to handle http options @public */ + private getHttpOptions(): GETAPIURLHEADER { + return { + headers: new HttpHeaders({ + Accept: 'application/gzip, application/json', + 'Cache-Control': 'no-cache, no-store, must-revalidate, max-age=0' + }), + responseType: 'arraybuffer' + }; + } +} diff --git a/src/test.ts b/src/test.ts new file mode 100644 index 0000000..cf21bef --- /dev/null +++ b/src/test.ts @@ -0,0 +1,44 @@ +/* + Copyright 2020 TATA ELXSI + + Licensed under the Apache License, Version 2.0 (the 'License'); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + Author: KUMARAN M (kumaran.m@tataelxsi.co.in), RAJESH S (rajesh.s@tataelxsi.co.in), BARATH KUMAR R (barath.r@tataelxsi.co.in) + */ +/** + * @file This file is required by karma.conf.js and loads recursively all the .spec and framework files. + */ +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting +} from '@angular/platform-browser-dynamic/testing'; +import 'zone.js/dist/zone-testing'; + +/** const variable require */ +// tslint:disable:no-reserved-keywords +// tslint:disable-next-line:no-any +declare const require: any; + +// First, initialize the Angular testing environment. +getTestBed().initTestEnvironment( + BrowserDynamicTestingModule, + platformBrowserDynamicTesting() +); + +/** const variable context */ +// Then we find all the tests. +// tslint:disable-next-line:typedef +const context = require.context('./', true, /\.spec\.ts$/); +// And load the modules. +context.keys().map(context); diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json new file mode 100644 index 0000000..384c218 --- /dev/null +++ b/src/tsconfig.app.json @@ -0,0 +1,16 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/app", + "types": [] + }, + "exclude": [ + "test.ts", + "**/*.spec.ts" + ], + "angularCompilerOptions": { + "enableIvy": true, + "fullTemplateTypeCheck": false, + "strictInjectionParameters": false + } +} \ No newline at end of file diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json new file mode 100644 index 0000000..0a65d17 --- /dev/null +++ b/src/tsconfig.spec.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig.json", + "compilerOptions": { + "outDir": "../out-tsc/spec", + "types": [ + "jasmine", + "node" + ] + }, + "files": [ + "test.ts", + "polyfills.ts" + ], + "include": [ + "**/*.spec.ts", + "**/*.d.ts" + ] +} diff --git a/src/tslint.json b/src/tslint.json new file mode 100644 index 0000000..52e2c1a --- /dev/null +++ b/src/tslint.json @@ -0,0 +1,17 @@ +{ + "extends": "../tslint.json", + "rules": { + "directive-selector": [ + true, + "attribute", + "app", + "camelCase" + ], + "component-selector": [ + true, + "element", + "app", + "kebab-case" + ] + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..fca2693 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,139 @@ +{ + "compileOnSave": false, + "compilerOptions": { + "resolveJsonModule": true, + "baseUrl": ".", + "downlevelIteration": true, + "outDir": "./dist/out-tsc", + "sourceMap": true, + "declaration": false, + "module": "esnext", + "moduleResolution": "node", + "emitDecoratorMetadata": true, + "experimentalDecorators": true, + "importHelpers": true, + "target": "es5", + "typeRoots": [ + "node_modules/@types" + ], + "lib": [ + "es2018", + "dom" + ], + "paths": { + "CommonModel": ["src/models/CommonModel"], + "environment": ["src/environments/environment"], + "AuthInterceptorService": ["src/services/AuthInterceptorService"], + "RestService": ["src/services/RestService"], + "SharedService": ["src/services/SharedService"], + "ProjectService": ["src/services/ProjectService"], + "DataService": ["src/services/DataService"], + "AuthenticationService": ["src/services/AuthenticationService"], + "AuthGuardService": ["src/services/AuthGuardService"], + "AcessGuardService": ["src/services/AcessGuardService"], + "DeviceCheckService": ["src/services/DeviceCheckService"], + "NSDModel":["src/models/NSDModel"], + "VimAccountModel" : ["src/models/VimAccountModel"], + "LayoutComponent": ["src/app/layouts/LayoutComponent"], + "SidebarComponent": ["src/app/layouts/sidebar/SidebarComponent"], + "HeaderComponent": ["src/app/layouts/header/HeaderComponent"], + "UserSettingsComponent": ["src/app/user-settings/UserSettingsComponent"], + "LoginComponent": ["src/app/login/LoginComponent"], + "DashboardComponent": ["src/app/dashboard/DashboardComponent"], + "NSPackages" : ["src/app/packages/ns-packages/NSPackagesComponent"], + "NsPackagesAction": ["src/app/utilities/ns-packages-action/NsPackagesActionComponent"], + "InstantiateNs": ["src/app/packages/instantiate-ns/InstantiateNsComponent"], + "ShowContent": ["src/app/packages/show-content/ShowContentComponent"], + "DeleteComponent": ["src/app/utilities/delete/DeleteComponent"], + "EditPackagesComponent": ["src/app/utilities/edit-packages/EditPackagesComponent"], + "NetsliceTemplate":["src/app/packages/netslice-template/NetsliceTemplateComponent"], + "DragDirective": ["src/app/utilities/dragDropUpload/DragDirective"], + "NSComposer": ["src/app/packages/ns-packages/ns-composer/NSComposerComponent"], + "VNFComposer": ["src/app/packages/ns-packages/vnf-composer/VNFComposerComponent"], + "Packages":["src/app/packages/PackagesComponent"], + "VNFPackages": ["src/app/packages/vnf-packages/VNFPackagesComponent"], + "VNFDModel": ["src/models/VNFDModel"], + "VNFPackagesAction" :["src/app/utilities/vnf-packages-action/VNFPackagesActionComponent"], + "NetworkSliceModel" : ["src/models/NetworkSliceModel"], + "NetslicePackagesAction" : ["src/app/utilities/netslice-packages-action/NetslicePackagesActionComponent"], + "PageNotFound" : ["src/app/page-not-found/PageNotFoundComponent"], + "ProjectsModule" : ["src/app/projects/ProjectsModule"], + "ProjectModel" : ["src/models/ProjectModel"], + "ProjectsComponent" : ["src/app/projects/ProjectsComponent"], + "ProjectCreateUpdate" : ["src/app/projects/project-create-update/ProjectCreateUpdateComponent"], + "ProjectsAction": ["src/app/utilities/projects-action/ProjectsActionComponent"], + "BreadCrumb": ["src/app/layouts/breadcrumb/BreadcrumbComponent"], + "VNFDEdit": ["src/app/packages/vnfd-edit/VNFDEditComponent"], + "VNFInstanceModel": ["src/models/VNFInstanceModel"], + "InstancesComponent": ["src/app/instances/InstancesComponent"], + "VNFInstancesComponent": ["src/app/instances/vnf-instances/VNFInstancesComponent"], + "NSInstancesComponent": ["src/app/instances/ns-instances/NSInstancesComponent"], + "HistoryOperationsComponent": ["src/app/instances/ns-history-operations/HistoryOperationsComponent"], + "NetsliceInstancesComponent": ["src/app/instances/netslice-instances/NetsliceInstancesComponent"], + "VNFInstancesActionComponent": ["src/app/utilities/vnf-instances-action/VNFInstancesActionComponent"], + "NSInstancesActionComponent": ["src/app/utilities/ns-instances-action/NSInstancesActionComponent"], + "NetsliceInstancesActionComponent": ["src/app/utilities/netslice-instances-action/NetsliceInstancesActionComponent"], + "NSInstanceModel": ["src/models/NSInstanceModel"], + "ShowInfoComponent": ["src/app/utilities/show-info/ShowInfoComponent"], + "NSTopologyComponent": ["src/app/instances/ns-topology/NSTopologyComponent"], + "NSTopologyModel": ["src/models/NSTopologyModel"], + "SDNControllerComponent": ["src/app/sdn-controller/SDNControllerComponent"], + "SDNControllerDetailsComponent": ["src/app/sdn-controller/sdn-controller-details/SDNControllerDetailsComponent"], + "SDNControllerInfoComponent": ["src/app/sdn-controller/sdn-controller-info/SDNControllerInfoComponent"], + "SDNControllerActionComponent": ["src/app/utilities/sdn-controller-action/SDNControllerActionComponent"], + "NewSDNControllerComponent": ["src/app/sdn-controller/new-sdn-controller/NewSDNControllerComponent"], + "SDNControllerModel": ["src/models/SDNControllerModel"], + "UserModel": ["src/models/UserModel"], + "UsersComponent": ["src/app/users/UsersComponent"], + "UserDetailsComponent": ["src/app/users/user-details/UserDetailsComponent"], + "AddEditUserComponent": ["src/app/users/add-user/AddEditUserComponent"], + "UsersActionComponent": ["src/app/utilities/users-action/UsersActionComponent"], + "ProjectRoleComponent": ["src/app/users/project-role/ProjectRoleComponent"], + "PagePerRow": ["src/app/utilities/page-per-row/PagePerRow"], + "PagePerRowModule": ["src/app/utilities/page-per-row/PagePerRowModule"], + "VimAccountsModule": ["src/app/vim-accounts/VimAccountsModule"], + "VimAccountsComponent": ["src/app/vim-accounts/VimAccountsComponent"], + "VimAccountDetails": ["src/app/vim-accounts/vim-account-details/VimAccountDetailsComponent"], + "NewVimaccount": ["src/app/vim-accounts/new-vimaccount/NewVimaccountComponent"], + "InfoVim": ["src/app/vim-accounts/info-vim/InfoVimComponent"], + "VimAccountsAction": ["src/app/utilities/vim-accounts-action/VimAccountsActionComponent"], + "InstantiateNetSliceTemplate":["src/app/packages/instantiate-net-slice-template/InstantiateNetSliceTemplateComponent"], + "LoaderComponent": ["src/app/utilities/loader/LoaderComponent"], + "LoaderModule": ["src/app/utilities/loader/LoaderModule"], + "NSPrimitiveComponent": ["src/app/instances/ns-primitive/NSPrimitiveComponent"], + "ConfirmationTopology": ["src/app/utilities/confirmation-topology/ConfirmationTopologyComponent"], + "ComposePackages": ["src/app/utilities/compose-packages/ComposePackages"], + "WIMAccountsAction": ["src/app/utilities/wim-accounts-action/WIMAccountsActionComponent"], + "WIMAccountsModule": ["src/app/wim-accounts/WIMAccountsModule"], + "WIMAccountsComponent": ["src/app/wim-accounts/WIMAccountsComponent"], + "WIMAccountDetails": ["src/app/wim-accounts/wim-account-details/WIMAccountDetailsComponent"], + "NewWIMAccount": ["src/app/wim-accounts/new-wim-account/NewWIMAccountComponent"], + "WIMAccountInfo": ["src/app/wim-accounts/wim-account-info/WIMAccountInfoComponent"], + "WIMAccountModel": ["src/models/WIMAccountModel"], + "Roles": ["src/app/roles/RolesComponent"], + "RolesDetails": ["src/app/roles/roles-details/RolesDetailsComponent"], + "RolesAction": ["src/app/utilities/roles-action/RolesActionComponent"], + "RolesCreateEdit": ["src/app/roles/roles-create-edit/RolesCreateEditComponent"], + "RolesModel": ["src/models/RoleModel"], + "PDUInstancesComponent": ["src/app/instances/pdu-instances/PDUInstancesComponent"], + "PDUInstanceModel": ["src/models/PDUInstanceModel"], + "PDUInstancesActionComponent": ["src/app/utilities/pdu-instances-action/PDUInstancesActionComponent"], + "AddPDUInstancesComponent": ["src/app/instances/pdu-instances/add-pdu-instances/AddPDUInstancesComponent"], + "ClonePackage": ["src/app/utilities/clone-package/ClonePackageComponent"], + "K8sComponent": ["src/app/k8s/K8sComponent"], + "K8sClusterComponent": ["src/app/k8s/k8scluster/K8sClusterComponent"], + "K8sRepositoryComponent":["src/app/k8s/k8srepository/K8sRepositoryComponent"], + "K8sActionComponent": ["src/app/k8s/k8s-action/K8sActionComponent"], + "K8sModel": ["src/models/K8sModel"], + "K8sAddClusterComponent": ["src/app/k8s/k8s-add-cluster/K8sAddClusterComponent"], + "K8sAddRepoComponent": ["src/app/k8s/k8s-add-repo/K8sAddRepoComponent"], + "SwitchProjectComponent": ["src/app/utilities/switch-project/SwitchProjectComponent"], + "ProjectLinkComponent":["src/app/utilities/project-link/ProjectLinkComponent"], + "PageReload": ["src/app/utilities/page-reload/PageReload"], + "PageReloadModule": ["src/app/utilities/page-reload/PageReloadModule"], + "GoToTopDirective": ["src/directive/GoToTopDirective"], + "VNFLinkComponent": ["src/app/instances/vnf-instances/vnf-link/VNFLinkComponent"], + "PACKAGEJSON": ["package.json"] + } + } +} \ No newline at end of file diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..ba584e0 --- /dev/null +++ b/tslint.json @@ -0,0 +1,299 @@ +{ + "linterOptions" : { + "exclude" : [ + "package.json" + ] + }, + "defaultSeverity": "error", + "rules": { + "insecure-random": false, + "no-banned-terms": true, + "no-cookies": true, + "no-delete-expression": true, + "no-disable-auto-sanitization": true, + "no-document-domain": true, + "no-document-write": true, + "no-eval": true, + "no-exec-script": true, + "no-function-constructor-with-string-args": true, + "no-http-string": [ + true, + "http://www.example.com/?.*", + "http://www.examples.com/?.*" + ], + "no-inner-html": true, + "no-octal-literal": true, + "no-reserved-keywords": true, + "no-string-based-set-immediate": true, + "no-string-based-set-interval": true, + "no-string-based-set-timeout": true, + "non-literal-require": true, + "possible-timing-attack": true, + "react-anchor-blank-noopener": true, + "react-iframe-missing-sandbox": true, + "react-no-dangerous-html": true, + "forin": true, + "jquery-deferred-must-complete": true, + "label-position": true, + "mocha-avoid-only": true, + "mocha-no-side-effect-code": true, + "no-any": true, + "no-arg": true, + "no-backbone-get-set-outside-model": true, + "no-bitwise": true, + "no-conditional-assignment": true, + "no-console": false, + "no-constant-condition": true, + "no-control-regex": true, + "no-debugger": true, + "no-duplicate-case": true, + "no-duplicate-variable": true, + "no-empty": true, + "no-increment-decrement": true, + "no-invalid-regexp": true, + "no-invalid-this": true, + "no-jquery-raw-elements": true, + "no-misused-new": true, + "no-regex-spaces": true, + "no-sparse-arrays": true, + "no-stateless-class": true, + "no-string-literal": true, + "no-string-throw": true, + "no-unnecessary-bind": true, + "no-unnecessary-initializer": true, + "no-unnecessary-override": true, + "no-unsafe-finally": true, + "no-unused-expression": true, + "no-with-statement": true, + "promise-must-complete": true, + "radix": true, + "react-this-binding-issue": true, + "react-unused-props-and-state": true, + "switch-default": true, + "triple-equals": [ + true, + "allow-null-check" + ], + "use-isnan": true, + "use-named-parameter": true, + "valid-typeof": true, + "adjacent-overload-signatures": true, + "array-type": [ + true, + "array" + ], + "arrow-parens": true, + "callable-types": true, + "chai-prefer-contains-to-index-of": true, + "chai-vague-errors": true, + "class-name": true, + "comment-format": true, + "export-name": true, + "function-name": true, + "import-name": true, + "interface-name": false, + "jsdoc-format": true, + "max-classes-per-file": [ + true, + 3 + ], + "max-file-line-count": true, + "max-func-body-length": [ + true, + 100, + { + "ignore-parameters-to-function-regex": "describe" + } + ], + "max-line-length": [ + true, + 140 + ], + "member-access": true, + "member-ordering": [ + true, + { + "order": "fields-first" + } + ], + "missing-jsdoc": true, + "mocha-unneeded-done": true, + "new-parens": true, + "no-construct": true, + "no-default-export": true, + "no-empty-interface": true, + "no-for-in": true, + "no-function-expression": true, + "no-inferrable-types": false, + "no-multiline-string": true, + "no-null-keyword": false, + "no-parameter-properties": true, + "no-relative-imports": false, + "no-require-imports": true, + "no-shadowed-variable": true, + "no-typeof-undefined": true, + "no-unnecessary-field-initialization": true, + "no-unnecessary-local-variable": true, + "no-var-keyword": true, + "no-var-requires": true, + "no-var-self": true, + "object-literal-sort-keys": false, + "one-variable-per-declaration": true, + "only-arrow-functions": [ + true, + "allow-declarations", + "allow-named-functions" + ], + "ordered-imports": true, + "prefer-array-literal": true, + "prefer-const": true, + "prefer-for-of": true, + "prefer-method-signature": true, + "typedef": [ + true, + "call-signature", + "arrow-call-signature", + "parameter", + "arrow-parameter", + "property-declaration", + "variable-declaration", + "member-variable-declaration" + ], + "underscore-consistent-invocation": true, + "unified-signatures": true, + "variable-name": true, + "react-a11y-anchors": true, + "react-a11y-aria-unsupported-elements": true, + "react-a11y-event-has-role": true, + "react-a11y-image-button-has-alt": true, + "react-a11y-img-has-alt": true, + "react-a11y-lang": true, + "react-a11y-meta": true, + "react-a11y-props": true, + "react-a11y-proptypes": true, + "react-a11y-role": true, + "react-a11y-role-has-required-aria-props": true, + "react-a11y-role-supports-aria-props": true, + "react-a11y-tabindex-no-positive": true, + "react-a11y-titles": true, + "align": [ + true, + "statements" + ], + "curly": true, + "eofline": true, + "import-spacing": true, + "indent": [ + true, + "spaces" + ], + "linebreak-style": false, + "no-consecutive-blank-lines": true, + "no-empty-line-after-opening-brace": true, + "no-trailing-whitespace": true, + "no-unnecessary-semicolons": true, + "object-literal-key-quotes": [ + true, + "as-needed" + ], + "one-line": [ + false + ], + "quotemark": [ + true, + "single" + ], + "react-tsx-curly-spacing": true, + "semicolon": [ + true, + "always" + ], + "trailing-comma": [ + true, + { + "singleline": "never", + "multiline": "never" + } + ], + "typedef-whitespace": false, + "whitespace": [ + true, + "check-branch", + "check-decl", + "check-operator", + "check-separator", + "check-type" + ], + "ban": false, + "cyclomatic-complexity": true, + "file-header": false, + "import-blacklist": false, + "interface-over-type-literal": true, + "no-internal-module": true, + "no-magic-numbers": true, + "no-mergeable-namespace": false, + "no-namespace": true, + "no-reference": true, + "no-unexternalized-strings": true, + "object-literal-shorthand": true, + "no-angle-bracket-type-assertion": true, + "prefer-type-cast": false, + "space-before-function-paren": false, + "missing-optional-annotation": false, + "no-duplicate-parameter-names": false, + "no-empty-interfaces": true, + "no-missing-visibility-modifiers": false, + "no-multiple-var-decl": false, + "no-switch-case-fall-through": true, + //As of 2017-08-21 'no-unused-variable' doesn't work well with generics, disabled for now + "no-unused-variable": false, + "typeof-compare": true, + "no-inferred-empty-object-type": true, + "await-promise": true, + "no-floating-promises": true, + "no-for-in-array": true, + "no-use-before-declare": true, + "promise-function-async": true, + "completed-docs": [ + true, + { + "classes": { + "visibilities": ["all"] + }, + "enums": { + "visibilities": ["all"] + }, + "functions": { + "visibilities": ["all"] + }, + "interfaces": { + "visibilities": ["all"] + }, + "methods": { + "locations": ["all"], + "privacies": ["all"] + }, + "namespaces": { + "visibilities": ["all"] + }, + "properties": { + "locations": ["all"], + "privacies": ["all"] + }, + "types": { + "visibilities": ["all"] + }, + "variables": { + "visibilities": ["all"] + } + } + ], + "no-unnecessary-qualifier": true, + "no-void-expression": true, + "strict-boolean-expressions": [true, "allow-null-union"], + // The following produce too much noise with untyped or not-sufficiently typed libraries + "restrict-plus-operands": false, + "no-unsafe-any": false + }, + "rulesDirectory": ["./node_modules/tslint-microsoft-contrib/"] +}