diff options
Diffstat (limited to 'openecomp-ui')
213 files changed, 5863 insertions, 1795 deletions
diff --git a/openecomp-ui/.gitignore b/openecomp-ui/.gitignore index 7704a027fe..2a11210d95 100644 --- a/openecomp-ui/.gitignore +++ b/openecomp-ui/.gitignore @@ -1,6 +1,7 @@ .idea .vscode +.history debug.log dist node_modules diff --git a/openecomp-ui/external-resources/healthcheck/v1.0/healthcheck b/openecomp-ui/external-resources/healthcheck/v1.0/healthcheck new file mode 100644 index 0000000000..6a3dd41755 --- /dev/null +++ b/openecomp-ui/external-resources/healthcheck/v1.0/healthcheck @@ -0,0 +1,11 @@ +{ + "sdcVersion": "1.0-SNAPSHOT", + "componentsInfo": [ + { + "healthCheckComponent": "FE", + "healthCheckStatus": "UP", + "version": "1.0-SNAPSHOT", + "description": "OK" + } + ] +} diff --git a/openecomp-ui/gulpfile.js b/openecomp-ui/gulpfile.js index 2cad6d8520..eb755a2be0 100644 --- a/openecomp-ui/gulpfile.js +++ b/openecomp-ui/gulpfile.js @@ -5,9 +5,11 @@ let gulpHelpers = require('gulp-helpers'); let replace = require('gulp-replace'); let taskMaker = gulpHelpers.taskMaker(gulp); let runSequence = gulpHelpers.framework('run-sequence'); -let i18nTask = require('./tools/gulp/tasks/i18n'); -let prodTask = require('./tools/gulp/tasks/prod'); let gulpCssUsage = require('gulp-css-usage').default; + +let prodTask = require('./tools/gulp/tasks/prod'); +let i18nTask = require('./tools/gulp/tasks/i18n.js'); + let jsonConfig = { "appContextPath" : "/onboarding" }; @@ -15,48 +17,60 @@ let jsonConfig = { try { jsonConfig = require('./src/sdc-app/config/config.json'); } catch (e) { - console.log('could not load config. using deault value instead'); + console.log('could not load config. using default value instead'); } const appName = 'onboarding'; const dist = 'dist'; const path = { - jetty: './webapp-onboarding/WEB-INF/jetty-web.xml', - appinf: './webapp-onboarding/**/*.*', - appinf_output: dist + '/webapp-onboarding', - locales: dist + '/i18n/', - output: dist, + // inputs json: './src/**/*.json', index: './src/index.html', heat: './src/heat.html', scss: './resources/scss/**/*.scss', - css: dist + '/css', + i18nBundles: './src/nfvo-utils/i18n/*.json', svgSrc: './resources/images/svg/*.svg', + appinf: './webapp-onboarding/**/*.*', + jetty: './webapp-onboarding/WEB-INF/jetty-web.xml', + srcDir: './src/', + // output + output: dist, + css: dist + '/css', svg: dist + '/resources/images/svg', - war: [dist + '/index.html', dist + '/punch-outs_en.js', dist + '/**/*.{css,png,svg,eot,ttf,woff,woff2,otf}', dist + '/**/*(config.json|locale.json)', 'tools/gulp/deployment/**', dist + '/webapp-onboarding/**'], - heatWar: [dist + '/heat.html', dist + '/heat-validation_en.js', dist + '/**/*.{css,png,svg,eot,ttf,woff,woff2,otf}', dist + '/**/*(config.json|locale.json)', 'webapp-heat-validation/**'], + appinf_output: dist + '/webapp-onboarding', + // war + war: [dist + '/index.html', dist + '/punch-outs*.js', dist + '/**/*.{css,png,svg,eot,ttf,woff,woff2,otf}', dist + '/**/*(config.json)', dist + '/webapp-onboarding/**'], + heatWar: [dist + '/heat.html', dist + '/heat-validation_en.js', dist + '/**/*.{css,png,svg,eot,ttf,woff,woff2,otf}', dist + '/**/*(config.json)', 'webapp-heat-validation/**'], wardest: dist, + // storybook storybookFonts: './.storybook/fonts/*', storybookDist: './.storybook-dist', storybookResources: './.storybook/resources/onboarding/resources/images/svg', storybookDistResources: './.storybook-dist/onboarding/resources/images/svg' }; - +// cleans up the output directory taskMaker.defineTask('clean', {taskName: 'clean', src: path.output}); +// copies for all relevant files to the output directory taskMaker.defineTask('copy', {taskName: 'copy-json', src: path.json, dest: path.output, changed: {extension: '.json'}}); taskMaker.defineTask('copy', {taskName: 'copy-index.html', src: path.index, dest: path.output, rename: 'index.html'}); taskMaker.defineTask('copy', {taskName: 'copy-heat.html', src: path.heat, dest: path.output, rename: 'heat.html'}); taskMaker.defineTask('copy', {taskName: 'copy-svg', src: path.svgSrc, dest: path.svg}); -//TODO: delete this task after gulp-css-usage support for SCSS files -taskMaker.defineTask('sass', {taskName: 'sass', src: path.scss, dest: path.css, config: {outputStyle: 'compressed'}}); -taskMaker.defineTask('compress', {taskName: 'compress-war', src: path.war, filename: appName + '.war', dest: path.wardest}); -taskMaker.defineTask('compress', {taskName: 'compress-heat-war', src: path.heatWar, filename: 'heat-validation.war', dest: path.wardest}); -taskMaker.defineTask('watch', {taskName: 'watch-stuff', src: [path.json, path.index, path.heat], tasks: ['copy-stuff']}); taskMaker.defineTask('copy', {taskName: 'copy-storybook-fonts', src: path.storybookFonts, dest: path.storybookDist}); taskMaker.defineTask('copy', {taskName: 'copy-storybook-resources', src: path.svgSrc, dest: path.storybookResources}); taskMaker.defineTask('copy', {taskName: 'copy-storybook-resources-prod', src: path.svgSrc, dest: path.storybookDistResources}); +// used for compressing war files +taskMaker.defineTask('compress', {taskName: 'compress-war', src: path.war, filename: appName + '.war', dest: path.wardest}); +taskMaker.defineTask('compress', {taskName: 'compress-heat-war', src: path.heatWar, filename: 'heat-validation.war', dest: path.wardest}); +// used for watching for changes for test +taskMaker.defineTask('watch', {taskName: 'watch-stuff', src: [path.json, path.index, path.heat], tasks: ['copy-stuff']}); + + +//TODO: delete this task after gulp-css-usage support for SCSS files +taskMaker.defineTask('sass', {taskName: 'sass', src: path.scss, dest: path.css, config: {outputStyle: 'compressed'}}); + +// update the app-context for the web-xml file to the value from the config gulp.task('app-context', function(){ gulp.src([path.appinf]) .pipe(gulp.dest(path.appinf_output)) @@ -66,22 +80,17 @@ gulp.task('app-context', function(){ .pipe(gulp.dest(path.appinf_output + '/WEB-INF')); }) }); - +// aggregates all copy tasks gulp.task('copy-stuff', callback => runSequence(['copy-json', 'copy-index.html', 'copy-heat.html', 'copy-svg', 'app-context'], callback)); -gulp.task('i18n', () => - i18nTask({outputPath: path.output, localesPath: path.locales, lang: 'en'}).catch(err => { - console.log('i18n Task : Error! ', err); - throw err; - }) -); - -gulp.task('dev', callback => runSequence('clean', ['i18n', 'copy-stuff'], callback)); -gulp.task('build', callback => runSequence('clean', ['copy-stuff', 'i18n'], 'prod', ['compress-war', 'compress-heat-war'], callback)); - +// minimum build for dev +gulp.task('dev', callback => runSequence('clean', 'copy-stuff', callback)); +// build procedure for war file +gulp.task('build', callback => runSequence('clean', 'copy-stuff', 'prod', ['compress-war', 'compress-heat-war'], callback)); +// default build is set to 'dev' gulp.task('default', ['dev']); - -gulp.task('prod', () => prodTask({outDir: path.output}) +// creating the webpack tasks for the production build +gulp.task('prod', () => prodTask({outDir: path.output, i18nBundles : path.i18nBundles}) .catch(err => { if (err && err.stack) { console.error(err, err.stack); @@ -90,7 +99,12 @@ gulp.task('prod', () => prodTask({outDir: path.output}) }) ); +/*** + * T O O L S . N O T P A R T O F B U I L D + */ +// this is used to manually run on the sass files to check which classes are never used. not run as part of build. +// can be run as npm task gulp.task('gulp-css-usage', () => { return gulp.src('src/**/*.jsx').pipe(gulpCssUsage({css: path.css + '/style.css', babylon: ['objectRestSpread']})); }); @@ -99,3 +113,15 @@ gulp.task('css-usage', () => { runSequence('sass', 'gulp-css-usage'); }); + +gulp.task('static-keys-bundle', () => i18nTask({outDir: path.output, srcDir: path.srcDir}) + .catch(err => { + throw new Error('static-keys-bundle FAILED'); + }) +); + +gulp.task('static-keys-bundle-with-report', () => i18nTask({outDir: path.output, srcDir: path.srcDir, i18nBundles : path.i18nBundles }) + .catch(err => { + throw new Error('static-keys-bundle FAILED'); + }) +); diff --git a/openecomp-ui/package.json b/openecomp-ui/package.json index 8157be8141..0e1e66b80e 100644 --- a/openecomp-ui/package.json +++ b/openecomp-ui/package.json @@ -7,6 +7,9 @@ "scripts": { "start": "gulp dev && webpack-dev-server --progress", "build": "gulp build", + "css-usage": "gulp css-usage", + "static-keys-bundle" : "gulp static-keys-bundle", + "check-keys-against-bundles" : "gulp static-keys-bundle-with-report", "test": "jest", "test-failedTestReport": "jest --json | node test-utils/failedTestReport.js", "test-dev": "jest --watch", @@ -36,6 +39,7 @@ "react-sortable": "^1.2.0", "redux": "^3.3.1", "restful-js": "^0.7.0", + "sdc-ui": "^1.5.12", "uuid-js": "^0.7.5", "validator": "^4.3.0" }, @@ -70,7 +74,7 @@ "gulp-helpers": "^5.0.0", "gulp-rename": "^1.2.2", "gulp-replace": "^0.5.4", - "gulp-util": "^3.0.8", + "gulp-tap": "^1.0.1", "html-loader": "^0.4.3", "http-proxy-middleware": "^0.8.2", "ignore-loader": "^0.1.1", @@ -80,9 +84,11 @@ "json-loader": "^0.5.4", "jsx-loader": "^0.13.2", "mkdirp": "^0.5.1", + "moment": "^2.18.1", "node-watch": "^0.3.5", "prompt": "^0.2.14", "react-addons-test-utils": "~15.3.2", + "react-datepicker": "^0.48.0", "react-hot-loader": "^1.3.1", "rosie": "^1.6.0", "sass-loader": "^3.2.3", @@ -107,7 +113,7 @@ "^nfvo-components(.*)$": "<rootDir>/src/nfvo-components$1", "^sdc-app(.*)$": "<rootDir>/src/sdc-app$1", "^test-utils(.*)$": "<rootDir>/test-utils$1", - "^i18nJson$": "<rootDir>/src/nfvo-utils/i18n/locale.json", + "^i18nJson$": "<rootDir>/src/nfvo-utils/i18n/en.json", "^src(.*)$": "<rootDir>/src$1" }, "globals": { diff --git a/openecomp-ui/pom.xml b/openecomp-ui/pom.xml index 78eb97c57b..77313092c6 100644 --- a/openecomp-ui/pom.xml +++ b/openecomp-ui/pom.xml @@ -56,20 +56,12 @@ <groupId>com.github.eirslett</groupId> <artifactId>frontend-maven-plugin</artifactId> <version>1.4</version> + + <configuration> + <installDirectory>${project.parent.parent.basedir}</installDirectory> + </configuration> <executions> - - <execution> - <id>install node and npm in dox-sequence-diagram-ui</id> - <goals> - <goal>install-node-and-npm</goal> - </goals> - <configuration> - <workingDirectory>${project.basedir}/../dox-sequence-diagram-ui</workingDirectory> - <nodeVersion>v6.9.5</nodeVersion> - <npmVersion>3.10.10</npmVersion> - </configuration> - </execution> <execution> <id>install node and npm</id> @@ -81,6 +73,16 @@ <npmVersion>3.10.10</npmVersion> </configuration> </execution> + + <execution> + <id>npm set progress off</id> + <goals> + <goal>npm</goal> + </goals> + <configuration> + <arguments>set progress=false</arguments> + </configuration> + </execution> <execution> <id>npm install in dox-sequence-diagram-ui</id> diff --git a/openecomp-ui/resources/images/angle-left.svg b/openecomp-ui/resources/images/angle-left.svg new file mode 100644 index 0000000000..b2d2f81b3d --- /dev/null +++ b/openecomp-ui/resources/images/angle-left.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="angle-left_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 6.3 9.9" style="enable-background:new 0 0 6.3 9.9;" xml:space="preserve"> +<g transform="translate(0,-952.36218)"> + <path d="M5.8,952.4c-0.1,0-0.2,0-0.2,0.1l-5.5,4.6c-0.2,0.1-0.2,0.4,0,0.5l0,0l5.5,4.6c0.2,0.1,0.4,0.1,0.5,0 + c0.1-0.2,0.1-0.4,0-0.5l0,0l-5.2-4.3l5.2-4.3c0.2-0.1,0.2-0.4,0.1-0.5C6,952.4,5.9,952.4,5.8,952.4z"/> +</g> +</svg> diff --git a/openecomp-ui/resources/images/angle-right.svg b/openecomp-ui/resources/images/angle-right.svg new file mode 100644 index 0000000000..f8e6efc3a6 --- /dev/null +++ b/openecomp-ui/resources/images/angle-right.svg @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Generator: Adobe Illustrator 21.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<svg version="1.1" id="angle-right_icon" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + viewBox="0 0 6.3 9.9" style="enable-background:new 0 0 6.3 9.9;" xml:space="preserve"> +<g transform="translate(0,-952.36218)"> + <path d="M0.5,962.2c0.1,0,0.2,0,0.2-0.1l5.5-4.6c0.2-0.1,0.2-0.4,0-0.5l0,0l-5.5-4.6c-0.2-0.1-0.4-0.1-0.5,0 + c-0.1,0.2-0.1,0.4,0,0.5l0,0l5.2,4.3l-5.2,4.3C0,961.6,0,961.9,0.1,962C0.3,962.1,0.4,962.2,0.5,962.2z"/> +</g> +</svg> diff --git a/openecomp-ui/resources/images/svg/calendar.svg b/openecomp-ui/resources/images/svg/calendar.svg new file mode 100644 index 0000000000..9c059024d5 --- /dev/null +++ b/openecomp-ui/resources/images/svg/calendar.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 17 18" id="calendar_icon"><title>Asset 1</title><g data-name="Layer 2"><g id="Layer_1-2" data-name="Layer 1"><path d="M15.5,2H13V0H12V2H9V0H8V2H5V0H4V2H1.5A1.5,1.5,0,0,0,0,3.5v13A1.5,1.5,0,0,0,1.5,18h14A1.5,1.5,0,0,0,17,16.5V3.5A1.5,1.5,0,0,0,15.5,2ZM16,16.5a.5.5,0,0,1-.5.5H1.5a.5.5,0,0,1-.5-.5V8H16ZM1,7V3.5A.5.5,0,0,1,1.5,3H4V5H5V3H8V5H9V3h3V5h1V3h2.5a.5.5,0,0,1,.5.5V7Z"/><path d="M4.52,13.65l.7-.09a1.55,1.55,0,0,0,.41.86,1,1,0,0,0,.71.26,1.14,1.14,0,0,0,.84-.34,1.16,1.16,0,0,0,.34-.85,1.08,1.08,0,0,0-.32-.8,1.09,1.09,0,0,0-.8-.31,2,2,0,0,0-.5.08L6,11.84H6.1a1.45,1.45,0,0,0,.81-.23.8.8,0,0,0,.36-.72A.85.85,0,0,0,7,10.25.93.93,0,0,0,6.33,10a1,1,0,0,0-.68.26A1.29,1.29,0,0,0,5.3,11l-.7-.12a1.81,1.81,0,0,1,.59-1.1,1.69,1.69,0,0,1,1.14-.39,1.86,1.86,0,0,1,.86.2,1.45,1.45,0,0,1,.6.55A1.41,1.41,0,0,1,8,10.9a1.21,1.21,0,0,1-.2.68,1.36,1.36,0,0,1-.59.48,1.33,1.33,0,0,1,.79.49,1.48,1.48,0,0,1,.28.92,1.69,1.69,0,0,1-.55,1.27,1.92,1.92,0,0,1-1.38.52,1.8,1.8,0,0,1-1.25-.45A1.74,1.74,0,0,1,4.52,13.65Z"/><path d="M11.62,15.17h-.7V10.69a3.68,3.68,0,0,1-.67.48,4.77,4.77,0,0,1-.74.36v-.68a4.26,4.26,0,0,0,1-.67,2.66,2.66,0,0,0,.63-.77h.45Z"/></g></g></svg>
\ No newline at end of file diff --git a/openecomp-ui/resources/scss/_components.scss b/openecomp-ui/resources/scss/_components.scss index bd85f547c9..c70b914187 100644 --- a/openecomp-ui/resources/scss/_components.scss +++ b/openecomp-ui/resources/scss/_components.scss @@ -17,9 +17,9 @@ @import "components/expandableInput"; @import "components/grid"; @import "components/icon"; -@import "components/svgIcon"; @import "components/activityLog"; @import "components/selectActionTable"; +@import "components/datepicker"; %noselect { -webkit-touch-callout: none; diff --git a/openecomp-ui/resources/scss/_modules.scss b/openecomp-ui/resources/scss/_modules.scss index 578895dfe0..317f90800f 100644 --- a/openecomp-ui/resources/scss/_modules.scss +++ b/openecomp-ui/resources/scss/_modules.scss @@ -12,7 +12,9 @@ @import "modules/_softwareProductComponentGeneral"; @import "modules/_softwareproductComponentLoadBalancing"; @import "modules/_softwareProductComponentProcessesPage"; +@import "modules/_softwareProductComponentImage"; @import "modules/softwareProductComponentCompute"; +@import "modules/vspComponentCompute"; @import "modules/vspComponentMonitoring"; @import "modules/licenseModel"; @import "modules/onboardingCatalog"; @@ -20,3 +22,4 @@ @import "modules/uploadScreen"; @import "modules/vspHeatSetup"; @import "modules/softwareProductDependencies"; +@import "modules/softwareProductDeployment"; diff --git a/openecomp-ui/resources/scss/bootstrap-cust/_forms.scss b/openecomp-ui/resources/scss/bootstrap-cust/_forms.scss index 8085274cac..60fd7ab07d 100644 --- a/openecomp-ui/resources/scss/bootstrap-cust/_forms.scss +++ b/openecomp-ui/resources/scss/bootstrap-cust/_forms.scss @@ -1,6 +1,6 @@ .form-group { .control-label { - @extend .body-2-medium; + @extend .body-2-semibold; } &.required { label:before { diff --git a/openecomp-ui/resources/scss/bootstrap-cust/_modals.scss b/openecomp-ui/resources/scss/bootstrap-cust/_modals.scss index 6a825b811e..9301f1ed39 100644 --- a/openecomp-ui/resources/scss/bootstrap-cust/_modals.scss +++ b/openecomp-ui/resources/scss/bootstrap-cust/_modals.scss @@ -19,5 +19,11 @@ padding: 15px; border-top: 0; background-color: $tlv-gray; + .sdc-modal-footer { + .sdc-button + .sdc-button { + margin-left: 5px; + } + } + } } diff --git a/openecomp-ui/resources/scss/bootstrap-cust/_navs.scss b/openecomp-ui/resources/scss/bootstrap-cust/_navs.scss index 7b9cff963d..914a7794f1 100644 --- a/openecomp-ui/resources/scss/bootstrap-cust/_navs.scss +++ b/openecomp-ui/resources/scss/bootstrap-cust/_navs.scss @@ -22,7 +22,7 @@ &, &:hover, &:focus { - @extend .body-1-medium; + @extend .body-1-semibold; border-bottom: 3px solid $blue; } } diff --git a/openecomp-ui/resources/scss/bootstrap-cust/_variables.scss b/openecomp-ui/resources/scss/bootstrap-cust/_variables.scss index 1af39d5b39..1c053e500b 100644 --- a/openecomp-ui/resources/scss/bootstrap-cust/_variables.scss +++ b/openecomp-ui/resources/scss/bootstrap-cust/_variables.scss @@ -28,7 +28,7 @@ $link-hover-color: $blue; //== Typography // //## Font, line-height, and color for body text, headings, and more. -$font-family-sans-serif: omnes-regular, "Omnes-Regular", "Helvetica Neue", Helvetica, Arial, sans-serif; +$font-family-sans-serif: "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; //$font-family-base: $font-family-sans-serif !default; $font-size-base: $body-font-2; $font-size-large: $body-font-1; diff --git a/openecomp-ui/resources/scss/bootstrap.scss b/openecomp-ui/resources/scss/bootstrap.scss index a8c470216d..777f490a89 100644 --- a/openecomp-ui/resources/scss/bootstrap.scss +++ b/openecomp-ui/resources/scss/bootstrap.scss @@ -7,12 +7,12 @@ @import "bootstrap/variables"; @import "bootstrap/mixins"; // Reset and dependencies -@import "bootstrap/normalize"; +//@import "bootstrap/normalize"; //@import "bootstrap/print"; //@import "bootstrap/glyphicons"; // Core CSS -@import "bootstrap/scaffolding"; +//@import "bootstrap/scaffolding"; @import "bootstrap/type"; @import "bootstrap/code"; @import "bootstrap/grid"; @@ -20,8 +20,8 @@ @import "bootstrap-cust/tables"; @import "bootstrap/forms"; @import "bootstrap-cust/forms"; -@import "bootstrap/buttons"; -@import "bootstrap-cust/buttons"; +//@import "bootstrap/buttons"; +//@import "bootstrap-cust/buttons"; // Components @import "bootstrap/component-animations"; @import "bootstrap/dropdowns"; diff --git a/openecomp-ui/resources/scss/bootstrap/_mixins.scss b/openecomp-ui/resources/scss/bootstrap/_mixins.scss index 62dfda69dc..3d08c9b390 100644 --- a/openecomp-ui/resources/scss/bootstrap/_mixins.scss +++ b/openecomp-ui/resources/scss/bootstrap/_mixins.scss @@ -16,7 +16,7 @@ @import "mixins/vendor-prefixes"; // Components @import "mixins/alerts"; -@import "mixins/buttons"; +//@import "mixins/buttons"; @import "mixins/panels"; @import "mixins/pagination"; @import "mixins/list-group"; diff --git a/openecomp-ui/resources/scss/common/_typography.scss b/openecomp-ui/resources/scss/common/_typography.scss index 1543f0adcd..94e1ba4d61 100644 --- a/openecomp-ui/resources/scss/common/_typography.scss +++ b/openecomp-ui/resources/scss/common/_typography.scss @@ -1,22 +1,26 @@ /* Fonts */ @mixin base-font-regular() { - font-family: omnes-regular, Arial, sans-serif; + font-family: OpenSans, OpenSans-Regular, 'Open Sans',omnes-regular, Arial, sans-serif; } @mixin base-font-light() { - font-family: omnes-light, Arial, sans-serif; + font-family: OpenSans-Light, 'Open Sans', omnes-light, Arial, sans-serif; } -@mixin base-font-medium() { - font-family: omnes-medium, Arial, sans-serif; +@mixin base-font-italic(){ + font-family: OpenSans-Italic, 'Open Sans', omnes-italic, Arial, sans-serif; +} + +@mixin base-font-semibold() { + font-family: OpenSans-Semibold, 'Open Sans', omnes-medium, Arial, sans-serif; } @mixin base-font-bold() { - font-family: omnes-bold, Arial, sans-serif; + font-family: OpenSans-Bold, 'Open Sans', omnes-bold, Arial, sans-serif; } -$heading-font-1: 36px; +$heading-font-1: 28px; $heading-font-2: 24px; $heading-font-3: 20px; $heading-font-4: 18px; @@ -25,6 +29,7 @@ $heading-font-5: 16px; $body-font-1: 14px; $body-font-2: 13px; $body-font-3: 12px; +$body-font-4: 10px; $icon-font-size: 11px; $icon-font-family: Arial; @@ -52,8 +57,8 @@ $radio-font-family: Arial; @extend .text-uppercase !optional; } -.heading-3-medium { - @include base-font-medium; +.heading-3-semibold { + @include base-font-semibold; font-size: $heading-font-3; @extend .text-uppercase !optional; } @@ -63,8 +68,8 @@ $radio-font-family: Arial; font-size: $heading-font-4; } -.heading-4-medium { - @include base-font-medium; +.heading-4-semibold { + @include base-font-semibold; font-size: $heading-font-4; } @@ -73,8 +78,8 @@ $radio-font-family: Arial; font-size: $heading-font-5; } -.heading-5-medium { - @include base-font-medium; +.heading-5-semibold { + @include base-font-semibold; font-size: $heading-font-5; } @@ -83,8 +88,8 @@ $radio-font-family: Arial; font-size: $body-font-1; } -.body-1-medium { - @include base-font-medium; +.body-1-semibold { + @include base-font-semibold; font-size: $body-font-1; } @@ -98,8 +103,8 @@ $radio-font-family: Arial; font-size: $body-font-2; } -.body-2-medium { - @include base-font-medium; +.body-2-semibold { + @include base-font-semibold; font-size: $body-font-2; } @@ -108,18 +113,28 @@ $radio-font-family: Arial; font-size: $body-font-3; } -.body-3-medium { - @include base-font-medium; +.body-3-semibold { + @include base-font-semibold; font-size: $body-font-3; } +.body-4 { + @include base-font-regular; + font-size: $body-font-4; +} + +.body-4-semibold { + @include base-font-semibold; + font-size: $body-font-4; +} + .body-3-light { @include base-font-light; font-size: $body-font-3; } .circle-icon-text { - @include base-font-medium; + @include base-font-semibold; font-size: $body-font-1; } diff --git a/openecomp-ui/resources/scss/components/_activityLog.scss b/openecomp-ui/resources/scss/components/_activityLog.scss index 1e31e06814..9ada804934 100644 --- a/openecomp-ui/resources/scss/components/_activityLog.scss +++ b/openecomp-ui/resources/scss/components/_activityLog.scss @@ -29,7 +29,7 @@ $message-info-icon-size: 16px; height: 36px; @extend .body-1; &.header { - @extend .body-1-medium; + @extend .body-1-semibold; background-color: $tlv-light-gray; color: $text-black; } @@ -39,7 +39,7 @@ $message-info-icon-size: 16px; .svg-icon-wrapper { float: right; } - .check-circle { + .checkCircle { fill: $green; width: 16px; height: 16px; diff --git a/openecomp-ui/resources/scss/components/_buttons.scss b/openecomp-ui/resources/scss/components/_buttons.scss index fbf2c3e728..357a799e93 100644 --- a/openecomp-ui/resources/scss/components/_buttons.scss +++ b/openecomp-ui/resources/scss/components/_buttons.scss @@ -2,8 +2,7 @@ border: 1px solid; border-color: $blue; color: $blue; - font-weight: bolder; - @extend .body-1; + @extend .body-1-semibold; text-align: center; padding: 7px; border-radius: 5px; diff --git a/openecomp-ui/resources/scss/components/_datepicker.scss b/openecomp-ui/resources/scss/components/_datepicker.scss new file mode 100644 index 0000000000..593bb09d7d --- /dev/null +++ b/openecomp-ui/resources/scss/components/_datepicker.scss @@ -0,0 +1,51 @@ +.customized-date-picker { + margin-bottom: 24px; + .date-picker-label { + &.required { + &:before { + content: "*"; + color: $red; + margin: 0 4px 0 0; + } + } + + @extend .body-2-semibold; + color: $dark-gray; + margin-bottom: 8px; + } + .datepicker-custom-input { + display: flex; + justify-content: space-between; + width: 243px; + height: 30px; + border-radius: 2px; + color: $dark-gray; + border: 1px solid $light-gray; + padding: 6px 12px; + &:hover { + border-color: $gray; + .clear-input { + &:before { + cursor: pointer; + content: 'x'; + } + } + } + .datepicker-text { + cursor: pointer; + width: 170px; + @extend .body-1; + &.placeholder { + color: $light-gray; + } + + } + .calendar-input { + fill: $light-gray; + } + } + + + +} + diff --git a/openecomp-ui/resources/scss/components/_forms.scss b/openecomp-ui/resources/scss/components/_forms.scss index 23c58ea4ac..b662ce873c 100644 --- a/openecomp-ui/resources/scss/components/_forms.scss +++ b/openecomp-ui/resources/scss/components/_forms.scss @@ -1,5 +1,5 @@ .section-title { - @extend .heading-3-medium; + @extend .heading-3-semibold; padding: 50px 0 30px 0; &:first-child { padding: 0 0 30px 0; diff --git a/openecomp-ui/resources/scss/components/_grid.scss b/openecomp-ui/resources/scss/components/_grid.scss index d4d1fa7ccd..9a76f97546 100644 --- a/openecomp-ui/resources/scss/components/_grid.scss +++ b/openecomp-ui/resources/scss/components/_grid.scss @@ -1,7 +1,9 @@ $gridItemSpace: 15%; .grid-section { - padding-bottom: 30px; + &:not(:last-of-type) { + padding-bottom: 30px; + } .grid-items { display: flex; flex-direction: row; diff --git a/openecomp-ui/resources/scss/components/_listEditorView.scss b/openecomp-ui/resources/scss/components/_listEditorView.scss index 18d5426eb7..1c837ca4c2 100644 --- a/openecomp-ui/resources/scss/components/_listEditorView.scss +++ b/openecomp-ui/resources/scss/components/_listEditorView.scss @@ -15,16 +15,16 @@ border-bottom: 1px solid $light-gray; padding-bottom: 5px; .list-editor-view-title { - @extend .heading-3-medium; + @extend .heading-3-semibold; } .list-editor-view-add-controller { - @extend .heading-4-medium; + @extend .body-1-semibold; color: $blue; display: table; cursor: pointer; position: relative; - padding-top: 0px; - padding-bottom: 0px; + padding-top: 0; + padding-bottom: 0; margin-left: auto; .list-editor-view-add-title { display: flex; @@ -151,6 +151,13 @@ } } + .details-col{ + flex-direction: column; + .title { + padding-bottom: 0; + } + } + .description { @extend .body-1; @include multiline-ellipsis(1.3em, 3); diff --git a/openecomp-ui/resources/scss/components/_navigationSideBar.scss b/openecomp-ui/resources/scss/components/_navigationSideBar.scss index 36c14a2785..daf5025bee 100644 --- a/openecomp-ui/resources/scss/components/_navigationSideBar.scss +++ b/openecomp-ui/resources/scss/components/_navigationSideBar.scss @@ -16,7 +16,7 @@ flex-direction: column; background-color: $tlv-gray; .group-name { - @extend .heading-4-medium; + @extend .heading-4-semibold; @include ellipsis; min-height: 56px; display: block; @@ -47,13 +47,13 @@ @include ellipsis; white-space: normal; &.selected { - @extend .body-1-medium; + @extend .body-1-semibold; border-left: 4px solid $blue; padding-left: 18px; color: $blue; } &.bold-name { - @extend .body-1-medium; + @extend .body-1-semibold; } } } diff --git a/openecomp-ui/resources/scss/components/_notifications.scss b/openecomp-ui/resources/scss/components/_notifications.scss index 426f05cd89..7165e57ef9 100644 --- a/openecomp-ui/resources/scss/components/_notifications.scss +++ b/openecomp-ui/resources/scss/components/_notifications.scss @@ -5,12 +5,12 @@ .modal-header { padding: 15px 10px 10px; .modal-title { - @extend .heading-5-medium; + @extend .heading-5-semibold; } } .modal-body { padding: 30px 15px; - @extend .body-1-medium; + @extend .body-1-semibold; } } diff --git a/openecomp-ui/resources/scss/components/_selectActionTable.scss b/openecomp-ui/resources/scss/components/_selectActionTable.scss index fa17733374..4e42b6ce5b 100644 --- a/openecomp-ui/resources/scss/components/_selectActionTable.scss +++ b/openecomp-ui/resources/scss/components/_selectActionTable.scss @@ -1,16 +1,16 @@ .select-action-table-view { .svg-icon-wrapper { flex-direction: row; - + &::before { - content:""; + content:""; } .svg-icon { margin-left: 5px; margin-right: 5px; width:16px; height:16px; - } + } } .dummy-icon { background-color: $white; @@ -39,34 +39,39 @@ .select-action-table-headers { display: flex; background-color: $tlv-light-gray; - border-color: inherit; + border-color: inherit; .select-action-table-header { - @extend .body-1-medium; + @extend .body-1-semibold; flex: 1; border-top: 1px solid; - border-right: 1px solid; + border-right: 1px solid; border-color: inherit; padding: 8px 0 7px 20px; &:first-child { border-left: 1px solid; border-color: inherit; } - } + } } .select-action-table-row-wrapper { display: flex; - flex-direction: row; + flex-direction: row; margin-bottom: 14px; - .svg-icon.trash-o { - - fill: $dark-gray; + .svg-icon-wrapper.trashO { + .svg-icon { + fill: $dark-gray; + } + } + .svg-icon-wrapper.errorCircle { + .svg-icon { + fill: $red; + } } - .svg-icon.error-circle { - fill: $red; + .svg-icon-wrapper.checkCircle { + .svg-icon { + fill: $green; + } } - .svg-icon.check-circle { - fill: $green; - } .select-action-table-row { display: flex; flex: 1; @@ -90,7 +95,7 @@ } } .form-group { - margin: 0; + margin: 0; .Select-control { height:36px; border: none; @@ -102,7 +107,7 @@ padding-left: 20px; padding-right: 50px; padding-top: 4px; - + } .Select-placeholder { color: $dark-gray; @@ -110,23 +115,23 @@ .Select-arrow-zone { padding-right: 15px; } - } + } } &:last-child { border-right: none; - } + } } .Select-menu-outer { border-left: 1px solid $blue; border-right: 1px solid $blue; border-bottom: 1px solid $blue; overflow: auto; - .Select-menu { + .Select-menu { display: inline-block; - .Select-option { + .Select-option { width: 100%; display: inline-block; - border-bottom: 1px solid $light-gray; + border-bottom: 1px solid $light-gray; &:hover { background-color: $blue; color: $white; @@ -142,9 +147,9 @@ } &.is-focused { background-color: transparent; - } + } } - } + } } } } diff --git a/openecomp-ui/resources/scss/components/_submitErrorResponse.scss b/openecomp-ui/resources/scss/components/_submitErrorResponse.scss index e34be01af2..b917dfefeb 100644 --- a/openecomp-ui/resources/scss/components/_submitErrorResponse.scss +++ b/openecomp-ui/resources/scss/components/_submitErrorResponse.scss @@ -26,7 +26,7 @@ background-color: $tlv-gray; padding: 5px; cursor: pointer; - .chevron-down { + .chevronDown { width:10px; height:10px; margin-right: 10px; @@ -54,7 +54,7 @@ .component-name-header { margin-left: 45px; margin-top: 10px; - @extend .heading-5-medium; + @extend .heading-5-semibold; } } } diff --git a/openecomp-ui/resources/scss/components/_svgIcon.scss b/openecomp-ui/resources/scss/components/_svgIcon.scss deleted file mode 100644 index fc02f81fd4..0000000000 --- a/openecomp-ui/resources/scss/components/_svgIcon.scss +++ /dev/null @@ -1,51 +0,0 @@ -@mixin overrideBootstrapClose(){ - opacity: 1; - float: none; - &:hover { - opacity: 1; - } -} - -.svg-icon-wrapper { - display: inline-flex; - justify-content: center; - align-items: center; - &.bottom { - flex-direction: column; - .svg-icon-label { - margin-bottom: 5px; - } - } - &.right { - float: none; - .svg-icon-label { - margin-left: 5px; - } - } - &.top { - flex-direction: column-reverse;; - .svg-icon-label { - margin-top: 5px; - } - } - &.left { - flex-direction: row-reverse;; - .svg-icon-label { - margin-right: 5px; - } - } - // bootstrap override - &.close { - @include overrideBootstrapClose(); - } - .close { - @include overrideBootstrapClose(); - } - .svg-icon { - width: 20px; - height: 20px; - } - .svg-icon-label { - @extend .body-1; - } -} diff --git a/openecomp-ui/resources/scss/components/_validationForm.scss b/openecomp-ui/resources/scss/components/_validationForm.scss index 9404f2841a..46269ad699 100644 --- a/openecomp-ui/resources/scss/components/_validationForm.scss +++ b/openecomp-ui/resources/scss/components/_validationForm.scss @@ -4,6 +4,9 @@ form { position: relative; flex: 1; } + .validation-radio-wrapper { + position: relative; + } .nav-tabs { position: relative; .invalid-tab:not(.active) { diff --git a/openecomp-ui/resources/scss/components/_versionController.scss b/openecomp-ui/resources/scss/components/_versionController.scss index 3c30cdcc37..b454d3496b 100644 --- a/openecomp-ui/resources/scss/components/_versionController.scss +++ b/openecomp-ui/resources/scss/components/_versionController.scss @@ -20,7 +20,7 @@ padding-right: 10px; margin-right: 15px; margin-left: 10px; - @extend .body-1; + @extend .body-1; } .version-section { .form-group { @@ -59,7 +59,7 @@ margin-right: 20px; padding-bottom: 5px; - .version-controller-lock-closed { + .versionControllerLockClosed { fill: $dark-gray; width: 21px; height: 23px; @@ -71,7 +71,7 @@ fill: $black; } } - .version-controller-lock-open { + .versionControllerLockOpen { fill: $dark-gray; width: 24px; height: 28px; @@ -80,7 +80,7 @@ fill: $black; } } - .version-controller-submit { + .versionControllerSubmit { fill: $blue; &.disabled { fill: $light-gray; @@ -90,7 +90,7 @@ } } - .version-controller-revert { + .versionControllerRevert { fill: $dark-gray; &.disabled { fill: $light-gray; @@ -99,7 +99,7 @@ fill: $black; } } - .version-controller-save { + .versionControllerSave { fill: $dark-gray; &.disabled { fill: $light-gray; diff --git a/openecomp-ui/resources/scss/modules/_featureGroup.scss b/openecomp-ui/resources/scss/modules/_featureGroup.scss index 71e7cee575..8c45d8ec58 100644 --- a/openecomp-ui/resources/scss/modules/_featureGroup.scss +++ b/openecomp-ui/resources/scss/modules/_featureGroup.scss @@ -35,7 +35,7 @@ .tab-content { padding: 50px; .field-section { - @extend .body-2-medium; + @extend .body-2-semibold; margin-bottom: 23px; width: 400px; color: $black; diff --git a/openecomp-ui/resources/scss/modules/_licenseKeyGroup.scss b/openecomp-ui/resources/scss/modules/_licenseKeyGroup.scss index 5ea84e98c4..5de757bf64 100644 --- a/openecomp-ui/resources/scss/modules/_licenseKeyGroup.scss +++ b/openecomp-ui/resources/scss/modules/_licenseKeyGroup.scss @@ -25,7 +25,7 @@ .validation-form-content { padding: 50px; .field-section { - @extend .body-2-medium; + @extend .body-2-semibold; margin-bottom: 23px; width: 400px; color: $black; diff --git a/openecomp-ui/resources/scss/modules/_licenseModel.scss b/openecomp-ui/resources/scss/modules/_licenseModel.scss index 6912e19bcd..3d65be6274 100644 --- a/openecomp-ui/resources/scss/modules/_licenseModel.scss +++ b/openecomp-ui/resources/scss/modules/_licenseModel.scss @@ -5,7 +5,7 @@ .validation-form-content { padding: 50px; .field-section { - @extend .body-2-medium; + @extend .body-2-semibold; margin-bottom: 23px; width: 400px; color: $black; diff --git a/openecomp-ui/resources/scss/modules/_licenseModelOverview.scss b/openecomp-ui/resources/scss/modules/_licenseModelOverview.scss index 4ec7c8d3af..5c74e82d83 100644 --- a/openecomp-ui/resources/scss/modules/_licenseModelOverview.scss +++ b/openecomp-ui/resources/scss/modules/_licenseModelOverview.scss @@ -27,7 +27,7 @@ margin-top:5px; } .vendor-name { - @extend .heading-3-medium; + @extend .heading-4-semibold; text-transform: none; padding-bottom: 15px; border-bottom: 1px solid $tlv-light-gray; @@ -137,7 +137,7 @@ background-color: $tlv-gray; .summary-count-item { @extend .flex; - @extend .heading-4-medium; + @extend .heading-5-semibold; padding-top: 5px; padding-left: 45px; padding-right: 45px; @@ -349,7 +349,7 @@ .additional-data { padding-left: 50px; .additional-data-name { - @extend .body-1-medium; + @extend .body-1-semibold; } } .additional-data-col-border { @@ -373,7 +373,7 @@ .vlm-list-item-title { @extend .flex; .item-name { - @extend .heading-5-medium; + @extend .heading-5-semibold; flex: 0 1 auto; margin-bottom: 4px; } diff --git a/openecomp-ui/resources/scss/modules/_softwareProductAttachmentPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductAttachmentPage.scss index 37068975a2..bab2872691 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductAttachmentPage.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductAttachmentPage.scss @@ -8,8 +8,7 @@ border-bottom: 1px solid $light-gray; & > li { & > a { - font-size: 24px; - font-weight: lighter; + @extend .heading-2; padding-left: 0; padding-right: 0; margin-right: 40px; @@ -55,7 +54,7 @@ .vsp-attachments-heat-validation { @extend .body-1; display: flex; - .svg-icon.exclamation-triangle-line { + .svg-icon.exclamationTriangleFull { fill: $orange; width: 15px; height: 15px; @@ -88,7 +87,7 @@ margin-left: 20px; } .tree-header-title-text { - @extend .heading-4-medium; + @extend .heading-4-semibold; padding-left: 32px; cursor: pointer; &.tree-header-title-selected{ @@ -121,7 +120,7 @@ .error-text, .warning-text { @extend .body-3; &.large { - @extend .heading-4-medium; + @extend .heading-4-semibold; } } } @@ -146,9 +145,11 @@ justify-content: space-between; height: 40px; align-items: center; - .svg-icon.chevron-down, .svg-icon.chevron-up { - height: 10px; - width: 10px; + .svg-icon-wrapper.chevronDown, .svg-icon-wrapper.chevronUp { + .svg-icon { + height: 10px; + width: 10px; + } } &:after { @@ -227,7 +228,7 @@ margin-left: 15px; } .error-file-name { - @extend .body-1-medium; + @extend .body-1-semibold; margin-right: 5px; } } diff --git a/openecomp-ui/resources/scss/modules/_softwareProductComponentGeneral.scss b/openecomp-ui/resources/scss/modules/_softwareProductComponentGeneral.scss index 67d76f5454..6c5bcee03c 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductComponentGeneral.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductComponentGeneral.scss @@ -3,8 +3,11 @@ .one-line-textarea { height: 30px; } - .multi-line-textarea > textarea { - height: 113px; + .multi-line-textarea { + height: calc(100% - 25px); + textarea { + height: inherit; + } } } .additional-validation-form { diff --git a/openecomp-ui/resources/scss/modules/_softwareProductComponentImage.scss b/openecomp-ui/resources/scss/modules/_softwareProductComponentImage.scss new file mode 100644 index 0000000000..068404fcb6 --- /dev/null +++ b/openecomp-ui/resources/scss/modules/_softwareProductComponentImage.scss @@ -0,0 +1,58 @@ +.image-modal-new { + .modal-dialog { + width: 600px; + } + .image-filename { + width: 480px; + } +} + +.image-modal-edit { + .modal-dialog { + width: 910px; + } + .image-filename { + width: 550px; + } +} + +.image-modal-edit, .image-modal-new { + .modal-body { + padding: 0; + } + .vsp-components-image-editor { + + .image-format, .image-md5, .image-version { + width: 200px; + } + .image-version { + padding-left: 30px; + } + .section-title { + text-transform: capitalize; + font-size: 18px; + } + } +} + +.vsp-components-image { + .list-editor-item-view-content { + flex:1; + min-width: 0; + } + .list-editor-item-view-controller { + padding-top: 5px; + } + .image-filename-cell { + display: flex; + .image-filename { + white-space: nowrap; + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + Â span { + @include ellipsis(100%); + } + } + } +} diff --git a/openecomp-ui/resources/scss/modules/_softwareProductComponentNetwork.scss b/openecomp-ui/resources/scss/modules/_softwareProductComponentNetwork.scss index e14ab02fcd..402918bc5e 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductComponentNetwork.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductComponentNetwork.scss @@ -10,24 +10,39 @@ } .list-editor-view { margin-top: 50px; + .manual-title { + @extend .body-1-semibold; + } } } -.network-nic-modal { - .modal-body { - padding: 0; - } +.network-nic-modal-create { + .network-type-radio { + display: flex; + } +} +.network-nic-modal-edit, .network-nic-modal-create { + .modal-body { + padding: 0; + } + .validation-form-content { + padding-left: 50px; + padding-right: 50px; + padding-top: 20px; + } +} +.network-nic-modal-edit { + .modal-dialog { + width: 900px; + } .vsp-components-network-editor { .editor-data { - padding-left: 50px; - padding-right: 50px; - padding-top: 20px; height: 500px; .grid-section { padding-bottom: 15px; .section-title { @extend .heading-5; padding-bottom: 10px; - padding-left: 0px; + padding-left: 0; } } .part-title { @@ -38,7 +53,7 @@ .part-title-small { @extend .heading-3; padding-bottom: 10px; - padding-left: 0px; + padding-left: 0; } .network-radio label { font-size: 15px; @@ -51,7 +66,7 @@ .top-row { display: flex; .part-title-small { - padding-left: 0px; + padding-left: 0; &.packets { flex: 0 0 52%; } diff --git a/openecomp-ui/resources/scss/modules/_softwareProductComponentProcessesPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductComponentProcessesPage.scss index a6613190fd..be4caacfb5 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductComponentProcessesPage.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductComponentProcessesPage.scss @@ -5,4 +5,8 @@ .component-process-description > textarea { height: 113px; } +} + +.software-product-landing-view-right-side.vsp-components-processes-page { + overflow-y: initial; }
\ No newline at end of file diff --git a/openecomp-ui/resources/scss/modules/_softwareProductCreatePage.scss b/openecomp-ui/resources/scss/modules/_softwareProductCreatePage.scss index deac736cfa..b788a86e44 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductCreatePage.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductCreatePage.scss @@ -15,7 +15,7 @@ flex: 45%; .validation-input-wrapper { .field-section { - @extend .body-2-medium; + @extend .body-2-semibold; margin-bottom: 23px; color: $black; } diff --git a/openecomp-ui/resources/scss/modules/_softwareProductDependencies.scss b/openecomp-ui/resources/scss/modules/_softwareProductDependencies.scss index 01a50dd741..8fb739234f 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductDependencies.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductDependencies.scss @@ -15,11 +15,11 @@ color: $dark-blue; } } - .select-action-table-view { + .select-action-table-view { min-width: 770px; } .select-action-table-header { - @extend .body-1-medium; + @extend .body-1-semibold; color: $text-black; } -}
\ No newline at end of file +} diff --git a/openecomp-ui/resources/scss/modules/_softwareProductDeployment.scss b/openecomp-ui/resources/scss/modules/_softwareProductDeployment.scss new file mode 100644 index 0000000000..e0de8fc969 --- /dev/null +++ b/openecomp-ui/resources/scss/modules/_softwareProductDeployment.scss @@ -0,0 +1,55 @@ +.deployment-flavor-editor { + .modal-dialog { + width: 780px; + } + .grid-section { + padding-bottom: 25px; + } + .deployment-feature-groups-section.no-feature-groups { + padding-bottom: 0; + .form-group { + margin-bottom: 5px; + } + } + .deployment-feature-group-warning-section { + padding-bottom: 30px; + span { + @extend .body-2; + color: $red; + } + } + .grid-section.vfc-table { + .section-title { + padding-bottom: 10px; + } + } + .modal-content { + .modal-body { + padding: 0; + .validation-form-content { + .grid-col-1 { + flex-basis: 35%; + } + + .Select-value, .Select-placeholder { + font-family: omnes-regular, sans-serif; + } + + .grid-section.vfc-table { + padding-bottom: 50px; + .Select-menu { + max-height: 100px; + } + + } + + .grid-col-3 { + flex-basis: 65%; + } + padding-left: 54px; + padding-right: 33px; + overflow-y: visible; + } + } + } +} diff --git a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss index e75b110425..56860101b2 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductLandingPage.scss @@ -3,11 +3,11 @@ padding-right: 30px; padding-bottom: 10px; .title { - @extend .body-1-medium; + @extend .body-1-semibold; } .file-name { padding-left: 5px; - @extend .body-1-medium; + @extend .body-1-semibold; } } @@ -28,7 +28,7 @@ .missing-license { display: flex; align-items: baseline; - .svg-icon.exclamation-triangle-full { + .svg-icon-wrapper.exclamationTriangleFull .svg-icon{ fill: $orange; } .warning-text { @@ -46,7 +46,7 @@ } } .name { - @extend .body-1-medium; + @extend .body-1-semibold; } .software-product-landing-view-right-side { @extend .flex; @@ -76,7 +76,7 @@ @extend .flex-column; &.title-section { flex: 0.8; - @extend .heading-5-medium; + @extend .heading-5-semibold; } &.title-text { margin-bottom: 24px; @@ -125,7 +125,7 @@ } } .title { - @extend .body-1-medium; + @extend .body-1-semibold; } .software-product-landing-view-heading-title { @extend .section-title; @@ -181,7 +181,7 @@ } .drag-text { color: $blue; - font-weight: bolder; + @extend .body-1-semibold; } .or-text { margin-top: 10px; diff --git a/openecomp-ui/resources/scss/modules/_softwareProductProcessesPage.scss b/openecomp-ui/resources/scss/modules/_softwareProductProcessesPage.scss index 4956616687..d75e7447ab 100644 --- a/openecomp-ui/resources/scss/modules/_softwareProductProcessesPage.scss +++ b/openecomp-ui/resources/scss/modules/_softwareProductProcessesPage.scss @@ -25,13 +25,11 @@ align-items: center; .upload-btn { - padding: 20px; - padding-top: 7px; - padding-bottom: 3px; + padding: 4px 20px; } .drag-text { color: $blue; - font-weight: bolder; + @extend .body-1-semibold; } .or-text { margin-top: 10px; @@ -39,11 +37,9 @@ } } .vsp-processes-editor-data { - padding: 28px 54px; transition: border .2s; .vsp-process-dropzone-view { background-color: transparent; - padding: 15px; &.active-dragging { border: 3px dashed $dark-blue; border-radius: 20px; @@ -53,7 +49,7 @@ } .grid-section { .section-title { - padding-bottom: 0px; + padding-bottom: 0; } } } @@ -66,7 +62,8 @@ } } -.vsp-processes-page { +.software-product-landing-view-right-side.vsp-processes-page { + overflow-y: initial; .processes-list { @extend .flex-column; } diff --git a/openecomp-ui/resources/scss/modules/_softwareproductComponentLoadBalancing.scss b/openecomp-ui/resources/scss/modules/_softwareproductComponentLoadBalancing.scss index 04cb3c2051..ceae4a00de 100644 --- a/openecomp-ui/resources/scss/modules/_softwareproductComponentLoadBalancing.scss +++ b/openecomp-ui/resources/scss/modules/_softwareproductComponentLoadBalancing.scss @@ -1,45 +1,47 @@ .vsp-components-load-balancing { - .svg-icon-wrapper { - position: relative; - top: -3px; - .svg-icon.chevron-up, .svg-icon.chevron-down { - width: 10px; - height: 10px; - } + .svg-icon-wrapper { + position: relative; + top: -3px; + &.chevronUp, &.chevronDown { + .svg-icon { + width: 10px; + height: 10px; + } } + } .halb-data { - .load-balancing-page-title { - @extend .section-title; - &:first-child { - padding: 0 0 40px 0; - } - } - .question { - padding-top: 10px; - &:first-child { - padding-top: 0; - } - } - .title { - @extend .body-1-medium; - margin-bottom: 8px; - cursor: pointer; - .svg-icon { - @include transition(transform 0.3s); - margin-right: 5px; - position: relative; - top: 4px; - } - } - .add-padding { - padding-bottom: 20px; - } - .new-line { - margin-left: 16px; - } - textarea.form-control { - height: 90px; - } + .load-balancing-page-title { + @extend .section-title; + &:first-child { + padding: 0 0 40px 0; + } + } + .question { + padding-top: 10px; + &:first-child { + padding-top: 0; + } + } + .title { + @extend .body-1-semibold; + margin-bottom: 8px; + cursor: pointer; + .svg-icon { + @include transition(transform 0.3s); + margin-right: 5px; + position: relative; + top: 4px; + } + } + .add-padding { + padding-bottom: 20px; + } + .new-line { + margin-left: 16px; + } + textarea.form-control { + height: 90px; + } } } diff --git a/openecomp-ui/resources/scss/modules/_vspComponentCompute.scss b/openecomp-ui/resources/scss/modules/_vspComponentCompute.scss new file mode 100644 index 0000000000..ee8cfa5c7f --- /dev/null +++ b/openecomp-ui/resources/scss/modules/_vspComponentCompute.scss @@ -0,0 +1,19 @@ +.vsp-component-computeFlavor-view { + .component-questionnaire-validation-form { + .vm-sizing-section { + .section-title { + text-transform: capitalize; + font-size: 18px; + } + .duplicate-title-line label.control-label{ + height: 2.7em; + } + } + } +} + +.compute-flavor-editor-modal-edit { + .modal-lg { + width: 1182px; + } +}
\ No newline at end of file diff --git a/openecomp-ui/resources/scss/modules/_vspComponentMonitoring.scss b/openecomp-ui/resources/scss/modules/_vspComponentMonitoring.scss index c49e4f551d..4bcf7940eb 100644 --- a/openecomp-ui/resources/scss/modules/_vspComponentMonitoring.scss +++ b/openecomp-ui/resources/scss/modules/_vspComponentMonitoring.scss @@ -4,7 +4,7 @@ .section-title { padding-bottom: 20px; } - &:first-child { + &:not(:last-child) { padding-bottom: 50px; } .software-product-landing-view-top-block-col-upl { @@ -18,13 +18,11 @@ padding: 25px 0; align-items: center; .upload-btn { - padding: 20px; - padding-top: 7px; - padding-bottom: 3px; + padding: 4px 20px; } .drag-text { color: $blue; - font-weight: bolder; + @extend .body-1-semibold; } .or-text { margin-top: 10px; diff --git a/openecomp-ui/resources/scss/modules/_vspComponentQuestionnaire.scss b/openecomp-ui/resources/scss/modules/_vspComponentQuestionnaire.scss index d194c678b9..5696b354a7 100644 --- a/openecomp-ui/resources/scss/modules/_vspComponentQuestionnaire.scss +++ b/openecomp-ui/resources/scss/modules/_vspComponentQuestionnaire.scss @@ -25,7 +25,7 @@ .vertical-flex { flex-direction: column; .control-label { - @extend .body-2-medium; + @extend .body-2-semibold; } .radio-options-content-row { display: flex; diff --git a/openecomp-ui/resources/scss/modules/_vspHeatSetup.scss b/openecomp-ui/resources/scss/modules/_vspHeatSetup.scss index 59e983686b..75d96b4c85 100644 --- a/openecomp-ui/resources/scss/modules/_vspHeatSetup.scss +++ b/openecomp-ui/resources/scss/modules/_vspHeatSetup.scss @@ -82,31 +82,35 @@ min-width: 0; } - .svg-icon.trash-o { + .svg-icon-wrapper.trashO { + .svg-icon { fill: $dark-gray; height: 18px; width: 18px; &:hover { - fill: $black; + fill: $black; } + } } .module-title-by-type { - @extend .heading-5-medium; + @extend .heading-5-semibold; margin-right: 3px; } .modules-list-item-filename { display: flex; align-items: center; - .svg-icon.pencil { - height: 15px; - width: 15px; + .svg-icon-wrapper.pencil { + .svg-icon { + height: 15px; + width: 15px; + } margin-left: 3px; opacity: 0; } .filename-text { - @extend .heading-5-medium; + @extend .heading-5-semibold; } @@ -120,7 +124,7 @@ padding: 0; .name-edit { padding: 4px; - @extend .heading-5-medium; + @extend .heading-5-semibold; height: 100%; border: 1px solid $light-gray; width: 400px; @@ -140,12 +144,14 @@ border-color: transparent; } } - .svg-icon.pencil { + .svg-icon-wrapper.pencil { margin-left: 10px; opacity: 1; - stroke: $dark-gray; - &:hover { - stroke: $black; + .svg-icon { + stroke: $dark-gray; + &:hover { + stroke: $black; + } } } } @@ -158,7 +164,7 @@ .Select-option { @extend .body-1; &.is-selected { - @extend .body-1-medium; + @extend .body-1-semibold; background-color: $white; } &.is-focused { @@ -220,7 +226,7 @@ } .artifact-files-header { - @extend .heading-5-medium; + @extend .heading-5-semibold; display: flex; margin-bottom: 10px; justify-content: space-between; @@ -248,7 +254,6 @@ .unassigned-files { margin-top: 30px; border: 1px solid $light-gray; - width: 25%; background-color: $white; height: 250px; width: 250px; @@ -258,7 +263,7 @@ top: 10px; .unassigned-files-title { - @extend .heading-5-medium; + @extend .heading-5-semibold; background-color: $tlv-gray; padding: 11px 0 9px 15px; } @@ -284,16 +289,20 @@ display: flex; align-items: center; margin-bottom: 10px; - .svg-icon.angle-right { + .svg-icon-wrapper.angleRight { + .svg-icon { height: 10px; width: 10px; margin-left: 7px; fill: $blue; + } } &:hover { color: $dark-blue; - .svg-icon.angle-right { + .svg-icon-wrapper.angleRight { + .svg-icon { fill: $dark-blue; + } } } } diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogTile.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogTile.scss index 5ce8e12ec3..07f86aba2a 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogTile.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_catalogTile.scss @@ -1,8 +1,8 @@ .catalog-tile { - &:hover { - box-shadow: 0.3px 5px 12.8px 1.3px rgba(24, 24, 25, 0.15); - border: 1px solid $light-gray; - } + &:hover { + box-shadow: 0.3px 5px 12.8px 1.3px rgba(24, 24, 25, 0.15); + border: 1px solid $light-gray; + } .catalog-tile-top { position: relative; flex: 1; @@ -11,48 +11,54 @@ padding-left: 10px; align-items: flex-start; flex-direction: column; - .catalog-tile-content { - margin-top: auto; - width: 180px; - } - + .catalog-tile-content { + margin-top: auto; + width: 180px; + } .catalog-tile-type { - display: block; - margin-top: -25px; - font-size: $heading-font-5; - &.license-model-type { - color: $purple; - } - &.software-product-type { - color: $blue; - } + display: block; + margin-top: -25px; + font-size: $heading-font-5; + &.license-model-type { + color: $purple; + } + &.software-product-type { + color: $blue; + } } .catalog-tile-entity-details { - margin-top:23px; - .catalog-tile-version-info{ - display: flex; - justify-content: space-between; + margin-top: 20px; + display: flex; + flex-direction: column; + justify-content: space-between; + flex: 0.8; + .catalog-tile-version-info { + display: flex; + justify-content: space-between; - .catalog-tile-item-version { - @extend .body-2; - line-height: 6px; - } - } - .catalog-tile-vendor-name { - @extend .body-3-medium; - color: $gray; - line-height: 12px; - @include ellipsis(auto,inline-block,178px); + .catalog-tile-item-version { + @extend .body-2; + line-height: 6px; } + } + .catalog-tile-vendor-name { + @extend .body-3; + flex: 0.4; + align-self: baseline; + color: $gray; + line-height: 10px; + @include ellipsis(auto, inline-block, 178px); + } - } - .catalog-tile-item-name { - @extend .heading-5-medium; - color: $black; - @include ellipsis(auto,inline-block,175px); - } } + .catalog-tile-item-name { + @extend .heading-5-semibold; + color: $black; + @include ellipsis(auto, inline-block, 175px); + line-height: inherit; + } + } .catalog-tile-icon { width: 58px; @@ -65,32 +71,39 @@ align-self: center; height: 58px; width: 58px; - margin-left: 122px; + margin-left: 122px; background-repeat: no-repeat; - .svg-icon { + .svg-icon-wrapper { &.vendor { - fill: $dark-gray; - margin-top: 22px; - width: 53px; - height: 47px; - &:hover { + .svg-icon { fill: $dark-gray; + width: 53px; + height: 47px; + &:hover { + fill: $dark-gray; + } } + margin-top: 22px; + } &.vsp { - fill: $light-blue; + .svg-icon { + fill: $light-blue; + width: 60px; + height: 40px; + } margin-top: 18px; margin-left: 3px; - width: 60px; - height: 40px; } &.vlm { - fill: $purple; margin-top: 18px; - width: 45px; - height: 53px; - } + .svg-icon { + fill: $purple; + width: 45px; + height: 53px; + } + } } } } @@ -99,13 +112,17 @@ padding-top: 5px; display: flex; justify-content: space-between; - margin-top:2px; + margin-top: 2px; padding-bottom: 3px; - @extend .body-2-medium; - .svg-icon.plus { - height: 9px; - width: 9px; - fill: $blue; + @extend .body-2-semibold; + .svg-icon-wrapper { + &.plus { + .svg-icon { + height: 9px; + width: 9px; + fill: $blue; + } + } } .catalog-tile-item-details { overflow: hidden; @@ -113,27 +130,27 @@ .catalog-tile-add-new-vsp { color: $blue; - margin-left:40px; + margin-left: 40px; } .catalog-tile-locking-user-name { @extend .body-2; - @include ellipsis(auto,inline-block,180px); + @include ellipsis(auto, inline-block, 180px); } - .catalog-tile-check-in-status { - .svg-icon-wrapper { - .svg-icon { - &.locked { - margin-left: 7px; - width: 11px; - fill: $gray; - } - &.unlocked { - margin-left: 7px; - width: 11px; - fill: $gray; - } - } - } + .catalog-tile-check-in-status { + .svg-icon-wrapper { + &.locked { + .svg-icon { + width: 11px; + fill: $gray; + } } + &.unlocked { + .svg-icon { + width: 11px; + fill: $gray; + } + } + } + } } } diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_createItemTile.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_createItemTile.scss index b9f83fc452..aa3cf04c4f 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_createItemTile.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_createItemTile.scss @@ -22,7 +22,7 @@ } &:hover { box-shadow: 0.3px 5px 12.8px 1.3px rgba(24, 24, 25, 0.15); - + border: 1px solid $light-gray; } &:only-child { @@ -33,7 +33,7 @@ margin: 0 0 15px 0; } .create-item-text { - @extend .heading-4-medium; + @extend .heading-4-semibold; } } .create-item-plus-icon{ @@ -42,14 +42,14 @@ margin: -5px 12px 0 0; .svg-icon.plus { height: 19px; - width: 19px; + width: 19px; } } &.vlm-type { .create-item-text { color: $purple; } - + .create-item-plus-icon { fill: $purple; } @@ -58,14 +58,14 @@ .create-item-text { color: $blue; } - + .create-item-plus-icon { fill: $blue; } } .create-item-text { width: 140px; - @extend .heading-5-medium; + @extend .heading-5-semibold; } } } diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_onboardHeader.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_onboardHeader.scss index da4c017d39..32ebac98cf 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_onboardHeader.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_onboardHeader.scss @@ -15,7 +15,7 @@ flex-direction: row; margin-left: 60px; .onboard-header-tab { - @extend .body-1-medium; + @extend .body-1-semibold; margin-right: 40px; cursor: pointer; display: flex; diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_vendorTile.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_vendorTile.scss index 79a64f84ee..5972bb2d67 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_vendorTile.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_vendorTile.scss @@ -1,87 +1,87 @@ @mixin flipOverlayDirection($itemsInRow) { - &:nth-child(#{$itemsInRow}n){ - .vsp-overlay-wrapper { - right: 74%; - left: inherit; - .vsp-overlay-arrow { - border-right-color: transparent; - border-left-color: $tlv-light-gray; - border-right-width: 2px; - border-left-width: 6px; - left: 100%; - &:after { - border-left-color: $white; - border-right-color: transparent; - left: -11px; - } - } + &:nth-child(#{$itemsInRow}n) { + .vsp-overlay-wrapper { + right: 74%; + left: inherit; + .vsp-overlay-arrow { + border-right-color: transparent; + border-left-color: $tlv-light-gray; + border-right-width: 2px; + border-left-width: 6px; + left: 100%; + &:after { + border-left-color: $white; + border-right-color: transparent; + left: -11px; } + } + } } } - .catalog-tile.vendor-type { position: relative; .catalog-tile-top { - .catalog-tile-item-name { - margin-top:21px; - } - .catalog-tile-vsp-count { - @extend .body-3-medium; - margin-top: 8px; - margin-left: 54px; - margin-bottom: 9px; - color: $dark-gray; - border: 1px solid $dark-gray; - padding: 0 15px 0 15px; - border-radius: 15px; - - &.clickable { - &:hover { - background-color: #eceff3; - color: $dark-gray ; - } - } - &.active { - background-color: $white; - color: $dark-gray ; - } + .catalog-tile-item-name { + margin-top: 21px; + line-height: inherit; + } + .catalog-tile-vsp-count { + @extend .body-3-semibold; + margin-top: 8px; + margin-left: 54px; + margin-bottom: 9px; + color: $dark-gray; + border: 1px solid $dark-gray; + padding: 0 15px 0 15px; + border-radius: 15px; + + &.clickable { + &:hover { + background-color: #eceff3; + color: $dark-gray; } + } + &.active { + background-color: $white; + color: $dark-gray; + } + } } .catalog-tile-content { - flex-basis: auto; - max-height: 31px; - height: 31px; - text-align: center; - color: $blue; - display: block; - background-color: $white; - margin-bottom: 7px; - padding-bottom: 0px; - .create-new-vsp-button { - margin-top: 1px; - } - &:hover { - color: $dark-blue; - .svg-icon.plus { - fill: $dark-blue; - } - } - &.disabled { - cursor: default; - } + flex-basis: auto; + max-height: 31px; + height: 31px; + text-align: center; + color: $blue; + display: block; + background-color: $white; + margin-bottom: 7px; + padding-bottom: 0px; + .create-new-vsp-button { + margin-top: 1px; + } + &:hover { + color: $dark-blue; + .svg-icon.plus { + fill: $dark-blue; + } + } + &.disabled { + cursor: default; + } } - @media (min-width: 1900px){ + @media (min-width: 1900px) { @include flipOverlayDirection($itemsInRow: 8); } - @media (min-width: 1586px) and (max-width: 1899px){ + @media (min-width: 1586px) and (max-width: 1899px) { @include flipOverlayDirection($itemsInRow: 7); } - @media (min-width: 1368px) and (max-width: 1585px){ + @media (min-width: 1368px) and (max-width: 1585px) { @include flipOverlayDirection($itemsInRow: 6); } - @media (max-width: 1367px){ + @media (max-width: 1367px) { @include flipOverlayDirection($itemsInRow: 5); } @import "vspOverlay"; diff --git a/openecomp-ui/resources/scss/modules/onboardingCatalog/_vspOverlay.scss b/openecomp-ui/resources/scss/modules/onboardingCatalog/_vspOverlay.scss index 8816ca5df9..80ed7385e0 100644 --- a/openecomp-ui/resources/scss/modules/onboardingCatalog/_vspOverlay.scss +++ b/openecomp-ui/resources/scss/modules/onboardingCatalog/_vspOverlay.scss @@ -41,7 +41,7 @@ flex-direction: column; margin: 10px 0 10px 0; .vsp-overlay-title { - @extend .heading-5-medium; + @extend .heading-5-semibold; margin-bottom: 15px; padding: 10px 20px 10px 20px; background: $highlight-gray; diff --git a/openecomp-ui/resources/scss/onboarding.scss b/openecomp-ui/resources/scss/onboarding.scss index 6b892ac0a4..d7d4586354 100644 --- a/openecomp-ui/resources/scss/onboarding.scss +++ b/openecomp-ui/resources/scss/onboarding.scss @@ -1,12 +1,68 @@ .dox-ui { @import "bootstrap"; @import "~react-select/dist/react-select.min.css"; + @import "~react-datepicker/dist/react-datepicker.min.css"; @import "common"; @import "components"; @import "modules"; } +/* Out of namespace context for datepicker */ +div[data-reactroot].customized-date-picker-calendar { + @import "common/variables"; + @import "common/typography"; + border-radius: 2px; + border-color: $light-gray; + margin-top: -8px; + .react-datepicker__triangle { + margin-top: 0px; + } + .react-datepicker__navigation--previous { + border: none; + width: 15px; + height: 15px; + margin-top: 2px; + content: url(../images/angle-left.svg); + } + .react-datepicker__navigation--next { + border: none; + width: 15px; + height: 15px; + margin-top: 2px; + content: url(../images/angle-right.svg); + } + .react-datepicker__month-container { + .react-datepicker__header { + background-color: $background-gray; + border-bottom: none; + .react-datepicker__current-month { + @extend .heading-5; + background-color: $background-gray; + margin-bottom: 10px; + } + .react-datepicker__day-names { + @extend .heading-5; + background-color: $white; + } + } + .react-datepicker__day--selected { + @extend .heading-5; + border-radius: 20px; + background-color: $blue; + &:hover { + background-color: $dark-blue; + } + } + .react-datepicker__day { + @extend .heading-5; + &:hover { + border-radius: 20px; + } + } + } +} + /* Out of namespace context for tooltips */ div[data-reactroot].tooltip { @import "common/variables"; @@ -16,11 +72,26 @@ div[data-reactroot].tooltip { opacity: 1; } &.validation-error-message { - &.bottom { - .tooltip-arrow { - border-bottom-color: $red !important; - } - } + &.bottom { + .tooltip-arrow { + border-bottom-color: $red !important; + } + } + &.left { + .tooltip-arrow { + border-left-color: $red !important; + } + } + &.right { + .tooltip-arrow { + border-right-color: $red !important; + } + } + &.top { + .tooltip-arrow { + border-top-color: $red !important; + } + } } &.bottom { .tooltip-arrow { diff --git a/openecomp-ui/runLocalFE.cmd b/openecomp-ui/runLocalFE.cmd new file mode 100644 index 0000000000..ee718f2a0b --- /dev/null +++ b/openecomp-ui/runLocalFE.cmd @@ -0,0 +1,38 @@ +@REM /*! +@REM * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. +@REM * +@REM * Licensed under the Apache License, Version 2.0 (the "License"); +@REM * you may not use this file except in compliance with the License. +@REM * You may obtain a copy of the License at +@REM * +@REM * http://www.apache.org/licenses/LICENSE-2.0 +@REM * +@REM * Unless required by applicable law or agreed to in writing, software +@REM * distributed under the License is distributed on an "AS IS" BASIS, +@REM * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express +@REM * or implied. See the License for the specific language governing +@REM * permissions and limitations under the License. +@REM */ + +@echo off + +SETLOCAL + +set uiDir=%cd% +set currentDir=%cd% +if not ("%1" == "") set uiDir=%1 + +echo check npm version: +call npm -version +if errorlevel 1 ( + echo install node with npm from https://nodejs.org/en/download/ + goto done +) +echo npm is installed +echo one more check... +call npm list prompt +if errorlevel 1 ( + npm install prompt +) +echo ready to run +call node runLocalFE.js diff --git a/openecomp-ui/runLocalFE.js b/openecomp-ui/runLocalFE.js new file mode 100644 index 0000000000..1205aa48f9 --- /dev/null +++ b/openecomp-ui/runLocalFE.js @@ -0,0 +1,104 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +var exec = require('child_process'); +var prompt = require('prompt'); +var fs = require('fs'); + + +function runNpm(target, dir) { + console.log('\n---> npm ' + target); + let options = {stdio:[0,1,2]}; + if (dir) options.cwd = dir; + exec.execSync("npm " + target,options); +} + +function npmInstallAll() { + setNpmconfig(); + if (!fs.existsSync('../dox-sequence-diagram-ui/node_modules')) { + console.log('--> first time installing dox-sequence-diagram-ui'); + runNpm('install', '../dox-sequence-diagram-ui'); + }; + runNpm('install'); + // just to make sure restful js is installed properly + runNpm('install jquery', 'node_modules/restful-js'); +} + +function getDevConfig() { + var content=fs.readFileSync('./devConfig.json'); + var data=JSON.parse(content); + console.log('Current ATT server is set to: ' + data.proxyATTTarget); + if (!data.proxyTarget) { + console.log('Current onboarding server defaults to the ATT server'); + } else { + console.log('Current onboarding server set to: ' + data.proxyTarget); + } + return data; +} + +function setNpmconfig() { + exec.execSync("npm config set proxy http://genproxy.amdocs.com:8080"); + exec.execSync("npm config set https_proxy http://genproxy.amdocs.com:8080"); +} + +// getting the run details before starting to work +prompt.start(); +prompt.get([{ + name:'runType', + type:'number', + default:1, + description: 'Choose run: 1-test and build, 2- run frontend server ' + }], function (err, result) { + if (result.runType === 2) { + console.log('--> Reading the configuration for the local server'); + if (!fs.existsSync('./devConfig.json')) { + console.log('First time - setting up the devConfig.json file'); + fs.writeFileSync('./devConfig.json', fs.readFileSync('./devConfig.defaults.json')); + } + let data = getDevConfig(); + let attProxyField = { + name:'attProxyTarget', + description:'ATT server' + }; + let proxyField = { + name:'proxyTarget', + description:'onboarding server, \'null\' to reset' + }; + if (data.proxyATTTarget) attProxyField.default = data.proxyATTTarget; + if (data.proxyTarget) proxyField.default = data.proxyTarget; + prompt.get([ attProxyField, proxyField], function (err,result) { + data.proxyATTTarget = result.attProxyTarget; + if(result.proxyTarget) { + if (result.proxyTarget === 'null') { + if (data.proxyTarget) delete data.proxyTarget; + } else { + data.proxyTarget = result.proxyTarget; + } + } + fs.writeFileSync('./devConfig.json', JSON.stringify(data, null, 2)); + getDevConfig(); + console.log('FE server will be answering on: http://localhost:9000/sdc1/proxy-designer1#/onboardVendor'); + npmInstallAll(); + runNpm("start"); + } + ); + } else { + npmInstallAll(); + runNpm("run build"); + runNpm("run test"); + } +}); + diff --git a/openecomp-ui/src/index.html b/openecomp-ui/src/index.html index 7f4fe04f06..d4fab4dcb2 100644 --- a/openecomp-ui/src/index.html +++ b/openecomp-ui/src/index.html @@ -9,34 +9,6 @@ <body> <div id="sdc-app" class="sdc-app"></div> -<script> - -(function(){ - - /** - * Bundle Import script( By Language)! - */ - - var DEFAULT_LANG = 'en'; - var lang = localStorage.getItem('user_locale') || ((navigator && (navigator.language || navigator.userLanguage)) || DEFAULT_LANG).toLowerCase(); - - function writeAppBundle() { - var supportedLangs = [ - //<!--prod:supported-langs--><!--/prod:supported-langs--> - ]; - if(-1 === supportedLangs.indexOf(lang)) { - lang = DEFAULT_LANG; - } - - var bundleScript = document.createElement('script'); - bundleScript.src = 'bundle_' + lang + '.js'; - document.write(bundleScript.outerHTML); - } - - writeAppBundle(); - -})() -</script> - </body> </html> +npm diff --git a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx index 0759f2c28d..5fe592a663 100644 --- a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx +++ b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx @@ -16,7 +16,7 @@ import React, {Component} from 'react'; import ListGroupItem from 'react-bootstrap/lib/ListGroupItem.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Icon from 'nfvo-components/icon/Icon.jsx'; import {Collapse} from 'react-bootstrap'; /** @@ -145,7 +145,7 @@ class ErrorBlock extends React.Component { const ErrorHeader = ({errorType, collapsed, onClick}) => { return( <div onClick={onClick} className='error-block-header'> - <SVGIcon iconClassName={collapsed ? '' : 'right' } name='chevron-down'/> + <SVGIcon iconClassName={collapsed ? '' : 'right' } name='chevronDown'/> {errorType} </div> ); diff --git a/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx new file mode 100644 index 0000000000..cd39376bda --- /dev/null +++ b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx @@ -0,0 +1,75 @@ +import React from 'react'; +import DatePicker from 'react-datepicker'; +import moment from 'moment'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; + +class CustomInput extends React.Component { + + static propTypes = { + placeHolderText: React.PropTypes.string, + onChange: React.PropTypes.func, + onClick: React.PropTypes.func, + value: React.PropTypes.string + }; + + render() { + const {placeholderText, onClick, onClear, inputRef, value: date} = this.props; + const text = date ? date : placeholderText; + const textStyle = date ? '' : 'placeholder'; + return ( + <div ref={inputRef} className='datepicker-custom-input'> + <div onClick={onClick} className={`datepicker-text ${textStyle}`}>{text}</div> + <div onClick={onClear} className='clear-input'/> + <SVGIcon onClick={onClick} name='calendar'/> + </div> + ); + } +}; + +const parseDate = (date, format) => { + return typeof date === 'number' ? moment.unix(date) : moment(date, format); +}; + +class Datepicker extends React.Component { + static propTypes = { + date: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), + format: React.PropTypes.string, + onChange: React.PropTypes.func, + selectsStart: React.PropTypes.bool, + selectsEnd: React.PropTypes.bool, + startDate: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), + endDate: React.PropTypes.oneOfType([React.PropTypes.string, React.PropTypes.number]), + disabled: React.PropTypes.bool, + label: React.PropTypes.string, + isRequired: React.PropTypes.bool + } + render() { + let {date, format, onChange, selectsStart = false, startDate = null, endDate = null, selectsEnd = false, + disabled = false, inputRef} = this.props; + const placeholderText = 'Enter a date'; + const props = { + format, + onChange, + disabled, + selected: date ? parseDate(date, format) : date, + selectsStart, + selectsEnd, + placeholderText, + startDate: startDate ? parseDate(startDate, format) : startDate, + endDate: endDate ? parseDate(endDate, format) : endDate + }; + + return ( + <div className='customized-date-picker'> + <DatePicker + calendarClassName='customized-date-picker-calendar' + customInput={<CustomInput inputRef={inputRef} onClear={() => onChange(undefined)} placeholderText={placeholderText}/>} + minDate={selectsEnd && props.startDate} + maxDate={selectsStart && props.endDate} + {...props}/> + </div> + ); + } +} + +export default Datepicker; diff --git a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx index 175b3ee082..de8a4f3e64 100644 --- a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx +++ b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx @@ -14,10 +14,11 @@ * permissions and limitations under the License. */ import React from 'react'; +import classnames from 'classnames'; -const GridSection = ({title, children, titleClassName}) => { +const GridSection = ({title, children, className, titleClassName}) => { return ( - <div className='grid-section'> + <div className={classnames('grid-section', className)}> {title && <div className={`section-title ${titleClassName || ''}`}>{title}</div>} <div className='grid-items'> {children} diff --git a/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx b/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx deleted file mode 100644 index dd165fb52c..0000000000 --- a/openecomp-ui/src/nfvo-components/icon/SVGIcon.jsx +++ /dev/null @@ -1,54 +0,0 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * - * 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. - */ -import React, {PropTypes} from 'react'; -import Configuration from 'sdc-app/config/Configuration.js'; - -export default class SVGIcon extends React.Component { - - static propTypes = { - name: PropTypes.string.isRequired, - onClick: PropTypes.func, - label: PropTypes.oneOfType([PropTypes.string, PropTypes.node]), - labelPosition: PropTypes.string, - className: PropTypes.string, - iconClassName: PropTypes.string, - labelClassName: PropTypes.string - }; - - static defaultProps = { - name: '', - label: '', - className: '', - iconClassName: '', - labelClassName: '', - labelPosition: 'bottom' - }; - - render() { - let {name, onClick, label, className, iconClassName, labelClassName, labelPosition, ...other} = this.props; - let classes = `svg-icon-wrapper ${className} ${onClick ? 'clickable' : ''} ${labelPosition}`; - - return ( - <div {...other} onClick={onClick} className={classes}> - <svg className={`svg-icon ${name} ${iconClassName}`} > - <use href={Configuration.get('appContextPath') + '/resources/images/svg/' + this.props.name + '.svg#' + this.props.name + '_icon' } - xlinkHref={Configuration.get('appContextPath') + '/resources/images/svg/' + this.props.name + '.svg#' + this.props.name + '_icon' } /> - </svg> - {label && <span className={`svg-icon-label ${labelClassName}`}>{label}</span>} - </div> - ); - } -} diff --git a/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js b/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js deleted file mode 100644 index 6675670cea..0000000000 --- a/openecomp-ui/src/nfvo-components/icon/SVGIcon.stories.js +++ /dev/null @@ -1,50 +0,0 @@ -import React from 'react'; -import {storiesOf, action} from '@kadira/storybook'; -import {select, text, withKnobs} from '@kadira/storybook-addon-knobs'; -import SVGIcon from './SVGIcon.jsx'; - -const stories = storiesOf('SVGIcon', module); - -const iconNames = ['locked', - 'pencil', - 'plus-circle', - 'plus', - 'search', - 'sliders', - 'trash-o', - 'unlocked', - 'vendor', - 'version-controller-lock-closed', - 'version-controller-lock-open', - 'version-controller-revert', - 'version-controller-save', - 'version-controller-submit', - 'vlm', - 'vsp' ]; - -function colorChanger() { - return {fill: text('Color', '')}; -} - -function iconName() { - return select('Icon name' , iconNames, iconNames[0]); -} - -stories.addDecorator(withKnobs); - -stories - .add('icon', () => { - return ( - <SVGIcon name={iconName()} style={colorChanger()}/> - ); - }) - .add('icon with label', () => { - return ( - <SVGIcon name={iconName()} label={iconName()} style={colorChanger()}/> - ); - }) - .add('locked clickable', () => { - return ( - <SVGIcon name={iconName()} onClick={action('clicked')} style={colorChanger()}/> - ); - });
\ No newline at end of file diff --git a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx index e2ee40fcd2..eab1d45ef4 100644 --- a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx +++ b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx @@ -15,11 +15,11 @@ */ import React from 'react'; import ReactDOM from 'react-dom'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Input from 'nfvo-components/input/validation/InputWrapper.jsx'; const ExpandableInputClosed = ({iconType, onClick}) => ( - <SVGIcon className='expandable-input-wrapper closed' name={iconType} onClick={onClick} /> + <SVGIcon className='expandable-input-wrapper closed' data-test-id='expandable-input-closed' name={iconType} onClick={onClick} /> ); class ExpandableInputOpened extends React.Component { @@ -58,6 +58,7 @@ class ExpandableInputOpened extends React.Component { <div className='expandable-input-wrapper opened' key='expandable'> <Input type='text' + data-test-id='expandable-input-opened' value={value} ref={(input) => this.searchInputNode = input} className='expandable-active' @@ -65,7 +66,7 @@ class ExpandableInputOpened extends React.Component { onChange={e => onChange(e)} onKeyDown={e => this.handleKeyDown(e)} onBlur={handleBlur}/> - {value && <SVGIcon onClick={() => this.handleClose()} name='close' />} + {value && <SVGIcon data-test-id='expandable-input-close-btn' onClick={() => this.handleClose()} name='close' />} {!value && <SVGIcon name={iconType} onClick={handleBlur}/>} </div> ); diff --git a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx index c60d6f777e..a3be363ba4 100644 --- a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx +++ b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx @@ -14,7 +14,7 @@ * permissions and limitations under the License. */ import React from 'react'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Input from 'nfvo-components/input/validation/InputWrapper.jsx'; class DualListboxView extends React.Component { @@ -118,10 +118,10 @@ class DualListboxView extends React.Component { renderOperationsBar(isReadOnlyMode) { return ( <div className={`dual-list-options-bar${isReadOnlyMode ? ' disabled' : ''}`}> - {this.renderOperationBarButton(() => this.addToSelectedList(), 'angle-right')} - {this.renderOperationBarButton(() => this.removeFromSelectedList(), 'angle-left')} - {this.renderOperationBarButton(() => this.addAllToSelectedList(), 'angle-double-right')} - {this.renderOperationBarButton(() => this.removeAllFromSelectedList(), 'angle-double-left')} + {this.renderOperationBarButton(() => this.addToSelectedList(), 'angleRight')} + {this.renderOperationBarButton(() => this.removeFromSelectedList(), 'angleLeft')} + {this.renderOperationBarButton(() => this.addAllToSelectedList(), 'angleDoubleRight')} + {this.renderOperationBarButton(() => this.removeAllFromSelectedList(), 'angleDoubleLeft')} </div> ); } diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx index 98810d1c0d..8d53322587 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx @@ -25,7 +25,9 @@ class Form extends React.Component { onReset : null, labledButtons: true, onValidChange : null, - isValid: true + isValid: true, + submitButtonText: null, + cancelButtonText: null }; static propTypes = { @@ -36,6 +38,8 @@ class Form extends React.Component { onSubmit : React.PropTypes.func, onReset : React.PropTypes.func, labledButtons: React.PropTypes.bool, + submitButtonText: React.PropTypes.string, + cancelButtonText: React.PropTypes.string, onValidChange : React.PropTypes.func, onValidityChanged: React.PropTypes.func, onValidateForm: React.PropTypes.func @@ -48,7 +52,8 @@ class Form extends React.Component { render() { // eslint-disable-next-line no-unused-vars - let {isValid, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, onDataChanged, children, ...formProps} = this.props; + let {isValid, onValidChange, onValidityChanged, onDataChanged, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, submitButtonText, + cancelButtonText, children, ...formProps} = this.props; return ( <form {...formProps} ref={(form) => this.form = form} onSubmit={event => this.handleFormValidation(event)}> <div className='validation-form-content'> @@ -56,7 +61,13 @@ class Form extends React.Component { {children} </fieldset> </div> - {hasButtons && <ValidationButtons labledButtons={labledButtons} ref={(buttons) => this.buttons = buttons} isReadOnlyMode={isReadOnlyMode}/>} + {hasButtons && + <ValidationButtons + labledButtons={labledButtons} + submitButtonText={submitButtonText} + cancelButtonText={cancelButtonText} + ref={(buttons) => this.buttons = buttons} + isReadOnlyMode={isReadOnlyMode}/>} </form> ); } diff --git a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx index 59c35d7993..eef8fee1ce 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx @@ -22,6 +22,7 @@ import FormGroup from 'react-bootstrap/lib/FormGroup.js'; import FormControl from 'react-bootstrap/lib/FormControl.js'; import Overlay from 'react-bootstrap/lib/Overlay.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; +import Datepicker from 'nfvo-components/datepicker/Datepicker.jsx'; class Input extends React.Component { @@ -29,13 +30,14 @@ class Input extends React.Component { value: this.props.value, checked: this.props.checked, selectedValues: [] - } + }; render() { const {label, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props; // eslint-disable-next-line no-unused-vars - const {groupClassName, isValid = true, errorText, isRequired, ...inputProps} = this.props; - let wrapperClassName = (type !== 'radio') ? 'validation-input-wrapper' : 'form-group'; + const {groupClassName, isValid = true, errorText, isRequired, overlayPos, ...inputProps} = this.props; + const {dateFormat, startDate, endDate, selectsStart, selectsEnd} = this.props; // Date Props + let wrapperClassName = (type !== 'radio') ? 'validation-input-wrapper' : 'validation-radio-wrapper'; if (disabled) { wrapperClassName += ' disabled'; } @@ -43,7 +45,7 @@ class Input extends React.Component { <div className={wrapperClassName}> <FormGroup className={classNames('form-group', [groupClassName], {'required' : isRequired , 'has-error' : !isValid})} > {(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>} - {(type === 'text' || type === 'number') && + {type === 'text' && <FormControl bsClass={'form-control input-options-other'} onChange={(e) => this.onChange(e)} @@ -54,6 +56,17 @@ class Input extends React.Component { inputRef={(input) => this.input = input} type={type} data-test-id={this.props['data-test-id']}/>} + {type === 'number' && + <FormControl + bsClass={'form-control input-options-other'} + onChange={(e) => this.onChange(e)} + disabled={isReadOnlyMode || Boolean(disabled)} + onBlur={onBlur} + onKeyDown={onKeyDown} + value={(value !== undefined) ? value : ''} + inputRef={(input) => this.input = input} + type={type} + data-test-id={this.props['data-test-id']}/>} {type === 'textarea' && <FormControl @@ -81,6 +94,7 @@ class Input extends React.Component { disabled={isReadOnlyMode || Boolean(disabled)} value={value} onChange={(e)=>this.onChangeRadio(e)} + inputRef={(input) => this.input = input} data-test-id={this.props['data-test-id']}>{label}</Radio>} {type === 'select' && <FormControl onClick={ (e) => this.optionSelect(e) } @@ -88,6 +102,18 @@ class Input extends React.Component { inputRef={(input) => this.input = input} name={name} {...inputProps} data-test-id={this.props['data-test-id']}/>} + {type === 'date' && + <Datepicker + date={value} + format={dateFormat} + startDate={startDate} + endDate={endDate} + inputRef={(input) => this.input = input} + onChange={this.props.onChange} + disabled={isReadOnlyMode || Boolean(disabled)} + data-test-id={this.props['data-test-id']} + selectsStart={selectsStart} + selectsEnd={selectsEnd} />} </FormGroup> { this.renderErrorOverlay() } </div> @@ -116,7 +142,11 @@ class Input extends React.Component { const {onChange, type} = this.props; let value = e.target.value; if (type === 'number') { - value = Number(value); + if (value === '') { + value = undefined; + } else { + value = Number(value); + } } this.setState({ value @@ -154,7 +184,9 @@ class Input extends React.Component { else if (type === 'text' || type === 'email' || type === 'number' - || type === 'password') { + || type === 'radio' + || type === 'password' + || type === 'date') { position = 'bottom'; } diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx index 5ca716cc20..6c8115deee 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx @@ -71,6 +71,7 @@ class InputWrapper extends React.Component { checked={checked} disabled={isReadOnlyMode || Boolean(disabled)} value={value} + ref={(input) => this.inputWrapper = input} onChange={(e)=>this.onChangeRadio(e)} data-test-id={this.props['data-test-id']}>{label}</Radio>} {type === 'select' && diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx index ebb1473c04..c3808dd2c3 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx @@ -22,14 +22,16 @@ */ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import Button from 'react-bootstrap/lib/Button.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import Button from 'sdc-ui/lib/react/Button.js'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; class ValidationButtons extends React.Component { static propTypes = { labledButtons: React.PropTypes.bool.isRequired, - isReadOnlyMode: React.PropTypes.bool + isReadOnlyMode: React.PropTypes.bool, + submitButtonText: React.PropTypes.string, + cancelButtonText: React.PropTypes.string }; state = { @@ -37,16 +39,16 @@ class ValidationButtons extends React.Component { }; render() { - var submitBtn = this.props.labledButtons ? i18n('Save') : <SVGIcon className='check' name='check'/>; - var closeBtn = this.props.labledButtons ? i18n('Cancel') : <SVGIcon className='close' name='close'/>; + let submitBtn = this.props.labledButtons ? this.props.submitButtonText ? this.props.submitButtonText : i18n('Save') : <SVGIcon className='check' name='check'/>; + let closeBtn = this.props.labledButtons ? this.props.cancelButtonText ? this.props.cancelButtonText : i18n('Cancel') : <SVGIcon className='close' name='close'/>; return ( <div className='validation-buttons'> {!this.props.isReadOnlyMode ? <div> - <Button bsStyle='primary' ref='submitbutton' type='submit' disabled={!this.state.isValid}>{submitBtn}</Button> - <Button type='reset'>{closeBtn}</Button> + <Button type='submit' disabled={!this.state.isValid}>{submitBtn}</Button> + <Button btnType='outline' type='reset'>{closeBtn}</Button> </div> - : <Button type='reset'>{i18n('Close')}</Button> + : <Button btnType='outline' type='reset'>{i18n('Close')}</Button> } </div> ); diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx index f6c906b56b..8d7c63f567 100644 --- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx +++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx @@ -16,18 +16,18 @@ import React from 'react'; import classnames from 'classnames'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import store from 'sdc-app/AppStore.js'; import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; class ListEditorItem extends React.Component { static propTypes = { - onSelect: React.PropTypes.func, - onDelete: React.PropTypes.func, - onEdit: React.PropTypes.func, + onSelect: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]), + onDelete: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]), + onEdit: React.PropTypes.oneOfType([React.PropTypes.func, React.PropTypes.bool]), children: React.PropTypes.node, isReadOnlyMode: React.PropTypes.bool - } + }; render() { let {onDelete, onSelect, onEdit, children, isReadOnlyMode} = this.props; @@ -39,7 +39,7 @@ class ListEditorItem extends React.Component { </div> {(onEdit || onDelete) && <div className='list-editor-item-view-controller'> {onEdit && <SVGIcon name='sliders' onClick={() => this.onClickedItem(onEdit)}/>} - {onDelete && isAbilityToDelete && <SVGIcon name='trash-o' onClick={() => this.onClickedItem(onDelete)}/>} + {onDelete && isAbilityToDelete && <SVGIcon name='trashO' onClick={() => this.onClickedItem(onDelete)}/>} </div>} </div> ); @@ -52,8 +52,8 @@ class ListEditorItem extends React.Component { store.dispatch({ type: modalActionTypes.GLOBAL_MODAL_WARNING, data: { - title: i18n('Error'), - msg: i18n('This item is checkedin/submitted, Click Check Out to continue') + title: i18n('Error'), + msg: i18n('This item is checkedin/submitted, Click Check Out to continue') } }); } diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js index 65a1ad683b..825cc609a8 100644 --- a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js +++ b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js @@ -18,31 +18,33 @@ import React from 'react'; import {connect} from 'react-redux'; import Modal from 'nfvo-components/modal/Modal.jsx'; -import Button from 'react-bootstrap/lib/Button.js'; +import Button from 'sdc-ui/lib/react/Button.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import {modalContentComponents} from 'sdc-app/common/modal/ModalContentMapper.js'; import {actionTypes, typeEnum} from './GlobalModalConstants.js'; const typeClass = { - 'default': 'primary', - error: 'danger', + 'default': 'default', + error: 'negative', warning: 'warning', - success: 'success' + success: 'positive' }; -const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButtonText, cancelButtonText}) => +const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButtonText, cancelButtonText}) => <Modal.Footer> - <Button bsStyle={typeClass[type]} onClick={onDeclined ? () => { - onDeclined(); - onClose();} : () => onClose()}> - {cancelButtonText} + <div className='sdc-modal-footer'> + {onConfirmed && <Button color={typeClass[type]} onClick={() => { + onConfirmed(); + onClose(); + }}>{confirmationButtonText}</Button>} + <Button btnType='outline' color={typeClass[type]} onClick={onDeclined ? () => { + onDeclined(); + onClose();} : () => onClose()}> + {cancelButtonText} </Button> - {onConfirmed && <Button bsStyle={typeClass[type]} onClick={() => { - onConfirmed(); - onClose(); - }}>{confirmationButtonText}</Button>} + </div> </Modal.Footer>; ModalFooter.defaultProps = { @@ -87,7 +89,7 @@ export class GlobalModalView extends React.Component { }; render() { - let {title, type, show, modalComponentName, modalComponentProps, + let {title, type, show, modalComponentName, modalComponentProps, modalClassName, msg, onConfirmed, onDeclined, confirmationButtonText, cancelButtonText, onClose} = this.props; const ComponentToRender = modalContentComponents[modalComponentName]; return ( @@ -96,7 +98,7 @@ export class GlobalModalView extends React.Component { <Modal.Title>{title}</Modal.Title> </Modal.Header> <Modal.Body> - {ComponentToRender ? <ComponentToRender {...modalComponentProps}/> : msg} + {ComponentToRender ? <ComponentToRender {...modalComponentProps}/> : msg} </Modal.Body> {(onConfirmed || onDeclined || type !== typeEnum.DEFAULT) && <ModalFooter @@ -114,7 +116,7 @@ export class GlobalModalView extends React.Component { if (this.props.timeout) { setTimeout(this.props.onClose, this.props.timeout); } - } + } }; export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(GlobalModalView); diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js b/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js index 0a0ed1fd71..3e5545371a 100644 --- a/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js +++ b/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js @@ -31,3 +31,8 @@ export const typeEnum = { WARNING: 'warning', SUCCESS: 'success' }; + +export const modalSizes = { + LARGE: 'large', + SMALL: 'small' +}; diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx index 6d900dd0bb..ecfe7df116 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx +++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx @@ -17,7 +17,7 @@ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; import {actionsEnum, statusEnum, statusBarTextMap } from './VersionControllerConstants.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; @@ -115,8 +115,8 @@ class ActionButtons extends React.Component { render() { const {onSubmit, onRevert, onSave, isLatestVersion, isCheckedIn, isCheckedOut, isFormDataValid, version, status, onCheckinCheckout} = this.props; const [checkinBtnIconSvg, checkinCheckoutBtnTitle] = status === statusEnum.CHECK_OUT_STATUS ? - ['version-controller-lock-open', i18n('Check In')] : - ['version-controller-lock-closed', i18n('Check Out')]; + ['versionControllerLockOpen', i18n('Check In')] : + ['versionControllerLockClosed', i18n('Check Out')]; const disabled = (isLatestVersion && onCheckinCheckout && status !== statusEnum.LOCK_STATUS) ? false : true; return ( <div className='action-buttons'> @@ -125,14 +125,14 @@ class ActionButtons extends React.Component { {onSubmit && onRevert && <div className='version-control-buttons'> <VCButton dataTestId='vc-submit-btn' onClick={onSubmit} isDisabled={!isCheckedIn || !isLatestVersion} - name='version-controller-submit' tooltipText={i18n('Submit')}/> + name='versionControllerSubmit' tooltipText={i18n('Submit')}/> <VCButton dataTestId='vc-revert-btn' onClick={onRevert} isDisabled={!isCheckedOut || version.label === '0.1' || !isLatestVersion} - name='version-controller-revert' tooltipText={i18n('Revert')}/> + name='versionControllerRevert' tooltipText={i18n('Revert')}/> </div> } {onSave && <VCButton dataTestId='vc-save-btn' onClick={() => onSave()} isDisabled={!isCheckedOut || !isFormDataValid || !isLatestVersion} - name='version-controller-save' tooltipText={i18n('Save')}/> + name='versionControllerSave' tooltipText={i18n('Save')}/> } </div> ); diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx index 06cb98bbe8..6c04ad74fd 100644 --- a/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx +++ b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx @@ -1,23 +1,22 @@ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import uuid from 'uuid-js'; export default class SelectActionTable extends React.Component { render() { - let {columns, onAdd, isReadOnlyMode, children, onAddItem} = this.props; + let {columns, onAdd, isReadOnlyMode, children, onAddItem, numOfIcons} = this.props; return ( <div className={`select-action-table-view ${isReadOnlyMode ? 'disabled' : ''}`}> <div className='select-action-table-controllers'> {onAdd && onAddItem && <div data-test-id='select-action-table-add' onClick={onAdd}>{onAddItem}</div>} - <SVGIcon name='trash-o' className='dummy-icon' /> + <SVGIcon name='trashO' className='dummy-icon' /> </div> <div className='select-action-table'> <div className='select-action-table-headers'> {columns.map(column => <div key={uuid.create()} className='select-action-table-header'>{i18n(column)}</div>)} - <SVGIcon name='trash-o' className='dummy-icon' /> - <SVGIcon name='trash-o' className='dummy-icon' /> + {Array(numOfIcons).fill().map(() => <SVGIcon name='trashO' className='dummy-icon' />)} </div> <div className='select-action-table-body'> {children} diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx index 17d8a17c09..a711b42918 100644 --- a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx +++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx @@ -1,5 +1,5 @@ import React from 'react'; -import SVGIcon from '../icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; @@ -11,19 +11,29 @@ function tooltip (msg) { const IconWithOverlay = ({overlayMsg}) => ( <OverlayTrigger placement='bottom' overlay={tooltip(overlayMsg)}> - <SVGIcon name='error-circle'/> + <SVGIcon name='errorCircle'/> </OverlayTrigger> ); -const SelectActionTableRow = ({children, onDelete, hasError, overlayMsg}) => ( +function renderErrorOrCheck({hasError, overlayMsg}) { + if (hasError === undefined) { + return <SVGIcon name='angleRight' className='dummy-icon' />; + } + + if (hasError) { + return overlayMsg ? <IconWithOverlay overlayMsg={overlayMsg}/> : <SVGIcon name='errorCircle'/>; + } + + return <SVGIcon name='checkCircle'/>; +} + +const SelectActionTableRow = ({children, onDelete, hasError, hasErrorIndication, overlayMsg}) => ( <div className='select-action-table-row-wrapper'> <div className={`select-action-table-row ${hasError ? 'has-error' : ''}`}> {children} </div> - {onDelete ? <SVGIcon name='trash-o' data-test-id='select-action-table-delete' onClick={onDelete} /> : <SVGIcon name='angle-left' className='dummy-icon' />} - {hasError ? overlayMsg ? <IconWithOverlay overlayMsg={overlayMsg}/> : <SVGIcon name='error-circle'/> - : hasError === undefined ? <SVGIcon name='angle-left' className='dummy-icon'/> : <SVGIcon name='check-circle'/>} - + {onDelete && <SVGIcon name='trashO' data-test-id='select-action-table-delete' onClick={onDelete} />} + {hasErrorIndication && renderErrorOrCheck({hasError, overlayMsg})} </div> ); diff --git a/openecomp-ui/src/nfvo-utils/Validator.js b/openecomp-ui/src/nfvo-utils/Validator.js index 708179e9fb..8fcf24a714 100644 --- a/openecomp-ui/src/nfvo-utils/Validator.js +++ b/openecomp-ui/src/nfvo-utils/Validator.js @@ -21,6 +21,7 @@ class Validator { static get globalValidationFunctions() { return { required: value => value !== '', + requiredChooseOption: value => value !== '', maxLength: (value, length) => ValidatorJS.isLength(value, {max: length}), minLength: (value, length) => ValidatorJS.isLength(value, {min: length}), pattern: (value, pattern) => ValidatorJS.matches(value, pattern), @@ -31,10 +32,10 @@ class Validator { } return ValidatorJS.isNumeric(value); }, - maximum: (value, maxValue) => value <= maxValue, - minimum: (value, minValue) => value >= minValue, - maximumExclusive: (value, maxValue) => value < maxValue, - minimumExclusive: (value, minValue) => value > minValue, + maximum: (value, maxValue) => {return (value === undefined) ? true : (value <= maxValue);}, + minimum: (value, minValue) => {return (value === undefined) ? true : (value >= minValue);}, + maximumExclusive: (value, maxValue) => {return (value === undefined) ? true : (value < maxValue);}, + minimumExclusive: (value, minValue) => {return (value === undefined) ? true : (value > minValue);}, alphanumeric: value => ValidatorJS.isAlphanumeric(value), alphanumericWithSpaces: value => ValidatorJS.isAlphanumeric(value.replace(/ /g, '')), validateName: value => ValidatorJS.isAlphanumeric(value.replace(/\s|\.|\_|\-/g, ''), 'en-US'), @@ -42,24 +43,26 @@ class Validator { freeEnglishText: value => ValidatorJS.isAlphanumeric(value.replace(/\s|\.|\_|\-|\,|\(|\)|\?/g, ''), 'en-US'), email: value => ValidatorJS.isEmail(value), ip: value => ValidatorJS.isIP(value), - url: value => ValidatorJS.isURL(value) + url: value => ValidatorJS.isURL(value), + alphanumericWithUnderscores: value => ValidatorJS.isAlphanumeric(value.replace(/_/g, '')) }; } static get globalValidationMessagingFunctions() { return { required: () => i18n('Field is required'), + requiredChooseOption: () => i18n('Field should have one of these options'), maxLength: (value, maxLength) => i18n('Field value has exceeded it\'s limit, {maxLength}. current length: {length}', { length: value.length, maxLength }), - minLength: (value, minLength) => i18n('Field value should contain at least {minLength} characters.', {minLength}), - pattern: (value, pattern) => i18n('Field value should match the pattern: {pattern}.', {pattern}), + minLength: (value, minLength) => i18n(`Field value should contain at least ${minLength} characters.`), + pattern: (value, pattern) => i18n(`Field value should match the pattern: ${pattern}.`), numeric: () => i18n('Field value should contain numbers only.'), - maximum: (value, maxValue) => i18n('Field value should be less or equal to: {maxValue}.', {maxValue}), - minimum: (value, minValue) => i18n('Field value should be at least: {minValue}.', {minValue: minValue.toString()}), - maximumExclusive: (value, maxValue) => i18n('Field value should be less than: {maxValue}.', {maxValue}), - minimumExclusive: (value, minValue) => i18n('Field value should be more than: {minValue}.', {minValue: minValue.toString()}), + maximum: (value, maxValue) => i18n(`Field value should be less or equal to: ${maxValue}.`), + minimum: (value, minValue) => i18n(`Field value should be at least: ${minValue.toString()}.`), + maximumExclusive: (value, maxValue) => i18n(`Field value should be less than: ${maxValue}.`), + minimumExclusive: (value, minValue) => i18n(`Field value should be more than: ${minValue.toString()}.`), alphanumeric: () => i18n('Field value should contain letters or digits only.'), alphanumericWithSpaces: () => i18n('Field value should contain letters, digits or spaces only.'), validateName: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'), @@ -68,7 +71,8 @@ class Validator { email: () => i18n('Field value should be a valid email address.'), ip: () => i18n('Field value should be a valid ip address.'), url: () => i18n('Field value should be a valid url address.'), - general: () => i18n('Field value is invalid.') + general: () => i18n('Field value is invalid.'), + alphanumericWithUnderscores: () => i18n('Field value should contain letters, digits or _ only.') }; } diff --git a/openecomp-ui/src/nfvo-utils/i18n/en.json b/openecomp-ui/src/nfvo-utils/i18n/en.json new file mode 100644 index 0000000000..8ed638352c --- /dev/null +++ b/openecomp-ui/src/nfvo-utils/i18n/en.json @@ -0,0 +1,330 @@ +{ + "VSP Errors": "VSP Errors", + "Components Errors": "Components Errors", + "Upload Data Errors": "Upload Data Errors", + "Error: Upload Data Error": "Error: Upload Data Error", + "Field is required": "Field is required", + "Field should have one of these options": "Field should have one of these options", + "Field value has exceeded it\\": "Field value has exceeded it\\", + "Field value should contain at least {minLength} characters.": "Field value should contain at least {minLength} characters.", + "Field value should match the pattern: {pattern}.": "Field value should match the pattern: {pattern}.", + "Field value should contain numbers only.": "Field value should contain numbers only.", + "Field value should be less or equal to: {maxValue}.": "Field value should be less or equal to: {maxValue}.", + "Field value should be at least: {minValue}.": "Field value should be at least: {minValue}.", + "Field value should be less than: {maxValue}.": "Field value should be less than: {maxValue}.", + "Field value should be more than: {minValue}.": "Field value should be more than: {minValue}.", + "Field value should contain letters or digits only.": "Field value should contain letters or digits only.", + "Field value should contain letters, digits or spaces only.": "Field value should contain letters, digits or spaces only.", + "Field value should contain English letters, digits , spaces, underscores, dashes and dots only.": "Field value should contain English letters, digits , spaces, underscores, dashes and dots only.", + "Field value should contain English letters digits and spaces only.": "Field value should contain English letters digits and spaces only.", + "Field value should contain English letters, digits , spaces, underscores, dashes and dots only.": "Field value should contain English letters, digits , spaces, underscores, dashes and dots only.", + "Field value should be a valid email address.": "Field value should be a valid email address.", + "Field value should be a valid ip address.": "Field value should be a valid ip address.", + "Field value should be a valid url address.": "Field value should be a valid url address.", + "Field value is invalid.": "Field value is invalid.", + "Field value should contain letters, digits or _ only.": "Field value should contain letters, digits or _ only.", + "Success": "Success", + "Failure": "Failure", + "Activity Log": "Activity Log", + "OK": "OK", + "Cancel": "Cancel", + "Error": "Error", + "This item is checkedin/submitted, Click Check Out to continue": "This item is checkedin/submitted, Click Check Out to continue", + "Name": "Name", + "Description": "Description", + "Add Workflow": "Add Workflow", + "Edit Workflow": "Edit Workflow", + "Create New Workflow": "Create New Workflow", + "Save": "Save", + "Close": "Close", + "Save Failed": "Save Failed", + "Ok": "Ok", + "File Upload Failed": "File Upload Failed", + "License Model": "License Model", + "Software Products": "Software Products", + "Overview": "Overview", + "License Agreements": "License Agreements", + "Feature Groups": "Feature Groups", + "Entitlement Pools": "Entitlement Pools", + "License Key Groups": "License Key Groups", + "General": "General", + "Deployment Flavors": "Deployment Flavors", + "Process Details": "Process Details", + "Networks": "Networks", + "Components Dependencies": "Components Dependencies", + "Attachments": "Attachments", + "Components": "Components", + "Compute": "Compute", + "High Availability & Load Balancing": "High Availability & Load Balancing", + "Storage": "Storage", + "Images": "Images", + "Monitoring": "Monitoring", + "other": "other", + "One or more tabs are invalid": "One or more tabs are invalid", + "Check In": "Check In", + "Check Out": "Check Out", + "Submit": "Submit", + "Revert": "Revert", + "Submit Succeeded": "Submit Succeeded", + "This license model successfully submitted": "This license model successfully submitted", + "VLM": "VLM", + "VSP": "VSP", + "CREATE NEW VLM": "CREATE NEW VLM", + "CREATE NEW VSP": "CREATE NEW VSP", + "New License Model": "New License Model", + "New Software Product": "New Software Product", + "WORKSPACE": "WORKSPACE", + "ONBOARD CATALOG": "ONBOARD CATALOG", + "Component Dependencies": "Component Dependencies", + "This software product successfully submitted": "This software product successfully submitted", + "Submit Failed": "Submit Failed", + "Vendor Name": "Vendor Name", + "License model by the name \\": "License model by the name \\", + "please select…": "please select…", + "Warning": "Warning", + "Operational Scope": "Operational Scope", + "Threshold Units": "Threshold Units", + "Threshold Value": "Threshold Value", + "Entitlement Metric": "Entitlement Metric", + "Aggregate Function": "Aggregate Function", + "Manufacturer Reference Number": "Manufacturer Reference Number", + "Time": "Time", + "Increments": "Increments", + "Entitlement pool by the name \\": "Entitlement pool by the name \\", + "Add Entitlement Pool": "Add Entitlement Pool", + "Edit Entitlement Pool": "Edit Entitlement Pool", + "Create New Entitlement Pool": "Create New Entitlement Pool", + "Entitlement": "Entitlement", + "Are you sure you want to delete \"{poolName}\"?": "Are you sure you want to delete \"{poolName}\"?", + "This entitlement pool is associated with one or more feature groups": "This entitlement pool is associated with one or more feature groups", + "Part Number": "Part Number", + "Available Entitlement Pools": "Available Entitlement Pools", + "Selected Entitlement Pools": "Selected Entitlement Pools", + "There is no available entitlement pools": "There is no available entitlement pools", + "Available License Key Groups": "Available License Key Groups", + "Selected License Key Groups": "Selected License Key Groups", + "There is no available licsense key groups": "There is no available licsense key groups", + "Feature group by the name \\": "Feature group by the name \\", + "Add Feature Group": "Add Feature Group", + "Edit Feature Group": "Edit Feature Group", + "Create New Feature Group": "Create New Feature Group", + "Pools": "Pools", + "License key": "License key", + "Groups": "Groups", + "Are you sure you want to delete \"{name}\"?": "Are you sure you want to delete \"{name}\"?", + "This feature group is associated with one ore more license agreements": "This feature group is associated with one ore more license agreements", + "Available Feature Groups": "Available Feature Groups", + "Selected Feature Groups": "Selected Feature Groups", + "Requirements and Constraints": "Requirements and Constraints", + "License Term": "License Term", + "There is no available feature groups": "There is no available feature groups", + "License Agreement by the name \\": "License Agreement by the name \\", + "Add License Agreement": "Add License Agreement", + "Edit License Agreement": "Edit License Agreement", + "Create New License Agreement": "Create New License Agreement", + "Type": "Type", + "Feature": "Feature", + "License key group by the name \\": "License key group by the name \\", + "Add License Key Group": "Add License Key Group", + "Edit License Key Group": "Edit License Key Group", + "Create New License Key Group": "Create New License Key Group", + "This license key group is associated with one or more feature groups": "This license key group is associated with one or more feature groups", + "VLM List View": "VLM List View", + "Entities not in Use": "Entities not in Use", + "Create New ": "Create New ", + "overview": "overview", + "{name} needs to be updated. Click ‘Checkout & Update’, to proceed.": "{name} needs to be updated. Click ‘Checkout & Update’, to proceed.", + "Please don’t forget to submit afterwards": "Please don’t forget to submit afterwards", + "{name} is locked by user {lockingUser} for self-healing": "{name} is locked by user {lockingUser} for self-healing", + "Checkout & Update": "Checkout & Update", + "ALL": "ALL", + "BY VENDOR": "BY VENDOR", + "Create new VSP": "Create new VSP", + "Recently Edited": "Recently Edited", + "See More": "See More", + "Upload will erase existing data. Do you want to continue?": "Upload will erase existing data. Do you want to continue?", + "Continue": "Continue", + "Upload validation failed": "Upload validation failed", + "Download HEAT": "Download HEAT", + "Go to Overview": "Go to Overview", + "Upload New HEAT": "Upload New HEAT", + "Are you sure you want to delete {name}?": "Are you sure you want to delete {name}?", + "Virtual Function Components": "Virtual Function Components", + "Filter Components": "Filter Components", + "Add Component": "Add Component", + "Create": "Create", + "Vendor": "Vendor", + "Category": "Category", + "please select...": "please select...", + "Software product by the name \\": "Software product by the name \\", + "Onboarding procedure": "Onboarding procedure", + "HEAT file": "HEAT file", + "Manual": "Manual", + "Dependencies": "Dependencies", + "Add Rule": "Add Rule", + "There is a loop between selections": "There is a loop between selections", + "Select VFC...": "Select VFC...", + "Are you sure you want to delete \"{model}\"?": "Are you sure you want to delete \"{model}\"?", + "Add Deployment Flavor": "Add Deployment Flavor", + "Filter Deployment": "Filter Deployment", + "Licenses": "Licenses", + "Licensing Version": "Licensing Version", + "License Agreement": "License Agreement", + "Select...": "Select...", + "Availability": "Availability", + "Use Availability Zones for High Availability": "Use Availability Zones for High Availability", + "Regions": "Regions", + "Storage Data Replication": "Storage Data Replication", + "Storage Replication Size (GB)": "Storage Replication Size (GB)", + "Storage Replication Source": "Storage Replication Source", + "Storage Replication Freq. (min)": "Storage Replication Freq. (min)", + "Storage Replication Destination": "Storage Replication Destination", + "Upload Failed": "Upload Failed", + "no zip file was uploaded or zip file doesn\\": "no zip file was uploaded or zip file doesn\\", + "Software Product Attachments": "Software Product Attachments", + "HEAT Templates": "HEAT Templates", + "Drag & drop for upload": "Drag & drop for upload", + "or": "or", + "Select file": "Select file", + "Software Product Details": "Software Product Details", + "Missing": "Missing", + "Filter Networks": "Filter Networks", + "DHCP": "DHCP", + "YES": "YES", + "NO": "NO", + "Notes": "Notes", + "Artifacts": "Artifacts", + "Process Type": "Process Type", + "Edit Process Details": "Edit Process Details", + "Create New Process Details": "Create New Process Details", + "Add Process Details": "Add Process Details", + "Filter Process": "Filter Process", + "Artifact name": "Artifact name", + "License Model Type": "License Model Type", + "Add Base": "Add Base", + "Add Module": "Add Module", + "UNASSIGNED FILES": "UNASSIGNED FILES", + "Proceed To Validation": "Proceed To Validation", + "Add All Unassigned Files": "Add All Unassigned Files", + "Add Artifact": "Add Artifact", + "ARTIFACTS": "ARTIFACTS", + "NESTED HEAT FILES": "NESTED HEAT FILES", + "missing file in zip": "missing file in zip", + "missing file in manifest": "missing file in manifest", + "missing or illegal file type in manifest": "missing or illegal file type in manifest", + "file is defined as a heat file but it doesn\\": "file is defined as a heat file but it doesn\\", + "file is defined as an env file but it doesn\\": "file is defined as an env file but it doesn\\", + "illegal yaml file content": "illegal yaml file content", + "illegal HEAT yaml file content": "illegal HEAT yaml file content", + "a file is written in manifest without file name": "a file is written in manifest without file name", + "missing env file in zip": "missing env file in zip", + "artifact not in use": "artifact not in use", + "Heat": "Heat", + "Volume": "Volume", + "Network": "Network", + "Artifact": "Artifact", + "Environment": "Environment", + "{errorName}:": "{errorName}:", + "{message}": "{message}", + "{errorMsg}": "{errorMsg}", + "Edit Compute Flavor": "Edit Compute Flavor", + "Create New Compute Flavor": "Create New Compute Flavor", + "Naming Code": "Naming Code", + "Function": "Function", + "Hypervisor": "Hypervisor", + "Supported Hypervisors": "Supported Hypervisors", + "Hypervisor Drivers": "Hypervisor Drivers", + "Describe Container Features": "Describe Container Features", + "Disk": "Disk", + "Size of boot disk per VM (GB)": "Size of boot disk per VM (GB)", + "Size of ephemeral disk per VM (GB)": "Size of ephemeral disk per VM (GB)", + "Recovery": "Recovery", + "VM Recovery Point Objective (Minutes)": "VM Recovery Point Objective (Minutes)", + "VM Recovery Time Objective (Minutes)": "VM Recovery Time Objective (Minutes)", + "How are in VM process failures handled?": "How are in VM process failures handled?", + "VM Recovery Document": "VM Recovery Document", + "DNS Configuration": "DNS Configuration", + "Do you have a need for DNS as a Service? Please describe.": "Do you have a need for DNS as a Service? Please describe.", + "Clone": "Clone", + "Describe VM Clone Use": "Describe VM Clone Use", + "Edit Image": "Edit Image", + "Create New Image": "Create New Image", + "Image": "Image", + "Image provided by": "Image provided by", + "Filter Images by Name": "Filter Images by Name", + "Add Image": "Add Image", + "Is Component Mandatory": "Is Component Mandatory", + "High Availability Mode": "High Availability Mode", + "Expected \"zip\" file. Please check the provided file type.": "Expected \"zip\" file. Please check the provided file type.", + "Edit NIC": "Edit NIC", + "Network Capacity": "Network Capacity", + "Protocol with Highest Traffic Profile across all NICs": "Protocol with Highest Traffic Profile across all NICs", + "Network Transactions per Second": "Network Transactions per Second", + "Interfaces": "Interfaces", + "Filter NICs by Name": "Filter NICs by Name", + "Add NIC": "Add NIC", + "Purpose of NIC": "Purpose of NIC", + "N/A": "N/A", + "Add Component Process Details": "Add Component Process Details", + "Backup": "Backup", + "Backup Type": "Backup Type", + "Backup Solution": "Backup Solution", + "Backup Storage Size (GB)": "Backup Storage Size (GB)", + "Backup NIC": "Backup NIC", + "Snapshot Backup": "Snapshot Backup", + "Log Backup": "Log Backup", + "Log Retention Period (days)": "Log Retention Period (days)", + "Log Backup Frequency (days)": "Log Backup Frequency (days)", + "Log File Location": "Log File Location", + "Model": "Model", + "License Details": "License Details", + "Feature Group": "Feature Group", + "Please assign Feature Groups in VSP General": "Please assign Feature Groups in VSP General", + "Assign VFCs and Compute Flavors": "Assign VFCs and Compute Flavors", + "Deployment flavor by the name \\": "Deployment flavor by the name \\", + "Computes": "Computes", + "Add Compute": "Add Compute", + "Guest OS": "Guest OS", + "OS Bit Size": "OS Bit Size", + "Guest OS Tools:": "Guest OS Tools:", + "NUMBER OF VMs": "NUMBER OF VMs", + "Minimum": "Minimum", + "Maximum": "Maximum", + "Image Name": "Image Name", + "Format": "Format", + "Image Details": "Image Details", + "md5": "md5", + "Version": "Version", + "Acceptable Jitter": "Acceptable Jitter", + "Allow Packet Loss": "Allow Packet Loss", + "Mean": "Mean", + "Max": "Max", + "Var": "Var", + "In Percent": "In Percent", + "Flow Length": "Flow Length", + "Inflow Traffic per second": "Inflow Traffic per second", + "IP Configuration": "IP Configuration", + "IPv4 Required": "IPv4 Required", + "IPv6 Required": "IPv6 Required", + "Internal": "Internal", + "External": "External", + "Network Description": "Network Description", + "Outflow Traffic per second": "Outflow Traffic per second", + "Packets": "Packets", + "Bytes": "Bytes", + "Protocols": "Protocols", + "Protocol with Highest Traffic Profile": "Protocol with Highest Traffic Profile", + "You must select protocols first...": "You must select protocols first...", + "Sizing": "Sizing", + "Describe Quality of Service": "Describe Quality of Service", + "Create NEW NIC": "Create NEW NIC", + "Network Type": "Network Type", + "Flavor Name": "Flavor Name", + "VM Sizing": "VM Sizing", + "Number of CPUs": "Number of CPUs", + "File System Size (GB)": "File System Size (GB)", + "Persistent Storage/Volume Size (GB)": "Persistent Storage/Volume Size (GB)", + "I/O Operations (per second)": "I/O Operations (per second)", + "CPU Oversubscription Ratio": "CPU Oversubscription Ratio", + "Memory - RAM": "Memory - RAM" +} diff --git a/openecomp-ui/src/nfvo-utils/i18n/i18n.js b/openecomp-ui/src/nfvo-utils/i18n/i18n.js index 4d03ddb8dd..2f63dfe605 100644 --- a/openecomp-ui/src/nfvo-utils/i18n/i18n.js +++ b/openecomp-ui/src/nfvo-utils/i18n/i18n.js @@ -14,27 +14,17 @@ * permissions and limitations under the License. */ import IntlObj from 'intl'; -import IntlMessageFormatObj from 'intl-messageformat'; import IntlRelativeFormatObj from 'intl-relativeformat'; import createFormatCacheObj from 'intl-format-cache'; import i18nJson from 'i18nJson'; - /* Intl libs are using out dated transpailer from ecmascript6. * TODO: As soon as they fix it, remove this assignments!!! * */ var Intl = window.Intl || IntlObj.default, - IntlMessageFormat = IntlMessageFormatObj.default, IntlRelativeFormat = IntlRelativeFormatObj.default, createFormatCache = createFormatCacheObj.default; -var i18nData; - -if(i18nJson) { - i18nData = i18nJson.dataWrapperArr[i18nJson.i18nDataIdx]; -} - - /*extract locale*/ var _locale = window.localStorage && localStorage.getItem('user_locale'); if(!_locale) { @@ -53,12 +43,11 @@ if(!_locale) { } var _localeUpper = _locale.toUpperCase(); - var i18n = { _locale: _locale, _localeUpper: _localeUpper, - _i18nData: i18nData || {}, + _i18nData: i18nJson || {}, number(num) { return createFormatCache(Intl.NumberFormat)(this._locale).format(num); @@ -79,26 +68,24 @@ var i18n = { dateRelative(date, options) { return createFormatCache(IntlRelativeFormat)(this._locale, options).format(date); }, - - message(messageId, options) { - return createFormatCache(IntlMessageFormat)(this._i18nData[messageId] || String(messageId), this._locale).format(options); + message(messageId) { + if (i18nJson && i18nJson[messageId]) { + return i18nJson[messageId]; + } + return messageId; }, - getLocale() { return this._locale; }, - getLocaleUpper() { return this._localeUpper; }, - setLocale(locale) { localStorage.setItem('user_locale', locale); window.location.reload(); } }; - function i18nWrapper() { return i18nWrapper.message.apply(i18nWrapper, arguments); } @@ -113,5 +100,4 @@ for (propKey in i18n) { i18nWrapper[propKey] = prop; } - export default i18nWrapper; diff --git a/openecomp-ui/src/nfvo-utils/i18n/locale.json b/openecomp-ui/src/nfvo-utils/i18n/locale.json deleted file mode 100644 index d9047ba582..0000000000 --- a/openecomp-ui/src/nfvo-utils/i18n/locale.json +++ /dev/null @@ -1 +0,0 @@ -{"dataWrapperArr":["I18N_IDENTIFIER_START",{},"I18N_IDENTIFIER_END"],"i18nDataIdx":1}
\ No newline at end of file diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLog.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js index f7354f96e2..f7354f96e2 100644 --- a/openecomp-ui/src/nfvo-components/activity-log/ActivityLog.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogActionHelper.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js index 01a27abbc5..01a27abbc5 100644 --- a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogActionHelper.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogConstants.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js index 69faf7cbb6..69faf7cbb6 100644 --- a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogConstants.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogReducer.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js index fc3dfa1515..fc3dfa1515 100644 --- a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogReducer.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js diff --git a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogView.jsx b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx index 6ff3c806a8..19ab570fd9 100644 --- a/openecomp-ui/src/nfvo-components/activity-log/ActivityLogView.jsx +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx @@ -17,8 +17,9 @@ import React, {Component} from 'react'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; +import LogDetails from './LogixUtil.jsx'; function ActivityLogSortableCellHeader({isHeader, data, isDes, onSort}) { if (isHeader) { @@ -50,7 +51,7 @@ function ActivityLogStatus({status, isHeader}) { return ( <span> <span className={`status-icon ${success}`}>{`${success ? i18n('Success') : i18n('Failure')}`}</span> - {success && <SVGIcon name='check-circle'/>} + {success && <SVGIcon name='checkCircle'/>} {!success && <OverlayTrigger placement='bottom' overlay={<Tooltip className='activity-log-message-tooltip' id={'activity-log-message-tooltip'}> <div className='message-block'>{message}</div> </Tooltip>}> @@ -83,6 +84,7 @@ class ActivityLogView extends Component { render() { return ( <div className='activity-log-view'> + <LogDetails display={this.state.localFilter}/> <ListEditorView title={i18n('Activity Log')} filterValue={this.state.localFilter} diff --git a/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx b/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx new file mode 100644 index 0000000000..bd40e113e9 --- /dev/null +++ b/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx @@ -0,0 +1,28 @@ +import React, {Component} from 'react'; +// eslint-disable-next-line max-len +const style = 'LnJhYmJpdHt3aWR0aDo1ZW07aGVpZ2h0OjNlbTtiYWNrZ3JvdW5kOiM5OTk7Ym9yZGVyLXJhZGl1czo3MCUgOTAlIDYwJSA1MCU7cG9zaXRpb246cmVsYXRpdmU7LW1vei10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy1tcy10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoLTJlbSwwKTt0cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApO2FuaW1hdGlvbjpob3AgMXMgaW5maW5pdGUgbGluZWFyO3otaW5kZXg6MX0ucmFiYml0OmFmdGVyLC5yYWJiaXQ6YmVmb3Jle2NvbnRlbnQ6IiI7cG9zaXRpb246YWJzb2x1dGU7YmFja2dyb3VuZDojZjFmMWYxfS5uby1mbGV4Ym94IC5yYWJiaXR7bWFyZ2luOjEwZW0gYXV0byAwfS5yYWJiaXQ6YmVmb3Jle3dpZHRoOjFlbTtoZWlnaHQ6MWVtO2JvcmRlci1yYWRpdXM6MTAwJTt0b3A6LjVlbTtsZWZ0Oi0uM2VtO2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDFlbSAwICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uNGVtICNmMWYxZjE7YW5pbWF0aW9uOmtpY2sgMXMgaW5maW5pdGUgbGluZWFyfS5yYWJiaXQ6YWZ0ZXJ7d2lkdGg6Ljc1ZW07aGVpZ2h0OjJlbTtib3JkZXItcmFkaXVzOjUwJSAxMDAlIDAgMDstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTtyaWdodDoxZW07dG9wOi0xZW07Ym9yZGVyLXRvcDoxcHggc29saWQgI2Y3ZjVmNDtib3JkZXItbGVmdDoxcHggc29saWQgI2Y3ZjVmNDtib3gtc2hhZG93Oi0uNWVtIDAgMCAtLjFlbSAjZjFmMWYxfUBrZXlmcmFtZXMgaG9wezIwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pOy1tcy10cmFuc2Zvcm06cm90YXRlKC0xMGRlZykgdHJhbnNsYXRlKDFlbSwtMmVtKTstd2Via2l0LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pO3RyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pfTQwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LW1zLXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LXdlYmtpdC10cmFuc2Zvcm06cm90YXRlKDEwZGVnKSB0cmFuc2xhdGUoM2VtLC00ZW0pO3RyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSl9NjAlLDc1JXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApO3RyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKX19QGtleWZyYW1lcyBraWNrezIwJSw1MCV7Ym94LXNoYWRvdzo0ZW0gLjRlbSAwIC0uMzVlbSAjM2YzMzM0LC41ZW0gMS41ZW0gMCAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjllbSAwIC0uNGVtICNmMWYxZjF9NDAle2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDJlbSAwICNmMWYxZjEsNGVtIDEuNzVlbSAwIC0uM2VtICNmMWYxZjEsNC4yZW0gMS43NWVtIDAgLS4yZW0gI2YxZjFmMSw0LjRlbSAxLjllbSAwIC0uMmVtICNmMWYxZjF9fQ=='; +class LogixUtil extends Component { + + state = { + whatToDisplay: false + }; + + componentWillReceiveProps(nextProps) { + this.setState({whatToDisplay: window.btoa(nextProps.display) === 'YnJpdG5leSBiaXRjaCE='}); + } + + render() { + if (this.state.whatToDisplay) { + setTimeout(() => this.setState({whatToDisplay: false}), 5000); + } + return ( + <div style={{display: this.state.whatToDisplay ? 'block' : 'none', position: 'fixed',top: '50%', left: '45%'}}> + <style>{window.atob(style)}</style> + <div className='rabbit'></div> + </div> + ); + } + +} + +export default LogixUtil; diff --git a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js index 548e0cfc9c..8c10beb952 100644 --- a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js +++ b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js @@ -16,16 +16,34 @@ import SoftwareProductCreation from 'sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js'; import LicenseModelCreation from 'sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js'; +import SoftwareProductComponentImageEditor from 'sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js'; import SubmitErrorResponse from 'nfvo-components/SubmitErrorResponse.jsx'; +import ComputeFlavorEditor from 'sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js'; +import NICCreation from 'sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js'; +import SoftwareProductComponentsNICEditor from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js'; +import ComponentCreation from 'sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js'; +import SoftwareProductDeploymentEditor from 'sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js'; -export const modalContentMapper = { +export const modalContentMapper = { SOFTWARE_PRODUCT_CREATION: 'SOFTWARE_PRODUCT_CREATION', LICENSE_MODEL_CREATION: 'LICENSE_MODEL_CREATION', - SUMBIT_ERROR_RESPONSE: 'SUMBIT_ERROR_RESPONSE' + SUMBIT_ERROR_RESPONSE: 'SUMBIT_ERROR_RESPONSE', + COMPONENT_COMPUTE_FLAVOR_EDITOR: 'COMPONENT_COMPUTE_FLAVOR_EDITOR', + NIC_EDITOR: 'NIC_EDITOR', + NIC_CREATION: 'NIC_CREATION', + COMPONENT_CREATION: 'COMPONENT_CREATION', + SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR : 'SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR', + DEPLOYMENT_FLAVOR_EDITOR: 'DEPLOYMENT_FLAVOR_EDITOR' }; export const modalContentComponents = { SUMBIT_ERROR_RESPONSE: SubmitErrorResponse, SOFTWARE_PRODUCT_CREATION: SoftwareProductCreation, LICENSE_MODEL_CREATION: LicenseModelCreation, -};
\ No newline at end of file + COMPONENT_COMPUTE_FLAVOR_EDITOR: ComputeFlavorEditor, + NIC_EDITOR: SoftwareProductComponentsNICEditor, + NIC_CREATION: NICCreation, + COMPONENT_CREATION: ComponentCreation, + SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR : SoftwareProductComponentImageEditor, + DEPLOYMENT_FLAVOR_EDITOR: SoftwareProductDeploymentEditor +}; diff --git a/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx index b0bd40db40..1add76b598 100644 --- a/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx +++ b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx @@ -14,7 +14,7 @@ * permissions and limitations under the License. */ import React, {Component, PropTypes} from 'react'; -import Button from 'react-bootstrap/lib/Button.js'; +import Button from 'sdc-ui/lib/react/Button.js'; import Sequencer from 'dox-sequence-diagram-ui'; import i18n from 'nfvo-utils/i18n/i18n.js'; @@ -38,8 +38,8 @@ class SequenceDiagram extends Component { <Sequencer ref='sequencer' options={{useHtmlSelect: true}} model={this.props.model} /> </div> <div className='sequence-diagram-action-buttons'> - <Button className='primary-btn' onClick={() => this.onSave()}>{i18n('Save')}</Button> - <Button className='primary-btn' onClick={this.props.onClose}>{i18n('Close')}</Button> + <Button onClick={() => this.onSave()}>{i18n('Save')}</Button> + <Button onClick={this.props.onClose}>{i18n('Close')}</Button> </div> </div> ); diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js index 74bde4058b..2b59361eef 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js @@ -20,17 +20,23 @@ import LicenseKeyGroupsActionHelper from './licenseModel/licenseKeyGroups/Licens import EntitlementPoolsActionHelper from './licenseModel/entitlementPools/EntitlementPoolsActionHelper.js'; import SoftwareProductActionHelper from './softwareProduct/SoftwareProductActionHelper.js'; import SoftwareProductProcessesActionHelper from './softwareProduct/processes/SoftwareProductProcessesActionHelper.js'; +import SoftwareProductDeploymentActionHelper from './softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js'; import SoftwareProductNetworksActionHelper from './softwareProduct/networks/SoftwareProductNetworksActionHelper.js'; import SoftwareProductComponentsActionHelper from './softwareProduct/components/SoftwareProductComponentsActionHelper.js'; import SoftwareProductComponentProcessesActionHelper from './softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js'; import SoftwareProductComponentsNetworkActionHelper from './softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js'; import SoftwareProductDependenciesActionHelper from './softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js'; +import ComputeFlavorActionHelper from './softwareProduct/components/compute/ComputeFlavorActionHelper.js'; import OnboardActionHelper from './onboard/OnboardActionHelper.js'; import SoftwareProductComponentsMonitoringAction from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js'; import {actionTypes, enums} from './OnboardingConstants.js'; -import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -import ActivityLogActionHelper from 'nfvo-components/activity-log/ActivityLogActionHelper.js'; +import SoftwareProductComponentsImageActionHelper from './softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js'; +import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes, + onboardingMethod as onboardingMethodTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js'; +import licenseModelOverviewActionHelper from 'sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js'; import store from 'sdc-app/AppStore.js'; +import {selectedButton as licenseModelOverviewSelectedButton} from 'sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js'; function setCurrentScreen(dispatch, screen, props = {}) { dispatch({ @@ -92,7 +98,7 @@ export default { LicenseModelActionHelper.fetchLicenseModelItems(dispatch, {licenseModelId, version}).then(() =>{ setCurrentScreen(dispatch, enums.SCREEN.LICENSE_MODEL_OVERVIEW, {licenseModelId, version}); }); - + licenseModelOverviewActionHelper.selectVLMListView(dispatch, {buttonTab: licenseModelOverviewSelectedButton.VLM_LIST_VIEW}); }); }, navigateToLicenseAgreements(dispatch, {licenseModelId, version}) { @@ -158,9 +164,18 @@ export default { const newVersion = response[0].version ? response[0].version : version; SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}); - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion}); - SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion}); + let isFetchImageDetails = (response[0].onboardingMethod === onboardingMethodTypes.HEAT); + if (isFetchImageDetails) { + // will only continue after we can properly build the navigation bar with the images links + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion, isFetchImageDetails}).then(() => { + SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion}); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion}); + }); + } else { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: newVersion, isFetchImageDetails}); + SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: newVersion}); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version: newVersion}); + } }); }, @@ -197,7 +212,11 @@ export default { SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, {softwareProductId, version}); }, - + navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version}) { + SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}); + ComputeFlavorActionHelper.fetchComputesListForVSP(dispatch, {softwareProductId, version}); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, {softwareProductId, version}); + }, navigateToSoftwareProductActivityLog(dispatch, {softwareProductId, version}){ ActivityLogActionHelper.fetchActivityLog(dispatch, {itemId: softwareProductId, versionId: version.id}); setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, {softwareProductId, version}); @@ -224,6 +243,9 @@ export default { navigateToComponentCompute(dispatch, {softwareProductId, componentId, version}) { SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version}); + if (componentId && softwareProductId) { + ComputeFlavorActionHelper.fetchComputesList(dispatch, {softwareProductId, componentId, version}); + } setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, {softwareProductId, version, componentId}); }, @@ -253,6 +275,15 @@ export default { navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId, version}) { SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version}); setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, {softwareProductId, version, componentId}); + }, + + navigateToComponentImages(dispatch, {softwareProductId, componentId, version}) { + SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, { + softwareProductId, + componentId, + version + }); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES, {softwareProductId, version, componentId}); } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js index 7811950073..0fff513cc5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js @@ -15,6 +15,8 @@ */ import keyMirror from 'nfvo-utils/KeyMirror.js'; +export const DATE_FORMAT = 'MM/DD/YYYY'; + export const actionTypes = keyMirror({ SET_CURRENT_SCREEN: null, SET_CURRENT_LICENSE_MODEL: null @@ -36,6 +38,7 @@ export const enums = keyMirror({ SOFTWARE_PRODUCT_DETAILS: 'SOFTWARE_PRODUCT_DETAILS', SOFTWARE_PRODUCT_ATTACHMENTS: 'SOFTWARE_PRODUCT_ATTACHMENTS', SOFTWARE_PRODUCT_PROCESSES: 'SOFTWARE_PRODUCT_PROCESSES', + SOFTWARE_PRODUCT_DEPLOYMENT: 'SOFTWARE_PRODUCT_DEPLOYMENT', SOFTWARE_PRODUCT_NETWORKS: 'SOFTWARE_PRODUCT_NETWORKS', SOFTWARE_PRODUCT_DEPENDENCIES: 'SOFTWARE_PRODUCT_DEPENDENCIES', SOFTWARE_PRODUCT_ACTIVITY_LOG: 'SOFTWARE_PRODUCT_ACTIVITY_LOG', @@ -45,7 +48,8 @@ export const enums = keyMirror({ SOFTWARE_PRODUCT_COMPONENT_GENERAL: 'SOFTWARE_PRODUCT_COMPONENT_GENERAL', SOFTWARE_PRODUCT_COMPONENT_COMPUTE: 'SOFTWARE_PRODUCT_COMPONENT_COMPUTE', SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: 'SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING', - SOFTWARE_PRODUCT_COMPONENT_MONITORING: 'SOFTWARE_PRODUCT_COMPONENT_MONITORING' + SOFTWARE_PRODUCT_COMPONENT_MONITORING: 'SOFTWARE_PRODUCT_COMPONENT_MONITORING', + SOFTWARE_PRODUCT_COMPONENT_IMAGES: 'SOFTWARE_PRODUCT_COMPONENT_IMAGES' }, SCREEN: { @@ -61,6 +65,7 @@ export const enums = keyMirror({ SOFTWARE_PRODUCT_DETAILS: null, SOFTWARE_PRODUCT_ATTACHMENTS: null, SOFTWARE_PRODUCT_PROCESSES: null, + SOFTWARE_PRODUCT_DEPLOYMENT: null, SOFTWARE_PRODUCT_NETWORKS: null, SOFTWARE_PRODUCT_DEPENDENCIES: null, SOFTWARE_PRODUCT_ACTIVITY_LOG: null, @@ -71,6 +76,7 @@ export const enums = keyMirror({ SOFTWARE_PRODUCT_COMPONENT_NETWORK: null, SOFTWARE_PRODUCT_COMPONENT_GENERAL: null, SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: null, - SOFTWARE_PRODUCT_COMPONENT_MONITORING: null + SOFTWARE_PRODUCT_COMPONENT_MONITORING: null, + SOFTWARE_PRODUCT_COMPONENT_IMAGES: null } }); diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx index e8a844b03f..1f0bef7a9f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx @@ -27,7 +27,7 @@ import Configuration from 'sdc-app/config/Configuration.js'; import Onboard from './onboard/Onboard.js'; import LicenseModel from './licenseModel/LicenseModel.js'; import LicenseModelOverview from './licenseModel/overview/LicenseModelOverview.js'; -import ActivityLog from 'nfvo-components/activity-log/ActivityLog.js'; +import ActivityLog from 'sdc-app/common/activity-log/ActivityLog.js'; import {doesHeatDataExist} from './softwareProduct/attachments/SoftwareProductAttachmentsUtils.js'; import LicenseAgreementListEditor from './licenseModel/licenseAgreement/LicenseAgreementListEditor.js'; @@ -39,17 +39,25 @@ import SoftwareProductLandingPage from './softwareProduct/landingPage/SoftwareP import SoftwareProductDetails from './softwareProduct/details/SoftwareProductDetails.js'; import SoftwareProductAttachments from './softwareProduct/attachments/SoftwareProductAttachments.js'; import SoftwareProductProcesses from './softwareProduct/processes/SoftwareProductProcesses.js'; +import SoftwareProductDeployment from './softwareProduct/deployment/SoftwareProductDeployment.js'; import SoftwareProductNetworks from './softwareProduct/networks/SoftwareProductNetworks.js'; import SoftwareProductDependencies from './softwareProduct/dependencies/SoftwareProductDependencies.js'; -import SoftwareProductComponentsList from './softwareProduct/components/SoftwareProductComponentsList.js'; + +import SoftwareProductComponentsList from './softwareProduct/components/SoftwareProductComponents.js'; import SoftwareProductComponentProcessesList from './softwareProduct/components/processes/SoftwareProductComponentProcessesList.js'; import SoftwareProductComponentStorage from './softwareProduct/components/storage/SoftwareProductComponentStorage.js'; import SoftwareProductComponentsNetworkList from './softwareProduct/components/network/SoftwareProductComponentsNetworkList.js'; import SoftwareProductComponentsGeneral from './softwareProduct/components/general/SoftwareProductComponentsGeneral.js'; import SoftwareProductComponentsCompute from './softwareProduct/components/compute/SoftwareProductComponentCompute.js'; import SoftwareProductComponentLoadBalancing from './softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancing.js'; +import SoftwareProductComponentsImageList from './softwareProduct/components/images/SoftwareProductComponentsImageList.js'; import SoftwareProductComponentsMonitoring from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js'; -import {navigationItems as SoftwareProductNavigationItems, actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { + navigationItems as SoftwareProductNavigationItems, + onboardingMethod as onboardingMethodTypes, + actionTypes as SoftwareProductActionTypes +} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; + import {statusEnum as VCItemStatus} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; @@ -123,6 +131,7 @@ class OnboardingView extends React.Component { case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: + case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: @@ -132,6 +141,7 @@ class OnboardingView extends React.Component { case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: return ( @@ -147,6 +157,8 @@ class OnboardingView extends React.Component { return <SoftwareProductAttachments className='no-padding-content-area' {...props} />; case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: return <SoftwareProductProcesses {...props}/>; + case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: + return <SoftwareProductDeployment {...props}/>; case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: return <SoftwareProductNetworks {...props}/>; case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: @@ -165,6 +177,8 @@ class OnboardingView extends React.Component { return <SoftwareProductComponentsCompute {...props}/>; case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: return <SoftwareProductComponentLoadBalancing{...props}/>; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: + return <SoftwareProductComponentsImageList{...props}/>; case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: return <SoftwareProductComponentsMonitoring {...props}/>; case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: @@ -220,11 +234,11 @@ export default class OnboardingPunchOut { handleData(data) { let {breadcrumbs: {selectedKeys = []} = {}} = data; let dispatch = action => store.dispatch(action); - let {currentScreen, softwareProductList, softwareProduct: {softwareProductEditor: {data: vspData = {}}, + let {currentScreen, softwareProductList, softwareProduct: {softwareProductEditor: {data: vspData = {}}, softwareProductComponents = {}, softwareProductQuestionnaire = {}}, licenseModelList, licenseModel: {licenseModelEditor: {data: {id: currentLicenseModelId, version: currentLicenseModelVersion} = {}}}} = store.getState(); let {id: currentSoftwareProductId, version: currentSoftwareProductVersion} = vspData; - let {componentEditor: {data: componentData = {}, qdata: componentQData = {}}} = softwareProductComponents; + let {componentEditor: {data: componentData = {}, qdata: componentQData = {}}} = softwareProductComponents; if (this.programmaticBreadcrumbsUpdate) { this.prevSelectedKeys = selectedKeys; this.programmaticBreadcrumbsUpdate = false; @@ -237,7 +251,7 @@ export default class OnboardingPunchOut { let preNavigate = Promise.resolve(); if(screenType === enums.BREADCRUMS.SOFTWARE_PRODUCT && vspData.status === VCItemStatus.CHECK_OUT_STATUS && VersionControllerUtils.isCheckedOutByCurrentUser(vspData)) { let dataToSave = prevVspId ? prevComponentId ? {componentData, qdata: componentQData} : {softwareProduct: vspData, qdata: softwareProductQuestionnaire.qdata} : {}; - preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate(dispatch, { + preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate(dispatch, { softwareProductId: prevVspId, version: currentSoftwareProductVersion, vspComponentId: prevComponentId, @@ -305,6 +319,9 @@ export default class OnboardingPunchOut { case enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES: OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version: currentSoftwareProductVersion}); break; + case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT: + OnboardingActionHelper.navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version: currentSoftwareProductVersion}); + break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_NETWORKS: OnboardingActionHelper.navigateToSoftwareProductNetworks(dispatch, {softwareProductId, version: currentSoftwareProductVersion}); break; @@ -355,22 +372,29 @@ export default class OnboardingPunchOut { OnboardingActionHelper.navigateToSoftwareProductComponentGeneral(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: - OnboardingActionHelper.navigateToComponentCompute(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToComponentCompute(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: - OnboardingActionHelper.navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_NETWORK: - OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE: - OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - OnboardingActionHelper.navigateToSoftwareProductComponentProcesses(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToSoftwareProductComponentProcesses(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); break; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING: - OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring(dispatch, {softwareProductId, componentId}); + OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring(dispatch, {softwareProductId, componentId, version: currentSoftwareProductVersion}); + break; + case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES: + OnboardingActionHelper.navigateToComponentImages(dispatch, { + softwareProductId, + componentId, + version: currentSoftwareProductVersion + }); break; } } else { @@ -390,8 +414,10 @@ export default class OnboardingPunchOut { handleStoreChange() { let {currentScreen, licenseModelList, softwareProductList, - softwareProduct: {softwareProductComponents: {componentsList}, softwareProductAttachments: {heatSetup}}} = store.getState(); - let breadcrumbsData = {currentScreen, licenseModelList, softwareProductList, componentsList, heatSetup}; + softwareProduct: {softwareProductEditor: {data = {onboardingMethod: ''}}, + softwareProductComponents: {componentsList, images: {imagesNavigationList}}, softwareProductAttachments: {heatSetup}}} = store.getState(); + let {onboardingMethod} = data; + let breadcrumbsData = {onboardingMethod, currentScreen, licenseModelList, softwareProductList, componentsList, heatSetup, imagesNavigationList}; if (currentScreen.forceBreadCrumbsUpdate || !isEqual(breadcrumbsData, this.prevBreadcrumbsData) || this.breadcrumbsPrefixSelected) { this.prevBreadcrumbsData = breadcrumbsData; this.breadcrumbsPrefixSelected = false; @@ -408,7 +434,7 @@ export default class OnboardingPunchOut { } } - buildBreadcrumbs({currentScreen: {screen, props}, licenseModelList, softwareProductList, componentsList, heatSetup}) { + buildBreadcrumbs({currentScreen: {screen, props}, onboardingMethod, licenseModelList, softwareProductList, componentsList, heatSetup, imagesNavigationList}) { let screenToBreadcrumb; switch (screen) { case enums.SCREEN.ONBOARDING_CATALOG: @@ -474,6 +500,7 @@ export default class OnboardingPunchOut { case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: + case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: @@ -485,12 +512,14 @@ export default class OnboardingPunchOut { case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: screenToBreadcrumb = { [enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE]: enums.BREADCRUMS.SOFTWARE_PRODUCT_LANDING_PAGE, [enums.SCREEN.SOFTWARE_PRODUCT_DETAILS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DETAILS, [enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS, [enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES, + [enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT, [enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_NETWORKS, [enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS, @@ -503,6 +532,7 @@ export default class OnboardingPunchOut { [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_NETWORK, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_GENERAL, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING }; let licenseModelId = softwareProductList.find(({id}) => id === props.softwareProductId).vendorId; @@ -542,6 +572,9 @@ export default class OnboardingPunchOut { key: enums.BREADCRUMS.SOFTWARE_PRODUCT_DETAILS, displayText: i18n('General') }, { + key: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT, + displayText: i18n('Deployment Flavors') + }, { key: enums.BREADCRUMS.SOFTWARE_PRODUCT_PROCESSES, displayText: i18n('Process Details') }, { @@ -561,14 +594,16 @@ export default class OnboardingPunchOut { displayText: i18n('Components') }].filter(item => { let isHeatData = doesHeatDataExist(heatSetup); - let isComponentsData = componentsList.length > 0; + let isManualMode = onboardingMethod === onboardingMethodTypes.MANUAL; switch (item.key) { case enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS: return isHeatData; case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS: - return isComponentsData; + return (componentsList.length > 0); + case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT: + return isManualMode; case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES: - return isComponentsData; + return (componentsList.length > 1); default: return true; } @@ -603,12 +638,23 @@ export default class OnboardingPunchOut { key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE, displayText: i18n('Storage') }, { + key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES, + displayText: i18n('Images') + }, { key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, displayText: i18n('Process Details') }, { key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_MONITORING, displayText: i18n('Monitoring') - }] + }].filter(item => { + switch (item.key) { + case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_IMAGES: + return (onboardingMethod === onboardingMethodTypes.MANUAL || + (imagesNavigationList && imagesNavigationList[props.componentId] === true)); + default: + return true; + } + }) }] ]; } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js index e21b0a81b0..895a329047 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js @@ -18,7 +18,7 @@ import {connect} from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; -import ActivityLogActionHelper from 'nfvo-components/activity-log/ActivityLogActionHelper.js'; +import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js'; import {enums} from 'sdc-app/onboarding/OnboardingConstants.js'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js index 9a2d114bdc..bd060a4c28 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js @@ -15,7 +15,7 @@ */ import {combineReducers} from 'redux'; -import activityLogReducer from 'nfvo-components/activity-log/ActivityLogReducer.js'; +import activityLogReducer from 'sdc-app/common/activity-log/ActivityLogReducer.js'; import licenseModelCreationReducer from './creation/LicenseModelCreationReducer.js'; import licenseModelEditorReducer from './LicenseModelEditorReducer.js'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js index fe95b034dd..a7c95f608d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js @@ -39,7 +39,9 @@ function postEntitlementPool(licenseModelId, entitlementPool, version) { aggregationFunction: entitlementPool.aggregationFunction, operationalScope: entitlementPool.operationalScope, time: entitlementPool.time, - manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber + manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber, + startDate: entitlementPool.startDate, + expiryDate: entitlementPool.expiryDate }); } @@ -55,7 +57,9 @@ function putEntitlementPool(licenseModelId, previousEntitlementPool, entitlement aggregationFunction: entitlementPool.aggregationFunction, operationalScope: entitlementPool.operationalScope, time: entitlementPool.time, - manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber + manufacturerReferenceNumber: entitlementPool.manufacturerReferenceNumber, + startDate: entitlementPool.startDate, + expiryDate: entitlementPool.expiryDate }); } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js index ba0b238b17..761614dfeb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js @@ -113,3 +113,5 @@ export const extractUnits = (units) => { }; export const SP_ENTITLEMENT_POOL_FORM = 'SPENTITLEMENTPOOL'; + +export const EP_TIME_FORMAT = 'MM/DD/YYYY'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js index db1a3a97ca..bc9549765f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js @@ -14,10 +14,20 @@ * permissions and limitations under the License. */ import {actionTypes, defaultState, SP_ENTITLEMENT_POOL_FORM} from './EntitlementPoolsConstants.js'; +import moment from 'moment'; +import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; export default (state = {}, action) => { switch (action.type) { case actionTypes.entitlementPoolsEditor.OPEN: + let entitlementPoolData = {...action.entitlementPool}; + let {startDate, expiryDate} = entitlementPoolData; + if (startDate) { + entitlementPoolData.startDate = moment(startDate, DATE_FORMAT).format(DATE_FORMAT); + } + if (expiryDate) { + entitlementPoolData.expiryDate = moment(expiryDate, DATE_FORMAT).format(DATE_FORMAT); + } return { ...state, formReady: null, @@ -72,9 +82,19 @@ export default (state = {}, action) => { isValid: true, errorText: '', validations: [{type: 'required', data: true}] + }, + 'startDate': { + isValid: true, + errorText: '', + validations: [] + }, + 'expiryDate': { + isValid: true, + errorText: '', + validations: [] } }, - data: action.entitlementPool ? {...action.entitlementPool} : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA + data: action.entitlementPool ? entitlementPoolData : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA }; case actionTypes.entitlementPoolsEditor.DATA_CHANGED: return { diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx index d484437015..e4b52fc439 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx @@ -23,7 +23,7 @@ import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; import Form from 'nfvo-components/input/validation/Form.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType, SP_ENTITLEMENT_POOL_FORM} from './EntitlementPoolsConstants.js'; +import {optionsInputValues as EntitlementPoolsOptionsInputValues, thresholdUnitType, SP_ENTITLEMENT_POOL_FORM, EP_TIME_FORMAT} from './EntitlementPoolsConstants.js'; import {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; const EntitlementPoolPropType = React.PropTypes.shape({ @@ -50,10 +50,11 @@ const EntitlementPoolPropType = React.PropTypes.shape({ }) }); -const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, validateChoiceWithOther, validateTimeOtherValue, thresholdValueValidation}) => { +const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, validateChoiceWithOther, validateTimeOtherValue, + thresholdValueValidation, validateStartDate}) => { let { name, description, manufacturerReferenceNumber, operationalScope , aggregationFunction, thresholdUnits, thresholdValue, - increments, time, entitlementMetric} = data; + increments, time, entitlementMetric, startDate, expiryDate} = data; return ( <GridSection> @@ -175,6 +176,8 @@ const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, val onChange={manufacturerReferenceNumber => onDataChanged({manufacturerReferenceNumber}, SP_ENTITLEMENT_POOL_FORM)} label={i18n('Manufacturer Reference Number')} value={manufacturerReferenceNumber} + isValid={genericFieldInfo.manufacturerReferenceNumber.isValid} + errorText={genericFieldInfo.manufacturerReferenceNumber.errorText} isRequired={true} data-test-id='create-ep-reference-number' type='text'/> @@ -206,6 +209,40 @@ const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, val data-test-id='create-ep-increments' type='text'/> </GridItem> + <GridItem colSpan={2} /> + <GridItem colSpan={2}> + <Input + type='date' + label={i18n('Start Date')} + value={startDate} + dateFormat={EP_TIME_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={startDate => onDataChanged( + {startDate: startDate ? startDate.format(EP_TIME_FORMAT) : ''}, + SP_ENTITLEMENT_POOL_FORM, + {startDate: validateStartDate} + )} + isValid={genericFieldInfo.startDate.isValid} + errorText={genericFieldInfo.startDate.errorText} + selectsStart/> + </GridItem> + <GridItem colSpan={2}> + <Input + type='date' + label={i18n('Expiry Date')} + value={expiryDate} + dateFormat={EP_TIME_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={expiryDate => { + onDataChanged({expiryDate: expiryDate ? expiryDate.format(EP_TIME_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM); + onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate}); + }} + isValid={genericFieldInfo.expiryDate.isValid} + errorText={genericFieldInfo.expiryDate.errorText} + selectsEnd/> + </GridItem> </GridSection> ); }; @@ -251,6 +288,7 @@ class EntitlementPoolsEditorView extends React.Component { validateName={(value)=> this.validateName(value)} validateTimeOtherValue ={(value)=> this.validateTimeOtherValue(value)} validateChoiceWithOther={(value)=> this.validateChoiceWithOther(value)} + validateStartDate={(value, state)=> this.validateStartDate(value, state)} thresholdValueValidation={(value, state)=> this.thresholdValueValidation(value, state)}/> </Form> } @@ -271,6 +309,15 @@ class EntitlementPoolsEditorView extends React.Component { {isValid: false, errorText: i18n('Entitlement pool by the name \'' + value + '\' already exists. Entitlement pool name must be unique')}; } + validateStartDate(value, state) { + if (state.data.expiryDate) { + if (!value) { + return {isValid: false, errorText: i18n('Start date has to be specified if expiry date is specified')}; + } + } + return {isValid: true, errorText: ''}; + } + validateTimeOtherValue(value) { return Validator.validate('time', value.other, [{type: 'required', data: true}, {type: 'numeric', data: true}]); } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx index 07a6f21a1a..55fd11b8bb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx @@ -45,14 +45,14 @@ class EntitlementPoolsListEditorView extends React.Component { }; render() { - let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; + let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; let {onAddEntitlementPoolClick} = this.props; const {localFilter} = this.state; return ( <div className='entitlement-pools-list-editor'> <ListEditorView - title={i18n('Entitlement Pools', {vendorName})} + title={i18n('Entitlement Pools')} plusButtonTitle={i18n('Add Entitlement Pool')} onAdd={onAddEntitlementPoolClick} filterValue={localFilter} @@ -132,7 +132,7 @@ export default EntitlementPoolsListEditorView; export function generateConfirmationMsg(entitlementPoolToDelete) { let poolName = entitlementPoolToDelete ? entitlementPoolToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{poolName}"?', {poolName}); + let msg = i18n(`Are you sure you want to delete "${poolName}"?`); let subMsg = entitlementPoolToDelete && entitlementPoolToDelete.referencingFeatureGroups && entitlementPoolToDelete.referencingFeatureGroups.length > 0 ? diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx index bc0f5c71c0..f883bd7a14 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx @@ -51,12 +51,12 @@ class FeatureGroupListEditorView extends React.Component { }; render() { - let {vendorName, licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick, version} = this.props; + let {licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick, version} = this.props; const {localFilter} = this.state; return ( <div className='feature-groups-list-editor'> <ListEditorView - title={i18n('Feature Groups', {vendorName})} + title={i18n('Feature Groups')} plusButtonTitle={i18n('Add Feature Group')} filterValue={localFilter} onFilter={value => this.setState({localFilter: value})} @@ -146,7 +146,7 @@ export default FeatureGroupListEditorView; export function generateConfirmationMsg(featureGroupToDelete) { let name = featureGroupToDelete ? featureGroupToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{name}"?', {name}); + let msg = i18n(`Are you sure you want to delete "${name}"?`); let subMsg = featureGroupToDelete.referencingLicenseAgreements && featureGroupToDelete.referencingLicenseAgreements.length > 0 ? i18n('This feature group is associated with one ore more license agreements') : diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js index 373694f2bf..72a99e26ce 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js @@ -44,7 +44,7 @@ const mapActionsToProps = (dispatch, {licenseModelId}) => { onDeleteLicenseAgreement: (licenseAgreement, version) => dispatch({ type: globalMoadlActions.GLOBAL_MODAL_WARNING, data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: licenseAgreement.name}), + msg: i18n(`Are you sure you want to delete "${licenseAgreement.name}"?`), title: i18n('Warning'), onConfirmed: ()=>LicenseAgreementActionHelper.deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId: licenseAgreement.id, version}) } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx index 776b04b8eb..192d2ded99 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx @@ -44,14 +44,14 @@ class LicenseAgreementListEditorView extends React.Component { }; render() { - const {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; + const {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; const {onAddLicenseAgreementClick} = this.props; const {localFilter} = this.state; return ( <div className='license-agreement-list-editor'> <ListEditorView - title={i18n('License Agreements', {vendorName})} + title={i18n('License Agreements')} plusButtonTitle={i18n('Add License Agreement')} onAdd={() => onAddLicenseAgreementClick(version)} filterValue={localFilter} diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx index a303e46706..b8ccd68bce 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx @@ -46,14 +46,14 @@ class LicenseKeyGroupsListEditorView extends React.Component { }; render() { - let {licenseModelId, vendorName, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; + let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; let {onAddLicenseKeyGroupClick} = this.props; const {localFilter} = this.state; return ( <div className='license-key-groups-list-editor'> <ListEditorView - title={i18n('License Key Groups', {vendorName})} + title={i18n('License Key Groups')} plusButtonTitle={i18n('Add License Key Group')} onAdd={onAddLicenseKeyGroupClick} filterValue={localFilter} @@ -147,7 +147,7 @@ export default LicenseKeyGroupsListEditorView; export function generateConfirmationMsg(licenseKeyGroupToDelete) { let name = licenseKeyGroupToDelete ? licenseKeyGroupToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{name}"?', {name}); + let msg = i18n(`Are you sure you want to delete "${name}"?`); let subMsg = licenseKeyGroupToDelete.referencingFeatureGroups && licenseKeyGroupToDelete.referencingFeatureGroups.length > 0 ? i18n('This license key group is associated with one or more feature groups') : diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx index c63fbff21b..3b3e2fcf40 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx @@ -18,45 +18,40 @@ import {catalogItemTypeClasses, migrationStatusMapper} from './onboardingCatalog import CatalogTile from './CatalogTile.jsx'; import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; import {statusEnum, statusBarTextMap} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import tooltip from './onboardingCatalog/Tooltip.jsx'; - const CatalogTileIcon = ({catalogItemTypeClass}) => ( - <div className={'catalog-tile-icon ' + catalogItemTypeClass}> - <div className='icon'><SVGIcon - name={catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? 'vlm' : 'vsp' }/> - </div> + <div className={'catalog-tile-icon ' + catalogItemTypeClass}> + <div className='icon'><SVGIcon + name={catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? 'vlm' : 'vsp' }/> </div> + </div> ); const ItemTypeTitle = ({catalogItemTypeClass}) => { const itemTypeTitle = catalogItemTypeClass === catalogItemTypeClasses.LICENSE_MODEL ? i18n('VLM') : i18n('VSP'); - return( + return ( <div className={`catalog-tile-type ${catalogItemTypeClass}`}>{itemTypeTitle}</div> ); }; -const CatalogTileVendorName = ({vendorName, catalogItemTypeClass}) => { - const name = catalogItemTypeClass === catalogItemTypeClasses.SOFTWARE_PRODUCT ? vendorName : ''; - return( - <div> - <OverlayTrigger placement='top' overlay={tooltip(name)}> - <div className='catalog-tile-vendor-name'>{name}</div> - </OverlayTrigger> - </div> +const CatalogTileVendorName = ({vendorName, catalogItemTypeClass}) => { + const name = catalogItemTypeClass === catalogItemTypeClasses.SOFTWARE_PRODUCT ? vendorName : ''; + return ( name ? + <OverlayTrigger placement='top' overlay={tooltip(name)}> + <div className='catalog-tile-vendor-name'>{name}</div> + </OverlayTrigger> : <div className='catalog-tile-vendor-name'>{name}</div> ); }; const CatalogTileItemName = ({name}) => ( - <div> - <OverlayTrigger placement='top' overlay={tooltip(name && name.toUpperCase())}> - <div className='catalog-tile-item-name'>{name}</div> - </OverlayTrigger> - </div> + <OverlayTrigger placement='top' overlay={tooltip(name && name.toUpperCase())}> + <div className='catalog-tile-item-name'>{name}</div> + </OverlayTrigger> ); const VersionInfo = ({version}) => ( @@ -64,7 +59,7 @@ const VersionInfo = ({version}) => ( <div className='catalog-tile-item-version' data-test-id='catalog-item-version'> V {version} </div> - </div> + </div> ); const EntityDetails = ({catalogItemData, catalogItemTypeClass}) => { @@ -73,54 +68,55 @@ const EntityDetails = ({catalogItemData, catalogItemTypeClass}) => { <div className='catalog-tile-entity-details'> <CatalogTileVendorName catalogItemTypeClass={catalogItemTypeClass} vendorName={vendorName}/> <CatalogTileItemName name={name}/> - <VersionInfo version={version.label} /> - </div> + <VersionInfo version={version.label}/> + </div> ); }; -const ItemStatusInfo = ({catalogItemTypeClass, lockingUser, itemStatus}) => { +const ItemStatusInfo = ({catalogItemTypeClass, lockingUser, itemStatus}) => { const status = statusBarTextMap[itemStatus]; const lockedBy = lockingUser ? ` by ${lockingUser}` : ''; const toolTipMsg = `${status}${lockedBy}`; return ( - <div className={'catalog-tile-content ' + catalogItemTypeClass}> + <div className={'catalog-tile-content ' + catalogItemTypeClass}> <div className='catalog-tile-locking-user-name'>{i18n(status)}</div> - <OverlayTrigger placement='top' overlay={tooltip(toolTipMsg)}> + <OverlayTrigger placement='top' overlay={tooltip(toolTipMsg)}> <div className='catalog-tile-check-in-status'><SVGIcon name={itemStatus === statusEnum.CHECK_OUT_STATUS ? 'unlocked' : 'locked'} data-test-id={itemStatus === statusEnum.CHECK_IN_STATUS ? 'catalog-item-checked-in' : 'catalog-item-checked-out'}/> </div> - </OverlayTrigger> + </OverlayTrigger> </div> - + ); }; -const CatalogItemDetails = ({catalogItemData, catalogItemTypeClass, onSelect, onMigrate}) => { - +const CatalogItemDetails = ({catalogItemData, catalogItemTypeClass, onSelect, onMigrate}) => { + let {status: itemStatus} = VersionControllerUtils.getCheckOutStatusKindByUserID(catalogItemData.status, catalogItemData.lockingUser); - + return ( <CatalogTile catalogItemTypeClass={catalogItemTypeClass} onSelect={() => { if (catalogItemData.isOldVersion && catalogItemData.isOldVersion === migrationStatusMapper.OLD_VERSION) { onMigrate({ softwareProduct: catalogItemData }); - } else { + } + else { onSelect(); } }} data-test-id={catalogItemTypeClass}> - <div className='catalog-tile-top item-details'> - <ItemTypeTitle catalogItemTypeClass={catalogItemTypeClass}/> - <CatalogTileIcon catalogItemTypeClass={catalogItemTypeClass}/> - <EntityDetails catalogItemTypeClass={catalogItemTypeClass} catalogItemData={catalogItemData} /> - <ItemStatusInfo itemStatus={itemStatus} catalogItemTypeClass={catalogItemTypeClass} lockingUser={catalogItemData.lockingUser} /> + <div className='catalog-tile-top item-details'> + <ItemTypeTitle catalogItemTypeClass={catalogItemTypeClass}/> + <CatalogTileIcon catalogItemTypeClass={catalogItemTypeClass}/> + <EntityDetails catalogItemTypeClass={catalogItemTypeClass} catalogItemData={catalogItemData}/> + <ItemStatusInfo itemStatus={itemStatus} catalogItemTypeClass={catalogItemTypeClass} lockingUser={catalogItemData.lockingUser}/> </div> </CatalogTile> ); - + }; CatalogItemDetails.PropTypes = { diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx index 17248e3b02..51702e6d36 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx @@ -15,7 +15,7 @@ */ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; const SoftwareProductListHeader = ({selectedVendor, onBack}) => ( <div className='vendor-page-header'> diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js index 73a447558d..0d1e3992ce 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js @@ -26,7 +26,7 @@ import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/Soft function getMessageForMigration(name) { return ( <div> - <div>{i18n('{name} needs to be updated. Click ‘Checkout & Update’, to proceed.',{name})}</div> + <div>{i18n(`${name} needs to be updated. Click ‘Checkout & Update’, to proceed.`)}</div> <div>{i18n('Please don’t forget to submit afterwards')}</div> </div> ); @@ -65,7 +65,7 @@ const OnboardingCatalogActionHelper = { type: modalActionTypes.GLOBAL_MODAL_WARNING, data: { title: 'WARNING', - msg: i18n('{name} is locked by user {lockingUser} for self-healing',{name, lockingUser}) + msg: i18n(`${name} is locked by user ${lockingUser} for self-healing`) } }); } else { diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx index cecccdd9ad..d3d6f9ce37 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx @@ -19,7 +19,7 @@ import CatalogTile from '../CatalogTile.jsx'; import classnames from 'classnames'; import VSPOverlay from './VSPOverlay.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import tooltip from './Tooltip.jsx'; @@ -50,7 +50,7 @@ class VendorItem extends React.Component { </div> <OverlayTrigger placement='top' overlay={tooltip(vendorName)}> <div className='catalog-tile-item-name'>{vendorName}</div> - </OverlayTrigger> + </OverlayTrigger> <div className={classnames('catalog-tile-vsp-count', {active: shouldShowOverlay}, {clickable: softwareProductList.length})} onClick={(event) => this.handleVspCountClick(event)} @@ -63,7 +63,7 @@ class VendorItem extends React.Component { </div> </div> </div> - + {shouldShowOverlay && softwareProductList.length > 0 && <VSPOverlay onMigrate={onMigrate} VSPList={softwareProductList} onSelectVSP={onSelectVSP} onSeeMore={() => onVendorSelect(vendor)}/>} </CatalogTile> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js index 12f68a2afe..07d6c740e0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js @@ -22,7 +22,7 @@ import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; import {enums} from 'sdc-app/onboarding/OnboardingConstants.js'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; -import {navigationItems, mapScreenToNavigationItem} from './SoftwareProductConstants.js'; +import {navigationItems, mapScreenToNavigationItem, onboardingMethod as onboardingMethodTypes} from './SoftwareProductConstants.js'; import SoftwareProductActionHelper from './SoftwareProductActionHelper.js'; import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js'; import SoftwareProductDependenciesActionHelper from './dependencies/SoftwareProductDependenciesActionHelper.js'; @@ -36,7 +36,7 @@ function getActiveNavigationId(screen, componentId) { return activeItemId; } -const buildComponentNavigationBarGroups = ({componentId, meta}) => { +const buildComponentNavigationBarGroups = ({componentId, meta, hasImages}) => { const groups = ([ { id: navigationItems.GENERAL + '|' + componentId, @@ -64,6 +64,12 @@ const buildComponentNavigationBarGroups = ({componentId, meta}) => { disabled: false, meta }, { + id: navigationItems.IMAGES + '|' + componentId, + name: i18n('Images'), + disabled: false, + hidden: (!hasImages), + meta + }, { id: navigationItems.PROCESS_DETAILS + '|' + componentId, name: i18n('Process Details'), disabled: false, @@ -79,9 +85,9 @@ const buildComponentNavigationBarGroups = ({componentId, meta}) => { return groups; }; -const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}) => { +const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, imagesNavigationList}) => { const {softwareProductEditor: {data: currentSoftwareProduct = {}}} = softwareProduct; - const {id, name} = currentSoftwareProduct; + const {id, name, onboardingMethod} = currentSoftwareProduct; const groups = [{ id: id, name: name, @@ -96,6 +102,13 @@ const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, co name: i18n('General'), disabled: false, meta + }, + { + id: navigationItems.DEPLOYMENT_FLAVORS, + name: i18n('Deployment Flavors'), + disabled: false, + hidden: onboardingMethod !== onboardingMethodTypes.MANUAL, + meta }, { id: navigationItems.PROCESS_DETAILS, name: i18n('Process Details'), @@ -135,7 +148,8 @@ const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, co name: displayName, meta, expanded: mapOfExpandedIds[navigationItems.COMPONENTS + '|' + id] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, - items: buildComponentNavigationBarGroups({componentId: id, meta}) + items: buildComponentNavigationBarGroups({componentId: id, meta, + hasImages : (onboardingMethod === onboardingMethodTypes.MANUAL || imagesNavigationList[id] === true)}) })) ] } @@ -179,17 +193,18 @@ function buildMeta({softwareProduct, componentId, softwareProductDependencies}) const mapStateToProps = ({softwareProduct}, {currentScreen: {screen, props: {componentId}}}) => { const {softwareProductEditor, softwareProductComponents, softwareProductDependencies} = softwareProduct; const {mapOfExpandedIds = []} = softwareProductEditor; - const {componentsList = []} = softwareProductComponents; + const {componentsList = [], images: {imagesNavigationList}} = softwareProductComponents; + const meta = buildMeta({softwareProduct, componentId, softwareProductDependencies}); return { versionControllerProps: buildVersionControllerProps(softwareProduct), - navigationBarProps: buildNavigationBarProps({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}), + navigationBarProps: buildNavigationBarProps({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds, imagesNavigationList}), meta }; }; -const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, componentId, - meta: {isReadOnlyMode, softwareProduct, version, qdata, softwareProductDependencies, +const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, componentId, + meta: {isReadOnlyMode, softwareProduct, version, qdata, softwareProductDependencies, currentComponentMeta: {componentData, componentQdata}}}) => { let promise; if (isReadOnlyMode) { @@ -208,6 +223,7 @@ const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, componentI case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId: componentId, qdata: componentQdata}); break; @@ -242,6 +258,9 @@ const onComponentNavigate = (dispatch, {id, softwareProductId, version, currentC case navigationItems.NETWORKS: OnboardingActionHelper.navigateToComponentNetwork(dispatch, {softwareProductId, componentId: nextComponentId, version}); break; + case navigationItems.IMAGES: + OnboardingActionHelper.navigateToComponentImages(dispatch, {softwareProductId, componentId: nextComponentId, version}); + break; case navigationItems.STORAGE: OnboardingActionHelper.navigateToComponentStorage(dispatch, {softwareProductId, componentId: nextComponentId, version}); break; @@ -266,7 +285,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr let {heatSetup, heatSetupCache} = meta; let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ? HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) : - Promise.resolve(); + Promise.resolve(); let preNavigate = meta ? autoSaveBeforeNavigate({dispatch, screen, meta, softwareProductId, componentId: currentComponentId}) : Promise.resolve(); version = version || (meta ? meta.version : undefined); Promise.all([preNavigate, heatSetupPopupPromise]).then(() => { @@ -277,6 +296,9 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr case navigationItems.GENERAL: OnboardingActionHelper.navigateToSoftwareProductDetails(dispatch, {softwareProductId, version}); break; + case navigationItems.DEPLOYMENT_FLAVORS: + OnboardingActionHelper.navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version}); + break; case navigationItems.PROCESS_DETAILS: OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version}); break; @@ -299,7 +321,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr onComponentNavigate(dispatch, {id, softwareProductId, version, screen, currentComponentId}); break; } - }).catch(() => {}); + }).catch((e) => {console.error(e);}); } }; @@ -311,6 +333,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: + case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: props.onSave = () => { @@ -335,7 +358,7 @@ const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwarePr OnboardingActionHelper.navigateToSoftwareProductActivityLog(dispatch, {softwareProductId, version: newVersion}); } }); - }).catch(() => {}); + }).catch((e) => {console.error(e);}); }; return props; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js index 6f53886350..d6ba86ad6e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js @@ -27,6 +27,7 @@ import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel import {actionTypes as HeatSetupActions} from 'sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js'; import {actionTypes as featureGroupsActionConstants} from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js'; import {actionTypes as licenseAgreementActionTypes} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js'; +import {actionTypes as componentActionTypes} from './components/SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import {PRODUCT_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; @@ -57,7 +58,8 @@ function putSoftwareProduct(softwareProduct) { vendorName: softwareProduct.vendorName, licensingVersion: softwareProduct.licensingVersion && softwareProduct.licensingVersion.id ? softwareProduct.licensingVersion : {} , icon: softwareProduct.icon, - licensingData: softwareProduct.licensingData + licensingData: softwareProduct.licensingData, + onboardingMethod: softwareProduct.onboardingMethod }); } @@ -249,7 +251,8 @@ const SoftwareProductActionHelper = { processAndValidateHeatCandidate(dispatch, {softwareProductId, version}){ return validateHeatCandidate(softwareProductId, version).then(response => { if (response.status === 'Success') { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); + let isFetchImageDetails = true; + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version, isFetchImageDetails}); SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version}); } }); @@ -459,8 +462,20 @@ const SoftwareProductActionHelper = { }, /** for the next verision */ - addComponent(dispatch) { - return dispatch; + addComponent(dispatch, {softwareProductId, modalClassName}) { + SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch); + dispatch({ + type: componentActionTypes.COMPONENT_CREATE_OPEN + }); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMPONENT_CREATION, + modalComponentProps: {softwareProductId}, + modalClassName, + title: 'Create Virtual Function Component' + } + }); }, migrateSoftwareProduct(dispatch, {softwareProduct}) { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js index f29b0f6e0d..0379ee5d4a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js @@ -38,11 +38,13 @@ export const navigationItems = keyMirror({ VENDOR_SOFTWARE_PRODUCT: 'vendor-software-product', GENERAL: 'general', PROCESS_DETAILS: 'process-details', - NETWORKS: 'networks', - DEPENDENCIES: 'dependencies', + DEPLOYMENT_FLAVORS: 'deployment-flavor', + NETWORKS: 'networks', + IMAGES: 'images', ATTACHMENTS: 'attachments', ACTIVITY_LOG: 'activity-log', COMPONENTS: 'components', + DEPENDENCIES: 'dependencies', COMPUTE: 'compute', LOAD_BALANCING: 'load-balancing', @@ -50,6 +52,11 @@ export const navigationItems = keyMirror({ MONITORING: 'monitoring' }); +export const onboardingMethod = { + MANUAL: 'Manual', + HEAT: 'HEAT' +}; + export const forms = keyMirror({ VENDOR_SOFTWARE_PRODUCT_DETAILS: 'vendor-software-product-details', }); @@ -61,6 +68,7 @@ export const mapScreenToNavigationItem = { [enums.SCREEN.SOFTWARE_PRODUCT_DETAILS]: navigationItems.GENERAL, [enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS]: navigationItems.ATTACHMENTS, [enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES]: navigationItems.PROCESS_DETAILS, + [enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT]: navigationItems.DEPLOYMENT_FLAVORS, [enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS]: navigationItems.NETWORKS, [enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG]: navigationItems.ACTIVITY_LOG, [enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES]: navigationItems.DEPENDENCIES, @@ -69,6 +77,7 @@ export const mapScreenToNavigationItem = { [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE]: navigationItems.COMPUTE, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING]: navigationItems.LOAD_BALANCING, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK]: navigationItems.NETWORKS, + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES]: navigationItems.IMAGES, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE]: navigationItems.STORAGE, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES]: navigationItems.PROCESS_DETAILS, [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING]: navigationItems.MONITORING, diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js index 97988d87f9..5248c4e8fd 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js @@ -22,6 +22,8 @@ import SoftwareProductCreationReducer from './creation/SoftwareProductCreationRe import SoftwareProductDetailsReducer from './details/SoftwareProductDetailsReducer.js'; import SoftwareProductProcessesListReducer from './processes/SoftwareProductProcessesListReducer.js'; import SoftwareProductProcessesEditorReducer from './processes/SoftwareProductProcessesEditorReducer.js'; +import SoftwareProductDeploymentListReducer from './deployment/SoftwareProductDeploymentListReducer.js'; +import SoftwareProductDeploymentEditorReducer from './deployment/editor/SoftwareProductDeploymentEditorReducer.js'; import SoftwareProductNetworksListReducer from './networks/SoftwareProductNetworksListReducer.js'; import SoftwareProductComponentsListReducer from './components/SoftwareProductComponentsListReducer.js'; import SoftwareProductComponentEditorReducer from './components/SoftwareProductComponentEditorReducer.js'; @@ -31,12 +33,19 @@ import SoftwareProductComponentProcessesEditorReducer from './components/process import {actionTypes as componentProcessesActionTypes} from './components/processes/SoftwareProductComponentProcessesConstants.js'; import SoftwareProductComponentsNICListReducer from './components/network/SoftwareProductComponentsNICListReducer.js'; import SoftwareProductComponentsNICEditorReducer from './components/network/SoftwareProductComponentsNICEditorReducer.js'; +import SoftwareProductComponentsImageListReducer from './components/images/SoftwareProductComponentsImageListReducer.js'; +import SoftwareProductComponentsImageEditorReducer from './components/images/SoftwareProductComponentsImageEditorReducer.js'; +import SoftwareProductComponentsImageNavigationReducer from './components/images/SoftwareProductComponentsImageNavigationReducer.js'; +import SoftwareProductComponentsNICCreationReducer from './components/network/NICCreation/NICCreationReducer.js'; import SoftwareProductComponentsMonitoringReducer from './components/monitoring/SoftwareProductComponentsMonitoringReducer.js'; +import SoftwareProductComponentsComputeFlavorListReducer from './components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js'; +import SoftwareProductComponentsComputeFlavorReducer from './components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js'; import {createPlainDataReducer} from 'sdc-app/common/reducers/PlainDataReducer.js'; import SoftwareProductDependenciesReducer from './dependencies/SoftwareProductDependenciesReducer.js'; import {createJSONSchemaReducer, createComposedJSONSchemaReducer} from 'sdc-app/common/reducers/JSONSchemaReducer.js'; -import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import {COMPONENTS_QUESTIONNAIRE, COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js'; +import {IMAGE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js'; export default combineReducers({ softwareProductAttachments: combineReducers({ @@ -51,6 +60,10 @@ export default combineReducers({ processesEditor: createPlainDataReducer(SoftwareProductProcessesEditorReducer), processToDelete: (state = false, action) => action.type === processesActionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM ? action.processToDelete : state }), + softwareProductDeployment: combineReducers({ + deploymentFlavors: SoftwareProductDeploymentListReducer, + deploymentFlavorEditor: createPlainDataReducer(SoftwareProductDeploymentEditorReducer) + }), softwareProductNetworks: combineReducers({ networksList: SoftwareProductNetworksListReducer }), @@ -65,7 +78,17 @@ export default combineReducers({ }), network: combineReducers({ nicList: SoftwareProductComponentsNICListReducer, - nicEditor: createPlainDataReducer(createComposedJSONSchemaReducer(NIC_QUESTIONNAIRE, SoftwareProductComponentsNICEditorReducer)) + nicEditor: createPlainDataReducer(createComposedJSONSchemaReducer(NIC_QUESTIONNAIRE, SoftwareProductComponentsNICEditorReducer)), + nicCreation: createPlainDataReducer(SoftwareProductComponentsNICCreationReducer) + }), + images: combineReducers({ + imagesList: SoftwareProductComponentsImageListReducer, + imagesNavigationList: SoftwareProductComponentsImageNavigationReducer, + imageEditor: createPlainDataReducer(createComposedJSONSchemaReducer(IMAGE_QUESTIONNAIRE, SoftwareProductComponentsImageEditorReducer)) + }), + computeFlavor: combineReducers({ + computesList: SoftwareProductComponentsComputeFlavorListReducer, + computeEditor: createPlainDataReducer(createComposedJSONSchemaReducer(COMPONENTS_COMPUTE_QUESTIONNAIRE, SoftwareProductComponentsComputeFlavorReducer)), }), monitoring: SoftwareProductComponentsMonitoringReducer }), diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx index 0d8bc58361..901a583e24 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx @@ -14,14 +14,14 @@ * permissions and limitations under the License. */ import React, {Component} from 'react'; -import Button from 'react-bootstrap/lib/Button.js'; +import Button from 'sdc-ui/lib/react/Button.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import FormControl from 'react-bootstrap/lib/FormControl.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SelectInput from 'nfvo-components/input/SelectInput.jsx'; import Icon from 'nfvo-components/icon/Icon.jsx'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import {fileTypes} from './HeatSetupConstants.js'; import {tabsMapping} from '../SoftwareProductAttachmentsConstants.js'; import {sortable} from 'react-sortable'; @@ -76,8 +76,8 @@ class SortableModuleFileList extends Component { <div className='modules-list-wrapper'> <div className='modules-list-header'> <div className='modules-list-controllers'> - {!isBaseExist && <Button bsStyle='link' onClick={onBaseAdd} disabled={unassigned.length === 0}>{i18n('Add Base')}</Button>} - <Button bsStyle='link' onClick={onModuleAdd} disabled={unassigned.length === 0}>{i18n('Add Module')}</Button> + {!isBaseExist && <Button btnType='link' onClick={onBaseAdd} disabled={unassigned.length === 0}>{i18n('Add Base')}</Button>} + <Button btnType='link' onClick={onModuleAdd} disabled={unassigned.length === 0}>{i18n('Add Module')}</Button> </div> </div> <ul>{listItems}</ul> @@ -102,7 +102,7 @@ const EmptyListContent = props => { return ( <div className='go-to-validation-button-wrapper'> <div className='all-files-assigned'>{i18n(displayText)}</div> - {heatDataExist && <div className={'link'} onClick={onClick} data-test-id='go-to-validation'>{i18n('Proceed To Validation')}<SVGIcon name='angle-right'/></div>} + {heatDataExist && <div className={'link'} onClick={onClick} data-test-id='go-to-validation'>{i18n('Proceed To Validation')}<SVGIcon name='angleRight'/></div>} </div> ); }; @@ -212,7 +212,7 @@ class ModuleFile extends Component { data-test-id={isBase ? 'base-name' : 'module-name'}/>} </div> </div> - <SVGIcon name='trash-o' onClick={() => onModuleDelete(name)} data-test-id='module-delete'/> + <SVGIcon name='trashO' onClick={() => onModuleDelete(name)} data-test-id='module-delete'/> </div> <div className='modules-list-item-selectors'> <SelectWithFileType diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx index 25ad90f351..f2d5de4dff 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationView.jsx @@ -17,7 +17,7 @@ import React, {Component, PropTypes} from 'react'; import classNames from 'classnames'; import Collapse from 'react-bootstrap/lib/Collapse.js'; import Icon from 'nfvo-components/icon/Icon.jsx'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import {mouseActions, errorLevels, nodeFilters} from './HeatValidationConstants.js'; @@ -68,7 +68,7 @@ function HeatFileTreeRow(props) { isFolder && <div onClick={() => toggleExpanded(path)} className='tree-node-expander'> - <SVGIcon name={!node.expanded ? 'chevron-up' : 'chevron-down'} data-test-id='validation-tree-block-toggle'/> + <SVGIcon name={!node.expanded ? 'chevronUp' : 'chevronDown'} data-test-id='validation-tree-block-toggle'/> </div> } { @@ -205,23 +205,19 @@ class HeatMessageBoard extends Component { key={error.name + error.errorMessage + error.parentName + rand} className='error-item' data-test-id='validation-error'> {error.level === errorLevels.WARNING ? - <SVGIcon name='exclamation-triangle-line' iconClassName='large' /> : <Icon image='error-lg' /> } + <SVGIcon name='exclamationTriangleLine' iconClassName='large' /> : <Icon image='error-lg' /> } <span className='error-item-file-type'> { (this.props.selectedNode === nodeFilters.ALL) ? <span> <span className='error-file-name'> - {i18n('{errorName}:', { - errorName: error.name - })} + {i18n(`${error.name}`)} </span> <span> - {i18n('{message}', {message: error.errorMessage})} + {i18n(error.errorMessage)} </span> </span> : - i18n('{errorMsg}', { - errorMsg: error.errorMessage - }) + i18n(error.errorMesage) } </span> </div> @@ -249,7 +245,7 @@ class ErrorsAndWarningsCount extends Component { <div className={'error-text ' + (size ? size : '')} data-test-id='validation-error-count'>{errors.errorCount}</div> </div>} {(errors.warningCount > 0) && <div className='counter'> - <SVGIcon name='exclamation-triangle-line' iconClassName={size} /> + <SVGIcon name='exclamationTriangleLine' iconClassName={size} /> <div className={'warning-text ' + (size ? size : '')} data-test-id='validation-warning-count'>{errors.warningCount}</div> </div>} </div>); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js index 41e7556749..b13bde03c8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js @@ -17,6 +17,24 @@ import {actionTypes, forms} from './SoftwareProductComponentsConstants.js'; export default (state = {}, action) => { switch (action.type) { + case actionTypes.COMPONENT_CREATE_OPEN: + return { + ...state, + formName: forms.CREATE_FORM, + formReady: null, + genericFieldInfo: { + 'displayName' : { + isValid: true, + errorText: '', + validations: [{type: 'required', data: true}, {type: 'validateName', data: true}, {type: 'maxLength', data: 25}] + }, + 'description' : { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 1000}] + } + } + }; case actionTypes.COMPONENT_LOAD: return { ...state, @@ -34,6 +52,11 @@ export default (state = {}, action) => { errorText: '', validations: [] }, + 'nfcFunction' : { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 30}] + }, 'description' : { isValid: true, errorText: '', @@ -41,6 +64,27 @@ export default (state = {}, action) => { } } }; + case actionTypes.COMPONENT_UPDATE: + return { + ...state, + data: action.component + }; + case actionTypes.COMPONENT_QUESTIONNAIRE_UPDATE: + return { + ...state, + qdata: action.payload.qdata || state.qdata, + qschema: action.payload.qschema || state.qschema + }; + case actionTypes.COMPONENT_DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + case actionTypes.COMPONENT_DATA_CLEAR: + return {}; default: return state; } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js new file mode 100644 index 0000000000..61aebdf293 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js @@ -0,0 +1,65 @@ +import {connect} from 'react-redux'; +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import SoftwareProductComponentsList from './SoftwareProductComponentsList.js'; +import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import SoftwareProductComponentsActionHelper from '../components/SoftwareProductComponentsActionHelper.js'; +import {onboardingMethod} from '../SoftwareProductConstants.js'; +import ConfirmationModalConstants from 'nfvo-components/modal/GlobalModalConstants.js'; + +const generateMessage = (name) => { + return i18n(`Are you sure you want to delete ${name}?`); +}; + +const mapStateToProps = ({softwareProduct}) => { + let {softwareProductEditor: {data: currentSoftwareProduct}, softwareProductComponents} = softwareProduct; + let {componentsList} = softwareProductComponents; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + + return { + currentSoftwareProduct, + isReadOnlyMode, + componentsList, + isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL + + }; +}; + +class SoftwareProductComponentsView extends React.Component { + render() { + let {currentSoftwareProduct, isReadOnlyMode, componentsList, isManual, onDeleteComponent} = this.props; + return ( + <SoftwareProductComponentsList + isReadOnlyMode={isReadOnlyMode} + componentsList={componentsList} + onDeleteComponent={onDeleteComponent} + isManual={isManual} + currentSoftwareProduct={currentSoftwareProduct}/>); + } + +} + +const mapActionToProps = (dispatch) => { + return { + onComponentSelect: ({id: softwareProductId, componentId, version}) => { + OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version }); + }, + onAddComponent: (softwareProductId) => SoftwareProductComponentsActionHelper.addComponent(dispatch, {softwareProductId}), + onDeleteComponent: (component, softwareProductId, version) => dispatch({ + type: ConfirmationModalConstants.GLOBAL_MODAL_WARNING, + data:{ + msg: generateMessage(component.displayName), + onConfirmed: ()=>SoftwareProductComponentsActionHelper.deleteComponent(dispatch, + { + softwareProductId, + componentId: component.id, + version + }) + } + }) + }; +}; + +export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js index 4e526d3b56..71dc8325ad 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js @@ -18,6 +18,8 @@ import Configuration from 'sdc-app/config/Configuration.js'; import {actionTypes, COMPONENTS_QUESTIONNAIRE} from './SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import SoftwareProductComponentsImageActionHelper from './images/SoftwareProductComponentsImageActionHelper.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; function baseUrl(softwareProductId, version) { const versionId = version.id; @@ -46,17 +48,53 @@ function putSoftwareProductComponent(softwareProductId, version, vspComponentId, name: vspComponent.name, displayName: vspComponent.displayName, vfcCode: vspComponent.vfcCode, + nfcFunction: vspComponent.nfcFunction, description: vspComponent.description }); } +function deleteSoftwareProductComponent(softwareProductId, componentId, version) { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${componentId}`,); +} + + +function postSoftwareProductComponent(softwareProductId, vspComponent, version) { + + return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { + name: vspComponent.displayName, + displayName: vspComponent.displayName, + description: vspComponent.description + }); +} + + const SoftwareProductComponentsActionHelper = { - fetchSoftwareProductComponents(dispatch, {softwareProductId, version}) { + fetchSoftwareProductComponents(dispatch, {softwareProductId, version, isFetchImageDetails = false}) { return fetchSoftwareProductComponents(softwareProductId, version).then(response => { - dispatch({ - type: actionTypes.COMPONENTS_LIST_UPDATE, - componentsList: response.results - }); + let componentImagesCalls = []; + if (isFetchImageDetails && response.listCount) { + response.results.map(component => { + let componentId = component.id; + componentImagesCalls[componentImagesCalls.length] = + SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, { + softwareProductId, + componentId, + version + }); + + }); + return Promise.all(componentImagesCalls).then(() => { + dispatch({ + type: actionTypes.COMPONENTS_LIST_UPDATE, + componentsList: response.results + }); + }); + } else { + dispatch({ + type: actionTypes.COMPONENTS_LIST_UPDATE, + componentsList: response.results + }); + } }); }, @@ -110,7 +148,45 @@ const SoftwareProductComponentsActionHelper = { type: actionTypes.COMPONENTS_LIST_UPDATE, componentsList: [] }); - } + }, + + createSoftwareProductComponent(dispatch,{softwareProductId, componentData, version}) { + SoftwareProductComponentsActionHelper.closeComponentCreationModal(dispatch); + /* for mock only */ + + dispatch({ + type: actionTypes.COMPONENTS_LIST_UPDATE, + componentsList: [{id: '123', ...componentData}] + }); + + postSoftwareProductComponent(softwareProductId, componentData, version).then(() => { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); + }); + }, + + clearComponentCreationData(dispatch) { + dispatch({ + type: actionTypes.COMPONENT_DATA_CLEAR + }); + }, + + closeComponentCreationModal(dispatch) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch); + }, + + deleteComponent(dispatch, {softwareProductId, componentId, version}) { + deleteSoftwareProductComponent(softwareProductId, componentId, version); + dispatch({ + type: actionTypes.COMPONENT_DELETE, + componentId: componentId + }); + }, + + + }; export default SoftwareProductComponentsActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js index 9307b099ed..35633b65cf 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js @@ -18,7 +18,13 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ COMPONENTS_LIST_UPDATE: null, COMPONENTS_LIST_EDIT: null, - COMPONENT_LOAD: null + COMPONENT_UPDATE: null, + COMPONENT_DATA_CHANGED: null, + COMPONENT_DATA_CLEAR: null, + COMPONENT_QUESTIONNAIRE_UPDATE: null, + COMPONENT_DELETE: null, + COMPONENT_LOAD: null, + COMPONENT_CREATE_OPEN: null }); export const storageConstants = keyMirror({ @@ -30,16 +36,20 @@ export const storageConstants = keyMirror({ export const forms = keyMirror({ ALL_SPC_FORMS: null, - NIC_EDIT_FORM: null + NIC_EDIT_FORM: null, + CREATE_FORM: null, + IMAGE_EDIT_FORM: null }); export const COMPONENTS_QUESTIONNAIRE = 'component'; +export const COMPONENTS_COMPUTE_QUESTIONNAIRE = 'compute'; export const navigationItems = keyMirror({ STORAGE: 'Storage', PROCESS_DETAILS: 'Process Details', MONITORING: 'Monitoring', NETWORK: 'Network', + IMAGES: 'Images', COMPUTE: 'Compute', LOAD_BALANCING: 'High Availability & Load Balancing' }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js index f789a92c6f..bd4c2fa884 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsList.js @@ -14,21 +14,16 @@ * permissions and limitations under the License. */ import {connect} from 'react-redux'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + import SoftwareProductComponentsListView from './SoftwareProductComponentsListView.jsx'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; -import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; - - -const mapStateToProps = ({softwareProduct}) => { - let {softwareProductEditor: {data: currentSoftwareProduct}, softwareProductComponents} = softwareProduct; - let {componentsList} = softwareProductComponents; - let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); +import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; +import SoftwareProductComponentsActionHelper from '../components/SoftwareProductComponentsActionHelper.js'; +import {actionTypes as globalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js'; - return { - currentSoftwareProduct, - isReadOnlyMode, - componentsList - }; +const generateMessage = (name) => { + return i18n(`Are you sure you want to delete ${name}?`); }; @@ -36,8 +31,21 @@ const mapActionToProps = (dispatch) => { return { onComponentSelect: ({id: softwareProductId, componentId, version}) => { OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version }); - } + }, + onAddComponent: (softwareProductId) => SoftwareProductActionHelper.addComponent(dispatch, {softwareProductId, modalClassName: 'create-vfc-modal'}), + onDeleteComponent: (component, softwareProductId, version) => dispatch({ + type: globalModalActions.GLOBAL_MODAL_WARNING, + data:{ + msg: generateMessage(component.displayName), + onConfirmed: ()=>SoftwareProductComponentsActionHelper.deleteComponent(dispatch, + { + softwareProductId, + componentId: component.id, + version + }) + } + }) }; }; -export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsListView); +export default connect(null, mapActionToProps, null, {withRef: true})(SoftwareProductComponentsListView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js index c7aaca5573..92211e0fd2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js @@ -22,6 +22,8 @@ export default (state = [], action) => { case actionTypes.COMPONENTS_LIST_EDIT: const indexForEdit = state.findIndex(component => component.id === action.component.id); return [...state.slice(0, indexForEdit), action.component, ...state.slice(indexForEdit + 1)]; + case actionTypes.COMPONENT_DELETE: + return state.filter(component => component.id !== action.componentId); default: return state; } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx index c28831fbde..a2a1964299 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx @@ -40,11 +40,11 @@ class SoftwareProductComponentsListView extends React.Component { }; render() { - let {componentsList = []} = this.props; + let {componentsList = [], isManual} = this.props; return ( <div className=''> { - componentsList.length > 0 && this.renderComponents() + (componentsList.length > 0 || isManual) && this.renderComponents() } </div> ); @@ -52,15 +52,16 @@ class SoftwareProductComponentsListView extends React.Component { renderComponents() { const {localFilter} = this.state; - let {isReadOnlyMode} = this.props; - + const {isManual, onAddComponent, isReadOnlyMode, currentSoftwareProduct: {id: softwareProductId}, componentsList } = this.props; return ( <ListEditorView title={i18n('Virtual Function Components')} filterValue={localFilter} placeholder={i18n('Filter Components')} onFilter={value => this.setState({localFilter: value})} - isReadOnlyMode={isReadOnlyMode} + isReadOnlyMode={isReadOnlyMode || !!this.filterList().length} + plusButtonTitle={i18n('Add Component')} + onAdd={isManual && componentsList.length === 0 ? () => onAddComponent(softwareProductId) : false} twoColumns> {this.filterList().map(component => this.renderComponentsListItem(component))} </ListEditorView> @@ -69,11 +70,12 @@ class SoftwareProductComponentsListView extends React.Component { renderComponentsListItem(component) { let {id: componentId, name, displayName, description = ''} = component; - let {currentSoftwareProduct: {id, version}, onComponentSelect} = this.props; + let {currentSoftwareProduct: {id, version}, onComponentSelect, isManual, isReadOnlyMode, onDeleteComponent} = this.props; return ( <ListEditorItemView key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()} className='list-editor-item-view' + onDelete={isManual && !isReadOnlyMode ? () => onDeleteComponent(component, id, version) : false} onSelect={() => onComponentSelect({id, componentId, version})}> <ListEditorItemViewField> <div className='name'>{displayName}</div> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js new file mode 100644 index 0000000000..02c09fbdf8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js @@ -0,0 +1,169 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import {actionTypes} from './computeComponents/computeFlavor/ComputeFlavorConstants.js'; +import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; +import {actionTypes as globalModalActionTypes, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import {COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; + +function baseUrl(softwareProductId, componentId, version) { + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/compute-flavors`; +} + +function baseUrlVSPLevel(softwareProductId, version){ + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/compute-flavors`; +} + +function fetchComputesList(softwareProductId, componentId, version){ + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}`); +} + +function fetchComputesListForVSP(softwareProductId, version){ + return RestAPIUtil.fetch(`${baseUrlVSPLevel(softwareProductId, version)}`); +} + +function fetchCompute(softwareProductId, componentId, computeId, version) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}/${computeId}`); +} + +function fetchComputeQuestionnaire({softwareProductId, componentId, computeId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}/${computeId}/questionnaire`); +} + +function postCompute({softwareProductId, componentId, compute, version}) { + return RestAPIUtil.post(baseUrl(softwareProductId, componentId, version), compute); +} + +function putCompute({softwareProductId, componentId, compute, version}) { + const computeData = { + name: compute.name, + description: compute.description + }; + return RestAPIUtil.put(`${baseUrl(softwareProductId, componentId, version)}/${compute.id}`, computeData); +} + +function putComputeQuestionnaire({softwareProductId, componentId, computeId, qdata, version}) { + return RestAPIUtil.put(`${baseUrl(softwareProductId, componentId, version)}/${computeId}/questionnaire`, qdata); +} + +function deleteCompute({softwareProductId, componentId, computeId, version}) { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, componentId, version)}/${computeId}`); +} + + +const ComputeFlavorActionHelper = { + openComputeEditor(dispatch, {props}) { + dispatch({ + type: actionTypes.computeEditor.LOAD_EDITOR_DATA, + compute: props.compute || {} + }); + dispatch({ + type: globalModalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMPONENT_COMPUTE_FLAVOR_EDITOR, + modalClassName: `compute-flavor-editor-modal-${props.compute ? 'edit' : 'create'}`, + modalComponentProps: {...props, size: props.compute ? modalSizes.LARGE : undefined, dialogClassName:'compute-flavor-editor-modal'}, + title: `${props.compute ? i18n('Edit Compute Flavor') : i18n('Create New Compute Flavor')}` + } + }); + }, + + closeComputeEditor(dispatch){ + dispatch({ + type: globalModalActionTypes.GLOBAL_MODAL_CLOSE + }); + dispatch({ + type: actionTypes.computeEditor.CLEAR_DATA + }); + }, + + fetchComputesList(dispatch, {softwareProductId, componentId, version}) { + return fetchComputesList(softwareProductId, componentId, version).then(response => dispatch({ + type: actionTypes.COMPUTE_FLAVORS_LIST_LOADED, + response + })); + }, + + fetchComputesListForVSP(dispatch, {softwareProductId, version}) { + return fetchComputesListForVSP(softwareProductId, version).then(response => dispatch({ + type: actionTypes.COMPUTE_FLAVORS_LIST_LOADED, + response + })); + }, + + loadComputeData({softwareProductId, componentId, computeId, version}) { + return fetchCompute(softwareProductId, componentId, computeId, version); + }, + + loadComputeQuestionnaire(dispatch, {softwareProductId, componentId, computeId, version}) { + return fetchComputeQuestionnaire({softwareProductId, componentId, computeId, version}).then(response => + ValidationHelper.qDataLoaded(dispatch, {qName: COMPONENTS_COMPUTE_QUESTIONNAIRE ,response: { + qdata: response.data ? JSON.parse(response.data) : {}, + qschema: JSON.parse(response.schema) + }}) + ); + }, + + loadCompute(dispatch, {softwareProductId, componentId, version, computeId, isReadOnlyMode}){ + return ComputeFlavorActionHelper.loadComputeData({softwareProductId, componentId, computeId, version}).then(({data}) => + ComputeFlavorActionHelper.loadComputeQuestionnaire(dispatch, {softwareProductId, componentId, computeId, version}).then(() => + ComputeFlavorActionHelper.openComputeEditor(dispatch, {props: {softwareProductId, componentId, version, isReadOnlyMode, compute: {id: computeId, ...data}}}) + )); + }, + + saveComputeDataAndQuestionnaire(dispatch, {softwareProductId, componentId, data: compute, qdata, version}) { + ComputeFlavorActionHelper.closeComputeEditor(dispatch); + if(compute.id) { + return Promise.all([ + putComputeQuestionnaire({softwareProductId, componentId, computeId: compute.id, qdata, version}), + putCompute({softwareProductId, componentId, compute, version}).then(() => { + dispatch({ + type: actionTypes.COMPUTE_LIST_EDIT, + compute + }); + }) + ]); + } + else { + return postCompute({softwareProductId, componentId, compute, version}).then(response => + dispatch({ + type: actionTypes.ADD_COMPUTE, + compute: { + ...compute, + id: response.id, + componentId + } + }) + ); + } + }, + + deleteCompute(dispatch, {softwareProductId, componentId, computeId, version}) { + return deleteCompute({softwareProductId, componentId, computeId, version}).then(() => dispatch({ + type: actionTypes.DELETE_COMPUTE, + computeId + })); + } +}; + +export default ComputeFlavorActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js index e97477b54d..bb8df29b82 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentCompute.js @@ -19,18 +19,23 @@ import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwarePr import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import {onboardingMethod} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -const mapStateToProps = ({softwareProduct}) => { +const mapStateToProps = ({softwareProduct, currentScreen: {props: {softwareProductId, componentId}}}) => { let {softwareProductEditor: {data: currentVSP}, softwareProductComponents} = softwareProduct; - let {componentEditor: {qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; + let {componentEditor: {qdata, dataMap, qgenericFieldInfo}, computeFlavor: {computesList: computeFlavorsList}} = softwareProductComponents; let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentVSP); return { qdata, dataMap, qgenericFieldInfo, - isReadOnlyMode + isReadOnlyMode, + softwareProductId, + componentId, + computeFlavorsList, + isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL }; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx index 8c197f0d49..dd524a35f3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/SoftwareProductComponentComputeView.jsx @@ -15,9 +15,9 @@ */ import React from 'react'; import Form from 'nfvo-components/input/validation/Form.jsx'; -import VmSizing from './computeComponents/VmSizing.jsx'; import NumberOfVms from './computeComponents/NumberOfVms.jsx'; import GuestOs from './computeComponents/GuestOs.jsx'; +import ComputeFlavors from './computeComponents/ComputeFlavors.js'; import Validator from 'nfvo-utils/Validator.js'; class SoftwareProductComponentComputeView extends React.Component { @@ -26,13 +26,15 @@ class SoftwareProductComponentComputeView extends React.Component { dataMap: React.PropTypes.object, qgenericFieldInfo: React.PropTypes.object, isReadOnlyMode: React.PropTypes.bool, + isManual: React.PropTypes.bool, onQDataChanged: React.PropTypes.func.isRequired, qValidateData: React.PropTypes.func.isRequired, onSubmit: React.PropTypes.func.isRequired }; render() { - let {qdata, dataMap, qgenericFieldInfo, isReadOnlyMode, onQDataChanged, qValidateData, onSubmit} = this.props; + let {softwareProductId, componentId, version, qdata, dataMap, qgenericFieldInfo, isReadOnlyMode, onQDataChanged, qValidateData, + onSubmit, computeFlavorsList, isManual} = this.props; return ( <div className='vsp-component-questionnaire-view'> @@ -44,11 +46,12 @@ class SoftwareProductComponentComputeView extends React.Component { onSubmit={() => onSubmit({qdata})} className='component-questionnaire-validation-form' isReadOnlyMode={isReadOnlyMode} > - <VmSizing onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} /> <NumberOfVms onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} qValidateData={qValidateData} customValidations={{'compute/numOfVMs/maximum' : this.validateMax, 'compute/numOfVMs/minimum': this.validateMin}} /> <GuestOs onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} /> + <ComputeFlavors computeFlavorsList={computeFlavorsList} softwareProductId={softwareProductId} componentId={componentId} + version={version} isReadOnlyMode={isReadOnlyMode} isManual={isManual}/> </Form> } </div> ); @@ -60,12 +63,24 @@ class SoftwareProductComponentComputeView extends React.Component { validateMin(value, state) { let maxVal = state.dataMap['compute/numOfVMs/maximum']; - return Validator.validateItem(value,maxVal,'maximum'); + // we are allowed to have an empty maxval, that will allow all minvals. + // if we do not have a minval than there is no point to check it either. + if (value === undefined || maxVal === undefined) { + return { isValid: true, errorText: '' }; + } else { + return Validator.validateItem(value, maxVal,'maximum'); + } } validateMax(value, state) { let minVal = state.dataMap['compute/numOfVMs/minimum']; - return Validator.validateItem(value,minVal,'minimum'); + if (minVal === undefined ) { + // having no minimum is the same as 0, maximum value doesn't need to be checked + // against it. + return { isValid: true, errorText: '' }; + } else { + return Validator.validateItem(value,minVal,'minimum'); + } } } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js new file mode 100644 index 0000000000..c72d42c11f --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js @@ -0,0 +1,116 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import {connect} from 'react-redux'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import ComputeFlavorActionHelper from 'sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; + +const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { + return { + onAddComputeClick: (isReadOnlyMode) => ComputeFlavorActionHelper.openComputeEditor(dispatch, {props: {softwareProductId, componentId, isReadOnlyMode, version}}), + onEditCompute: ({computeId, isReadOnlyMode}) => ComputeFlavorActionHelper.loadCompute(dispatch, {softwareProductId, componentId, version, computeId, isReadOnlyMode}), + onDeleteCompute: ({id, name}) => dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data:{ + msg: i18n(`Are you sure you want to delete "${name}"?`), + onConfirmed: () => ComputeFlavorActionHelper.deleteCompute(dispatch, {softwareProductId, componentId, computeId: id, version}) + } + }) + }; +}; + +const computeItemPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string +}); + +class ComputeFlavors extends React.Component { + + static propTypes = { + isReadOnlyMode: React.PropTypes.bool, + isManual: React.PropTypes.bool, + onAddComputeClick: React.PropTypes.func, + computeFlavorsList: React.PropTypes.arrayOf(computeItemPropType) + }; + + state = { + localFilter: '' + }; + + render() { + const {localFilter} = this.state; + const {isReadOnlyMode, isManual, onAddComputeClick, onEditCompute, onDeleteCompute} = this.props; + return ( + <div className='computes-list'> + <ListEditorView + title={i18n('Computes')} + plusButtonTitle={i18n('Add Compute')} + onAdd={isManual ? () => onAddComputeClick(isReadOnlyMode) : null} + isReadOnlyMode={isReadOnlyMode} + onFilter={isManual ? value => this.setState({localFilter: value}) : null} + filterValue={localFilter} + twoColumns> + {this.filterList().map(computeItem => + <ComputeItem key={computeItem.id} + computeItem={computeItem} isReadOnlyMode={isReadOnlyMode} isManual={isManual} + onEditCompute={onEditCompute} onDeleteCompute={onDeleteCompute}/>) + } + </ListEditorView> + </div> + ); + } + + filterList() { + const {computeFlavorsList = []} = this.props; + + const {localFilter} = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return computeFlavorsList.filter(({name = '', description = ''}) => { + return escape(name).match(filter) || escape(description).match(filter); + }); + } + else { + return computeFlavorsList; + } + } +} + +const ComputeItem = ({computeItem, isReadOnlyMode, isManual, onEditCompute, onDeleteCompute}) => { + const {id, name, description} = computeItem; + return ( + <ListEditorItemView + key={'item_' + id} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditCompute({computeId: id, isReadOnlyMode})} + onDelete={isManual ? () => onDeleteCompute({id, name}) : null}> + + <div className='list-editor-item-view-field'> + <div className='name'>{name}</div> + </div> + <div className='list-editor-item-view-field'> + <div className='description'>{description}</div> + </div> + </ListEditorItemView> + ); +}; + +export default connect(null, mapActionsToProps, null, {withRef: true})(ComputeFlavors); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx index 7a730d6f94..16bf599834 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/GuestOs.jsx @@ -24,17 +24,6 @@ const GuestOs = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { return( <div> <GridSection title={i18n('Guest OS')} > - <GridItem colSpan={2}> - <Input - data-test-id='guestOS-name' - label={i18n('Guest OS')} - type='text' - onChange={(tools) => onQDataChanged({'compute/guestOS/name' : tools})} - isValid={qgenericFieldInfo['compute/guestOS/name'].isValid} - errorText={qgenericFieldInfo['compute/guestOS/name'].errorText} - value={dataMap['compute/guestOS/name']} /> - </GridItem> - <GridItem colSpan={2}/> <GridItem> <div className='vertical-flex'> <label key='label' className='control-label'>{i18n('OS Bit Size')}</label> @@ -58,6 +47,16 @@ const GuestOs = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { <GridItem colSpan={2}/> <GridItem colSpan={2}> <Input + data-test-id='guestOS-name' + label={i18n('Guest OS')} + type='textarea' + onChange={(tools) => onQDataChanged({'compute/guestOS/name' : tools})} + isValid={qgenericFieldInfo['compute/guestOS/name'].isValid} + errorText={qgenericFieldInfo['compute/guestOS/name'].errorText} + value={dataMap['compute/guestOS/name']} /> + </GridItem> + <GridItem colSpan={2}> + <Input data-test-id='guestOS-tools' type='textarea' label={i18n('Guest OS Tools:')} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx index efeedc653e..ddde4391d9 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/NumberOfVms.jsx @@ -45,44 +45,6 @@ const NumberOfVms = ({qgenericFieldInfo, dataMap, onQDataChanged, qValidateData, errorText={qgenericFieldInfo['compute/numOfVMs/maximum'].errorText} value={dataMap['compute/numOfVMs/maximum']} /> </GridItem> - <GridItem> - <Input - data-test-id='numOfVMs-CpuOverSubscriptionRatio' - label={i18n('CPU Oversubscription Ratio')} - type='select' - groupClassName='bootstrap-input-options' - className='input-options-select' - isValid={qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].isValid} - errorText={qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].errorText} - value={dataMap['compute/numOfVMs/CpuOverSubscriptionRatio']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'compute/numOfVMs/CpuOverSubscriptionRatio' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['compute/numOfVMs/CpuOverSubscriptionRatio'].enum.map(cpuOSR => <option value={cpuOSR.enum} key={cpuOSR.enum}>{cpuOSR.title}</option>)} - </Input> - </GridItem> - <GridItem> - <Input - data-test-id='numOfVMs-MemoryRAM' - type='select' - label={i18n('Memory - RAM')} - groupClassName='bootstrap-input-options' - className='input-options-select' - isValid={qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].isValid} - errorText={qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].errorText} - value={dataMap['compute/numOfVMs/MemoryRAM']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'compute/numOfVMs/MemoryRAM' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['compute/numOfVMs/MemoryRAM'].enum.map(mRAM => <option value={mRAM.enum} key={mRAM.enum}>{mRAM.title}</option>)} - </Input> - </GridItem> </GridSection> ); }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx deleted file mode 100644 index 39f84807a2..0000000000 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/VmSizing.jsx +++ /dev/null @@ -1,68 +0,0 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * - * 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. - */ -import React from 'react'; -import i18n from 'nfvo-utils/i18n/i18n.js'; -import Input from 'nfvo-components/input/validation/Input.jsx'; -import GridSection from 'nfvo-components/grid/GridSection.jsx'; -import GridItem from 'nfvo-components/grid/GridItem.jsx'; -const VmSizing = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { - return( - <GridSection title={i18n('VM Sizing')}> - <GridItem> - <Input - data-test-id='numOfCPUs' - type='number' - label={i18n('Number of CPUs')} - onChange={(tools) => onQDataChanged({'compute/vmSizing/numOfCPUs' : tools})} - isValid={qgenericFieldInfo['compute/vmSizing/numOfCPUs'].isValid} - errorText={qgenericFieldInfo['compute/vmSizing/numOfCPUs'].errorText} - value={dataMap['compute/vmSizing/numOfCPUs']} /> - </GridItem> - <GridItem> - <Input - data-test-id='fileSystemSizeGB' - type='number' - label={i18n('File System Size (GB)')} - onChange={(tools) => onQDataChanged({'compute/vmSizing/fileSystemSizeGB' : tools})} - isValid={qgenericFieldInfo['compute/vmSizing/fileSystemSizeGB'].isValid} - errorText={qgenericFieldInfo['compute/vmSizing/fileSystemSizeGB'].errorText} - value={dataMap['compute/vmSizing/fileSystemSizeGB']} /> - </GridItem> - <GridItem> - <Input - data-test-id='persistentStorageVolumeSize' - type='number' - label={i18n('Persistent Storage/Volume Size (GB)')} - onChange={(tools) => onQDataChanged({'compute/vmSizing/persistentStorageVolumeSize' : tools})} - isValid={qgenericFieldInfo['compute/vmSizing/persistentStorageVolumeSize'].isValid} - errorText={qgenericFieldInfo['compute/vmSizing/persistentStorageVolumeSize'].errorText} - value={dataMap['compute/vmSizing/persistentStorageVolumeSize']} /> - </GridItem> - <GridItem> - <Input - data-test-id='IOOperationsPerSec' - type='number' - label={i18n('I/O Operations (per second)')} - onChange={(tools) => onQDataChanged({'compute/vmSizing/IOOperationsPerSec' : tools})} - isValid={qgenericFieldInfo['compute/vmSizing/IOOperationsPerSec'].isValid} - errorText={qgenericFieldInfo['compute/vmSizing/IOOperationsPerSec'].errorText} - value={dataMap['compute/vmSizing/IOOperationsPerSec']} /> - </GridItem> - </GridSection> - ); -}; - -export default VmSizing; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js new file mode 100644 index 0000000000..41728eefb0 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorConstants.js @@ -0,0 +1,32 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const COMPUTE_FLAVOR_FORM = 'COMPUTE_FLAVOR_FORM'; + +export const actionTypes = keyMirror({ + ADD_COMPUTE: null, + COMPUTE_FLAVORS_LIST_LOADED: null, + COMPUTE_LIST_EDIT: null, + EDIT_COMPUTE_FLAVOR: null, + DELETE_COMPUTE: null, + CONFIRM_DELETE_COMPUTE: null, + computeEditor: { + LOAD_EDITOR_DATA: null, + CLEAR_DATA: null + } +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js new file mode 100644 index 0000000000..caec0702fd --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js @@ -0,0 +1,55 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import ComputeFlavorEditorView from './ComputeFlavorEditorView.jsx'; +import {COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import ComputeFlavorActionHelper from 'sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import {COMPONENTS_COMPUTE_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import {onboardingMethod} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; + +export const mapStateToProps = ({softwareProduct: {softwareProductEditor, softwareProductComponents: {computeFlavor: {computeEditor = {}}}}}) => { + const {data: currentSoftwareProduct = {}} = softwareProductEditor; + const isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + let {data , qdata, qgenericFieldInfo, dataMap, genericFieldInfo, formReady} = computeEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + + return { + data, + qdata, + qgenericFieldInfo, + dataMap, + genericFieldInfo, + isReadOnlyMode, + isFormValid, + formReady, + isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL + }; +}; + + +const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { + return { + onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: COMPUTE_FLAVOR_FORM}), + onQDataChanged: deltaData => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_COMPUTE_QUESTIONNAIRE}), + onCancel: () => ComputeFlavorActionHelper.closeComputeEditor(dispatch), + onSubmit: ({data, qdata}) => ComputeFlavorActionHelper.saveComputeDataAndQuestionnaire(dispatch, {softwareProductId, componentId, data, qdata, version}), + onValidateForm: () => ValidationHelper.validateForm(dispatch, COMPUTE_FLAVOR_FORM) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(ComputeFlavorEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx new file mode 100644 index 0000000000..8f8a504629 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx @@ -0,0 +1,96 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import Form from 'nfvo-components/input/validation/Form.jsx'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; +import VmSizing from './VmSizing.jsx'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +class ComputeEditorView extends React.Component { + + static propTypes = { + data: React.PropTypes.object, + qdata: React.PropTypes.object, + qschema: React.PropTypes.object, + isReadOnlyMode: React.PropTypes.bool, + isManual: React.PropTypes.bool, + onDataChanged: React.PropTypes.func.isRequired, + onQDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + render() { + let {data = {}, qdata = {}, qgenericFieldInfo, dataMap, genericFieldInfo, isReadOnlyMode, isManual, isFormValid, formReady, + onDataChanged, onQDataChanged, onSubmit, onCancel, onValidateForm} = this.props; + const {id, name, description} = data; + const edittingComputeMode = Boolean(id); + + return ( + <div className='vsp-component-computeFlavor-view'> + {genericFieldInfo && <Form + ref={(form) => { + this.form = form; + }} + hasButtons={true} + onSubmit={ () => onSubmit({data, qdata}) } + onReset={ () => onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + isValid={isFormValid} + formReady={formReady} + onValidateForm={() => onValidateForm() } + className='component-questionnaire-validation-form' + submitButtonText={edittingComputeMode ? i18n('Save') : i18n('Create')}> + <GridSection> + <GridItem colSpan={edittingComputeMode ? 2 : 4}> + <Input + disabled={!isManual} + data-test-id='name' + type='text' + label={i18n('Flavor Name')} + value={name} + onChange={name => onDataChanged({name})} + isValid={genericFieldInfo['name'].isValid} + errorText={genericFieldInfo['name'].errorText} + isRequired/> + </GridItem> + <GridItem colSpan={edittingComputeMode ? 2 : 4}> + <Input + data-test-id='description' + type='textarea' + label={i18n('Description')} + value={description} + onChange={description => onDataChanged({description})} + isValid={genericFieldInfo['description'].isValid} + errorText={genericFieldInfo['description'].errorText}/> + </GridItem> + </GridSection> + {edittingComputeMode && <VmSizing qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged}/>} + </Form> + } + </div> + ); + } + + save(){ + return this.form.handleFormSubmit(new Event('dummy')); + } +} + +export default ComputeEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js new file mode 100644 index 0000000000..6c02f36c90 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorListReducer.js @@ -0,0 +1,33 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import {actionTypes} from './ComputeFlavorConstants.js'; + +export default (state = [], action) => { + switch (action.type) { + case actionTypes.COMPUTE_FLAVORS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_COMPUTE: + return [...state, action.compute]; + case actionTypes.COMPUTE_LIST_EDIT: + const indexForEdit = state.findIndex(({id}) => id === action.compute.id); + return [...state.slice(0, indexForEdit), action.compute, ...state.slice(indexForEdit + 1)]; + case actionTypes.DELETE_COMPUTE: + return state.filter(({id}) => id !== action.computeId); + default: + return state; + } +};
\ No newline at end of file diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js new file mode 100644 index 0000000000..a476f85a19 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorReducer.js @@ -0,0 +1,45 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes, COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.computeEditor.LOAD_EDITOR_DATA: + return { + ...state, + formName: COMPUTE_FLAVOR_FORM, + data: action.compute, + formReady: null, + genericFieldInfo: { + name: { + isValid: true, + errorText: '', + validations: [{type: 'required', data: true }] + }, + description: { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 300}] + } + } + }; + case actionTypes.computeEditor.CLEAR_DATA: + return {}; + default: + return state; + } +}; + diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx new file mode 100644 index 0000000000..8b30468362 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/VmSizing.jsx @@ -0,0 +1,106 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; +const VmSizing = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { + return( + <GridSection title={i18n('VM Sizing')}> + <GridItem> + <Input + data-test-id='numOfCPUs' + type='number' + label={i18n('Number of CPUs')} + onChange={(tools) => onQDataChanged({'vmSizing/numOfCPUs' : tools})} + isValid={qgenericFieldInfo['vmSizing/numOfCPUs'].isValid} + errorText={qgenericFieldInfo['vmSizing/numOfCPUs'].errorText} + value={dataMap['vmSizing/numOfCPUs']} /> + </GridItem> + <GridItem> + <Input + data-test-id='fileSystemSizeGB' + type='number' + label={i18n('File System Size (GB)')} + onChange={(tools) => onQDataChanged({'vmSizing/fileSystemSizeGB' : tools})} + isValid={qgenericFieldInfo['vmSizing/fileSystemSizeGB'].isValid} + errorText={qgenericFieldInfo['vmSizing/fileSystemSizeGB'].errorText} + value={dataMap['vmSizing/fileSystemSizeGB']} /> + </GridItem> + <GridItem> + <Input + data-test-id='persistentStorageVolumeSize' + type='number' + label={i18n('Persistent Storage/Volume Size (GB)')} + onChange={(tools) => onQDataChanged({'vmSizing/persistentStorageVolumeSize' : tools})} + isValid={qgenericFieldInfo['vmSizing/persistentStorageVolumeSize'].isValid} + errorText={qgenericFieldInfo['vmSizing/persistentStorageVolumeSize'].errorText} + value={dataMap['vmSizing/persistentStorageVolumeSize']} /> + </GridItem> + <GridItem> + <Input + data-test-id='ioOperationsPerSec' + type='number' + label={i18n('I/O Operations (per second)')} + onChange={(tools) => onQDataChanged({'vmSizing/ioOperationsPerSec' : tools})} + isValid={qgenericFieldInfo['vmSizing/ioOperationsPerSec'].isValid} + errorText={qgenericFieldInfo['vmSizing/ioOperationsPerSec'].errorText} + value={dataMap['vmSizing/ioOperationsPerSec']} /> + </GridItem> + <GridItem> + <Input + data-test-id='numOfVMs-cpuOverSubscriptionRatio' + label={i18n('CPU Oversubscription Ratio')} + type='select' + groupClassName='bootstrap-input-options' + className='input-options-select' + isValid={qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].isValid} + errorText={qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].errorText} + value={dataMap['vmSizing/cpuOverSubscriptionRatio']} + onChange={(e) => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({'vmSizing/cpuOverSubscriptionRatio' : val});} + }> + <option key='placeholder' value=''>{i18n('Select...')}</option> + {qgenericFieldInfo['vmSizing/cpuOverSubscriptionRatio'].enum.map(cpuOSR => <option value={cpuOSR.enum} key={cpuOSR.enum}>{cpuOSR.title}</option>)} + </Input> + </GridItem> + <GridItem> + <Input + data-test-id='numOfVMs-memoryRAM' + type='select' + label={i18n('Memory - RAM')} + groupClassName='bootstrap-input-options' + className='input-options-select' + isValid={qgenericFieldInfo['vmSizing/memoryRAM'].isValid} + errorText={qgenericFieldInfo['vmSizing/memoryRAM'].errorText} + value={dataMap['vmSizing/memoryRAM']} + onChange={(e) => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({'vmSizing/memoryRAM' : val});} + }> + <option key='placeholder' value=''>{i18n('Select...')}</option> + {qgenericFieldInfo['vmSizing/memoryRAM'].enum.map(mRAM => <option value={mRAM.enum} key={mRAM.enum}>{mRAM.title}</option>)} + </Input> + </GridItem> + </GridSection> + ); +}; + +export default VmSizing; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js new file mode 100644 index 0000000000..e85b6b6504 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js @@ -0,0 +1,50 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import {connect} from 'react-redux'; +import SoftwareProductComponentCreationView from './SoftwareProductComponentCreationView.jsx'; +import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import {forms} from '../SoftwareProductComponentsConstants.js'; + +export const mapStateToProps = ({softwareProduct}) => { + let {softwareProductComponents: {componentEditor: {data, genericFieldInfo, formReady}}, softwareProductEditor: {data: {version}}} = softwareProduct; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + return { + data, + genericFieldInfo, + formReady, + isFormValid, + version + }; +}; + + +const mapActionsToProps = (dispatch, {softwareProductId}) => { + return { + onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.CREATE_FORM}), + //onDataChanged: deltaData => SoftwareProductComponentsActionHelper.componentDataChanged(dispatch, {deltaData}), + onSubmit: (componentData, version) => { + return SoftwareProductComponentsActionHelper.createSoftwareProductComponent(dispatch, + {softwareProductId, componentData, version}); + }, + onCancel: () => SoftwareProductComponentsActionHelper.closeComponentCreationModal(dispatch), + onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) + }; + +}; + +export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentCreationView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx new file mode 100644 index 0000000000..55bcc818f5 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx @@ -0,0 +1,79 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import Form from 'nfvo-components/input/validation/Form.jsx'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; +import {forms} from '../SoftwareProductComponentsConstants.js'; + +class ComponentCreationView extends React.Component { + render() { + let {data = {}, onDataChanged, onCancel, genericFieldInfo} = this.props; + let {displayName, description} = data; + return( + <div> + { + genericFieldInfo && <Form + ref='validationForm' + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => onCancel() } + submitButtonText={i18n('Create')} + labledButtons={true} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => this.props.onValidateForm(forms.CREATE_FORM) } + className='entitlement-pools-form'> + <GridSection> + <GridItem colSpan={4}> + <Input + data-test-id='name' + onChange={displayName => onDataChanged({displayName})} + label={i18n('Name')} + isRequired={true} + isValid={genericFieldInfo.displayName.isValid} + errorText={genericFieldInfo.displayName.errorText} + value={displayName} + type='text'/> + </GridItem> + <GridItem colSpan={4}> + <Input + label={i18n('Description')} + onChange={description => onDataChanged({description})} + value={description} + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + data-test-id='description' + type='textarea'/> + </GridItem> + </GridSection> + </Form> + } + </div> + ); + } + + submit() { + const {onSubmit, data, version} = this.props; + onSubmit(data, version); + } +} + +export default ComponentCreationView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js index 34374aa7fb..7b4135028b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneral.js @@ -22,6 +22,7 @@ import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/Soft import {forms, COMPONENTS_QUESTIONNAIRE} from '../SoftwareProductComponentsConstants.js'; +import {onboardingMethod} from '../../SoftwareProductConstants.js'; export const mapStateToProps = ({softwareProduct}) => { @@ -34,6 +35,7 @@ export const mapStateToProps = ({softwareProduct}) => { componentData, qdata, isReadOnlyMode, + isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL, genericFieldInfo, qGenericFieldInfo, dataMap, diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx index e4595f97d6..6aa51d1609 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/general/SoftwareProductComponentsGeneralView.jsx @@ -21,7 +21,7 @@ import Form from 'nfvo-components/input/validation/Form.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -const GeneralSection = ({onDataChanged, displayName, vfcCode, description, isReadOnlyMode, genericFieldInfo}) => ( +const GeneralSection = ({onDataChanged, displayName, vfcCode, nfcFunction, description, isReadOnlyMode, genericFieldInfo, isManual}) => ( <GridSection title={i18n('General')}> {/* disabled until backend will be ready to implement it <div className='validation-input-wrapper'> @@ -37,9 +37,9 @@ const GeneralSection = ({onDataChanged, displayName, vfcCode, description, isRea data-test-id='name' label={i18n('Name')} value={displayName} - disabled={true} + disabled={!isManual || isReadOnlyMode} type='text'/> - <Input + {!isManual && <Input data-test-id='vfcCode' label={i18n('Naming Code')} value={vfcCode} @@ -47,6 +47,15 @@ const GeneralSection = ({onDataChanged, displayName, vfcCode, description, isRea errorText={genericFieldInfo.vfcCode.errorText} onChange={vfcCode => onDataChanged({vfcCode})} disabled={isReadOnlyMode} + type='text'/> } + <Input + data-test-id='nfcFunction' + label={i18n('Function')} + value={nfcFunction} + isValid={genericFieldInfo.nfcFunction.isValid} + errorText={genericFieldInfo.nfcFunction.errorText} + onChange={nfcFunction => onDataChanged({nfcFunction})} + disabled={isReadOnlyMode} type='text'/> </GridItem> <GridItem colSpan={2}> @@ -63,7 +72,7 @@ const GeneralSection = ({onDataChanged, displayName, vfcCode, description, isRea </GridItem> <GridItem /> </GridSection> - ); +); const HypervisorSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( <GridSection title={i18n('Hypervisor')}> @@ -110,64 +119,26 @@ const HypervisorSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( ); const ImageSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Image')}> - <GridItem> - <Input - data-test-id='format' - label={i18n('Image format')} - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - isValid={qgenericFieldInfo['general/image/format'].isValid} - errorText={qgenericFieldInfo['general/image/format'].errorText} - value={dataMap['general/image/format']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'general/image/format' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['general/image/format'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)} - </Input> - </GridItem> - <GridItem> - <Input - data-test-id='providedBy' - label={i18n('Image provided by')} - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - isValid={qgenericFieldInfo['general/image/providedBy'].isValid} - errorText={qgenericFieldInfo['general/image/providedBy'].errorText} - value={dataMap['general/image/providedBy']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'general/image/providedBy' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['general/image/providedBy'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)} - </Input> - </GridItem> + <GridSection title={i18n('Disk')}> <GridItem> <Input data-test-id='bootDiskSizePerVM' - onChange={(bootDiskSizePerVM) => onQDataChanged({'general/image/bootDiskSizePerVM' : bootDiskSizePerVM})} + onChange={(bootDiskSizePerVM) => onQDataChanged({'general/disk/bootDiskSizePerVM' : bootDiskSizePerVM})} label={i18n('Size of boot disk per VM (GB)')} type='number' - isValid={qgenericFieldInfo['general/image/bootDiskSizePerVM'].isValid} - errorText={qgenericFieldInfo['general/image/bootDiskSizePerVM'].errorText} - value={dataMap['general/image/bootDiskSizePerVM']}/> + isValid={qgenericFieldInfo['general/disk/bootDiskSizePerVM'].isValid} + errorText={qgenericFieldInfo['general/disk/bootDiskSizePerVM'].errorText} + value={dataMap['general/disk/bootDiskSizePerVM']}/> </GridItem> <GridItem> <Input data-test-id='ephemeralDiskSizePerVM' - onChange={(ephemeralDiskSizePerVM) => onQDataChanged({'general/image/ephemeralDiskSizePerVM' : ephemeralDiskSizePerVM})} + onChange={(ephemeralDiskSizePerVM) => onQDataChanged({'general/disk/ephemeralDiskSizePerVM' : ephemeralDiskSizePerVM})} label={i18n('Size of ephemeral disk per VM (GB)')} type='number' - isValid={qgenericFieldInfo['general/image/ephemeralDiskSizePerVM'].isValid} - errorText={qgenericFieldInfo['general/image/ephemeralDiskSizePerVM'].errorText} - value={dataMap['general/image/ephemeralDiskSizePerVM']}/> + isValid={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].isValid} + errorText={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].errorText} + value={dataMap['general/disk/ephemeralDiskSizePerVM']}/> </GridItem> </GridSection> ); @@ -257,7 +228,7 @@ const CloneSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( class SoftwareProductComponentsGeneralView extends React.Component { render() { - let {onQDataChanged, onDataChanged, genericFieldInfo, dataMap, qGenericFieldInfo, componentData: {displayName, vfcCode, description}, isReadOnlyMode} = this.props; + let {isManual, onQDataChanged, onDataChanged, genericFieldInfo, dataMap, qGenericFieldInfo, componentData: {displayName, vfcCode, nfcFunction, description}, isReadOnlyMode} = this.props; return( <div className='vsp-components-general'> <div className='general-data'> @@ -271,7 +242,9 @@ class SoftwareProductComponentsGeneralView extends React.Component { onDataChanged={onDataChanged} displayName={displayName} vfcCode={vfcCode} + nfcFunction={nfcFunction} description={description} + isManual={isManual} isReadOnlyMode={isReadOnlyMode} genericFieldInfo={genericFieldInfo}/> <HypervisorSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js new file mode 100644 index 0000000000..34198281b7 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js @@ -0,0 +1,169 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {IMAGE_QUESTIONNAIRE} from './SoftwareProductComponentsImageConstants.js'; +import {actionTypes} from './SoftwareProductComponentsImageConstants.js'; + +function baseUrl(softwareProductId, version, componentId) { + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/images`; +} + +function fetchImagesList({softwareProductId, componentId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`); +} + +function fetchImage({softwareProductId, componentId, imageId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${imageId}`); +} + +function destroyImage({softwareProductId, componentId, version, imageId}) { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${imageId}`); +} + +function createImage({softwareProductId, componentId, version, data}) { + return RestAPIUtil.post(baseUrl(softwareProductId, version, componentId), { + fileName: data.fileName + }); +} + +function fetchImageQuestionnaire({softwareProductId, componentId, imageId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${imageId}/questionnaire`); +} + +function saveImage({softwareProductId, version, componentId, image: {id, fileName}}) { + return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${id}`,{ + fileName + }); + +} + +function saveImageQuestionnaire({softwareProductId, componentId, version, imageId, qdata}) { + return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${imageId}/questionnaire`, qdata); +} + +const SoftwareProductComponentImagesActionHelper = { + fetchImagesList(dispatch, {softwareProductId, componentId, version}) { + dispatch({ + type: actionTypes.IMAGES_LIST_UPDATE, + response: [] + }); + + return fetchImagesList({softwareProductId, componentId, version}).then((response) => { + dispatch({ + type: actionTypes.IMAGES_LIST_UPDATE, + response: response.results, + componentId : componentId + }); + }); + }, + + deleteImage(dispatch, {softwareProductId, componentId, version, imageId}) { + return destroyImage({softwareProductId, componentId, version, imageId}).then(() => { + return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version}); + }); + }, + + loadImageData({softwareProductId, componentId, imageId, version}) { + return fetchImage({softwareProductId, componentId, imageId, version}); + }, + + openEditImageEditor(dispatch, {image, softwareProductId, componentId, version, isReadOnlyMode, modalClassName}) { + return SoftwareProductComponentImagesActionHelper.loadImageData({softwareProductId, componentId, imageId: image.id, version}).then(({data}) => { + SoftwareProductComponentImagesActionHelper.loadImageQuestionnaire(dispatch, { + softwareProductId, + componentId, + imageId: image.id, + version + }).then(() => { + SoftwareProductComponentImagesActionHelper.openImageEditor(dispatch, { + softwareProductId, + componentId, + version, + isReadOnlyMode, + modalClassName, + image, + data + }); + }); + }); + }, + + openImageEditor(dispatch, {image = {}, data = {}, softwareProductId, componentId, version, isReadOnlyMode}) { + + let title = (image && image.id) ? i18n('Edit Image') : i18n('Create New Image'); + let className = (image && image.id) ? 'image-edit-editor-model' : 'image-new-editor-modal'; + + dispatch({ + type: actionTypes.ImageEditor.OPEN, + image: {...data, id: image.id} + }); + + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR, + title: title, + modalComponentProps: {softwareProductId, componentId, version, isReadOnlyMode, dialogClassName:className} + } + }); + }, + + closeImageEditor(dispatch) { + + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + + dispatch({ + type: actionTypes.ImageEditor.CLOSE + }); + }, + + loadImageQuestionnaire(dispatch, {softwareProductId, componentId, imageId, version}) { + return fetchImageQuestionnaire({softwareProductId, componentId, imageId, version}).then((response) => { + ValidationHelper.qDataLoaded(dispatch, {qName: IMAGE_QUESTIONNAIRE ,response: { + qdata: response.data ? JSON.parse(response.data) : {}, + qschema: JSON.parse(response.schema) + }}); + }); + }, + + saveImageDataAndQuestionnaire(dispatch, {softwareProductId, componentId, version, data, qdata}) { + SoftwareProductComponentImagesActionHelper.closeImageEditor(dispatch); + if (data !== null && data.id) { + // editor in edit mode + return Promise.all([ + saveImageQuestionnaire({softwareProductId, version, componentId, imageId: data.id, qdata}), + saveImage({softwareProductId, version, componentId, image: data}).then(() => { + return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version}); + }) + ]); + } else { + // editor in create mode + createImage({softwareProductId, componentId, version, data}).then(() => { + return SoftwareProductComponentImagesActionHelper.fetchImagesList(dispatch, {softwareProductId, componentId, version}); + }); + } + } +}; +export default SoftwareProductComponentImagesActionHelper; diff --git a/openecomp-ui/tools/gulp/deployment/gulpfile.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js index bf127e6d19..6b6c9a30e5 100644 --- a/openecomp-ui/tools/gulp/deployment/gulpfile.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js @@ -13,16 +13,15 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -var gulp = require('gulp'); -var i18nUpdateTask = require('./tools/gulp/tasks/i18nUpdate'); +import keyMirror from 'nfvo-utils/KeyMirror.js'; -gulp.task('i18nUpdate', function() { +export const actionTypes = keyMirror({ + IMAGES_LIST_UPDATE: null, - return i18nUpdateTask({ - warDir: process.cwd(), - lang: 'en' - }); + ImageEditor: { + CLOSE: null, + OPEN: null + } }); -gulp.task('default', ['i18nUpdate']); - +export const IMAGE_QUESTIONNAIRE = 'image'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js new file mode 100644 index 0000000000..49d891c9df --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js @@ -0,0 +1,63 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import SoftwareProductComponentsImageActionHelper from './SoftwareProductComponentsImageActionHelper.js'; +import SoftwareProductComponentsImageEditorView from './SoftwareProductComponentsImageEditorView.jsx'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; +import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import {IMAGE_QUESTIONNAIRE} from './SoftwareProductComponentsImageConstants.js'; + +export const mapStateToProps = ({softwareProduct}) => { + + let {softwareProductEditor: {data:currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; + + let {images: {imageEditor = {}}} = softwareProductComponents; + let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = imageEditor; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + let {version, onboardingMethod} = currentSoftwareProduct; + let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo) && ValidationHelper.checkFormValid(qgenericFieldInfo); + + return { + version, + currentSoftwareProduct, + isValidityData, + data, + qdata, + dataMap, + isFormValid, + formReady, + genericFieldInfo, + qgenericFieldInfo, + isReadOnlyMode, + isManual: isManual + }; +}; + +const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { + return { + onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.IMAGE_EDIT_FORM}), + onSubmit: ({data, qdata}) => SoftwareProductComponentsImageActionHelper.saveImageDataAndQuestionnaire(dispatch, {softwareProductId, componentId, version, data, qdata}), + onCancel: () => SoftwareProductComponentsImageActionHelper.closeImageEditor(dispatch), + onValidateForm: () => ValidationHelper.validateForm(dispatch, forms.IMAGE_EDIT_FORM), + onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, + qName: IMAGE_QUESTIONNAIRE}), + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentsImageEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js new file mode 100644 index 0000000000..0ab785a97f --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js @@ -0,0 +1,42 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes} from './SoftwareProductComponentsImageConstants.js'; +import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.ImageEditor.CLOSE: + return {}; + case actionTypes.ImageEditor.OPEN: + return { + ...state, + data: { + ...action.image + }, + genericFieldInfo: { + 'fileName' : { + isValid: true, + errorText: '', + validations: [{type: 'required', data: true}, {type: 'validateName', data: true}] + } + }, + formName: forms.IMAGE_EDIT_FORM + }; + default: + return state; + } +}; + diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx new file mode 100644 index 0000000000..300f8edcc3 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx @@ -0,0 +1,71 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; + +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Form from 'nfvo-components/input/validation/Form.jsx'; + +import FileDetails from './imagesEditorComponents/FileDetails.jsx'; +import ImageDetails from './imagesEditorComponents/ImageDetails.jsx'; + +class SoftwareProductComponentsImageEditorView extends React.Component { + static propTypes = { + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + render() { + let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, genericFieldInfo, qgenericFieldInfo, dataMap, onDataChanged, isManual, onQDataChanged} = this.props; + let {id, fileName} = data; + let editingMode = Boolean(id); + return ( + <div> + {genericFieldInfo && <Form + ref={(form) => { this.form = form; }} + hasButtons={true} + onSubmit={ () => this.submit() } + onReset={ () => onCancel() } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + isValid={isFormValid} + formReady={formReady} + submitButtonText={editingMode ? i18n('Save') : i18n('Create')} + onValidateForm={() => onValidateForm() } + className='vsp-components-image-editor'> + <div className='editor-data'> + <FileDetails + editingMode={editingMode} + genericFieldInfo={genericFieldInfo} + qgenericFieldInfo={qgenericFieldInfo} + fileName={fileName} + onDataChanged={onDataChanged} + isManual={isManual} + dataMap={dataMap} + onQDataChanged={onQDataChanged}/> + {editingMode && <ImageDetails dataMap={dataMap}qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged}/>} + </div> + </Form>} + </div> + ); + } + submit() { + let {data, qdata, onSubmit, version} = this.props; + onSubmit({data, qdata, version}); + } +} + +export default SoftwareProductComponentsImageEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js new file mode 100644 index 0000000000..86c4e072d4 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js @@ -0,0 +1,88 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import SoftwareProductComponentsImageListView from './SoftwareProductComponentsImageListView.jsx'; +import ImageHelper from './SoftwareProductComponentsImageActionHelper.js'; +import SoftwareProductComponentsImagesActionHelper from './SoftwareProductComponentsImageActionHelper.js'; +import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js'; +import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; + +import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; + +export const mapStateToProps = ({softwareProduct}) => { + + let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; + let {images: {imagesList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + let {version, onboardingMethod} = currentSoftwareProduct; + let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; + + return { + version, + componentData, + qdata, + dataMap, + qgenericFieldInfo, + isValidityData, + imagesList, + isReadOnlyMode, + isManual : isManual + }; +}; + +const mapActionsToProps = (dispatch, {softwareProductId, componentId}) => { + return { + onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, + qName: COMPONENTS_QUESTIONNAIRE}), + onAddImage: (version, isReadOnlyMode) => { + SoftwareProductComponentsImagesActionHelper.openImageEditor(dispatch, + {isReadOnlyMode, softwareProductId, + componentId, version} + );}, + onDeleteImage: ((image, version) => { + let shortenedFileName = (image.fileName.length > 40) ? image.fileName.substr(0,40) + '...' : image.fileName; + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n(`Are you sure you want to delete "${shortenedFileName}"?`), + onConfirmed: () => ImageHelper.deleteImage(dispatch, { + softwareProductId, + componentId, + version, + imageId: image.id + }) + } + }); + }), + onEditImageClick: (image, version, isReadOnlyMode) => { + SoftwareProductComponentsImagesActionHelper.openEditImageEditor(dispatch, { + image, isReadOnlyMode, softwareProductId, componentId, version, modalClassName: 'image-modal-edit'} + ); + }, + onSubmit: ({qdata}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, + {softwareProductId, + vspComponentId: componentId, + qdata}); + } + }; +}; + +export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsImageListView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js new file mode 100644 index 0000000000..5dd2fb623b --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js @@ -0,0 +1,26 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes} from './SoftwareProductComponentsImageConstants.js'; + +export default (state = [], action) => { + switch (action.type) { + + case actionTypes.IMAGES_LIST_UPDATE: + return [...action.response]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx new file mode 100644 index 0000000000..ccf5b9d6b1 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx @@ -0,0 +1,132 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Form from 'nfvo-components/input/validation/Form.jsx'; + +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; +import Input from'nfvo-components/input/validation/Input.jsx'; + +class SoftwareProductComponentsImageListView extends React.Component { + state = { + localFilter: '' + }; + + render() { + let {dataMap, onQDataChanged, isReadOnlyMode, qgenericFieldInfo} = this.props; + return( + <div className='vsp-components-image'> + <div className='image-data'> + <div> + { qgenericFieldInfo && <Form + formReady={null} + isValid={true} + onSubmit={() => this.save()} + isReadOnlyMode={isReadOnlyMode} + hasButtons={false}> + + <h3 className='section-title'>{i18n('Image')}</h3> + <div className='rows-section'> + <div className='row-flex-components'> + <div className='single-col'> + <Input + data-test-id='providedBy' + label={i18n('Image provided by')} + type='select' + isValid={qgenericFieldInfo['general/image/providedBy'].isValid} + errorText={qgenericFieldInfo['general/image/providedBy'].errorText} + value={dataMap['general/image/providedBy']} + onChange={(e) => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({'general/image/providedBy' : val});} + }> + <option key='placeholder' value=''>{i18n('Select...')}</option> + { qgenericFieldInfo['general/image/providedBy'].enum.map(proto => + <option value={proto.enum} key={proto.enum}>{proto.title}</option>) } + </Input> + </div> + <div className='empty-two-col' /> + </div> + </div> + + </Form> } + </div> + </div> + {this.renderImagesList()} + </div> + ); + }; + + renderImagesList() { + const {localFilter} = this.state; + let {isReadOnlyMode, onAddImage, isManual, version} = this.props; + + return ( + <ListEditorView + title={i18n('Images')} + filterValue={localFilter} + placeholder={i18n('Filter Images by Name')} + isReadOnlyMode={isReadOnlyMode} + onFilter={value => this.setState({localFilter: value})} + onAdd={isManual ? () => onAddImage(version, isReadOnlyMode) : null} + plusButtonTitle={i18n('Add Image')} + twoColumns> + {this.filterList().map(image => this.renderImagesListItem(image, isReadOnlyMode))} + </ListEditorView> + ); + }; + + + renderImagesListItem(image, isReadOnlyMode) { + let {id, fileName} = image; + let {onEditImageClick, version, isManual, onDeleteImage} = this.props; + return ( + <ListEditorItemView + key={id} + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditImageClick(image, version, isReadOnlyMode)} + onDelete={isManual ? () => onDeleteImage(image, version) : null}> + + <ListEditorItemViewField> + <div className='image-filename-cell'><span className='image-filename'>{fileName}</span></div> + </ListEditorItemViewField> + </ListEditorItemView> + ); + } + + filterList() { + let {imagesList} = this.props; + let {localFilter} = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return imagesList.filter(({fileName = ''}) => { + return escape(fileName).match(filter); + }); + } + else { + return imagesList; + } + } + + save() { + let {onSubmit, qdata} = this.props; + return onSubmit({qdata}); + } +} +export default SoftwareProductComponentsImageListView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js new file mode 100644 index 0000000000..20d1f5dd18 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageNavigationReducer.js @@ -0,0 +1,32 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes} from './SoftwareProductComponentsImageConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + + case actionTypes.IMAGES_LIST_UPDATE: + if (action.componentId) { + return { + ...state, + [action.componentId] : (action.response && action.response.length > 0) + }; + } + return state; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx new file mode 100644 index 0000000000..ca58b697a2 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/FileDetails.jsx @@ -0,0 +1,48 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; +import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; + +import Format from './Format.jsx'; +import Version from './Version.jsx'; + +const FileDetails = ({editingMode, fileName, onDataChanged, isManual, dataMap, onQDataChanged, genericFieldInfo, qgenericFieldInfo}) => { + let fileNameCols = (editingMode) ? 3 : 4; + return( + <GridSection> + <GridItem colSpan={fileNameCols}> + <Input + disabled={!isManual} + onChange={fileName => onDataChanged({fileName}, forms.IMAGE_EDIT_FORM)} + label={i18n('Image Name')} + data-test-id='image-filename' + value={fileName} + isValid={genericFieldInfo.fileName.isValid} + errorText={genericFieldInfo.fileName.errorText} + isRequired={true} + type='text' + className='image-filename'/> + </GridItem> + {editingMode && <Version isManual={isManual} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged}/>} + {editingMode && <Format isManual={isManual} qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged}/>} + </GridSection> + ); +}; +export default FileDetails; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx new file mode 100644 index 0000000000..1f71c6b277 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Format.jsx @@ -0,0 +1,47 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + + +const Format = ({isManual, dataMap, qgenericFieldInfo, onQDataChanged}) => { + return( + <GridItem colSpan={2}> + <Input + disabled={!isManual} + data-test-id='image-format' + type='select' + label={i18n('Format')} + className='input-options-select' + groupClassName='bootstrap-input-options' + isValid={qgenericFieldInfo['format'].isValid} + errorText={qgenericFieldInfo['format'].errorText} + value={dataMap['format']} + onChange={(e) => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({'format' : val});} + }> + <option key='placeholder' value=''>{i18n('Select...')}</option> + {qgenericFieldInfo['format'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)} + </Input> + </GridItem> + ); +}; +export default Format; + diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx new file mode 100644 index 0000000000..24e54bbbcb --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/ImageDetails.jsx @@ -0,0 +1,39 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + +const ImageDetails = ({dataMap, qgenericFieldInfo, onQDataChanged}) => { + return( + <GridSection title={i18n('Image Details')}> + <GridItem colSpan={2}> + <Input + data-test-id='image-md5' + className='image-md5' + type='text' + label={i18n('md5')} + onChange={(md5) => onQDataChanged({'md5' : md5})} + isValid={qgenericFieldInfo['md5'].isValid} + errorText={qgenericFieldInfo['md5'].errorText} + value={dataMap['md5']}/> + </GridItem> + </GridSection> + ); +}; +export default ImageDetails; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx new file mode 100644 index 0000000000..3cac9a51b8 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/imagesEditorComponents/Version.jsx @@ -0,0 +1,39 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + + +const Version = ({isManual, dataMap, qgenericFieldInfo, onQDataChanged}) => { + return( + <GridItem colSpan={1}> + <Input + disabled={!isManual} + data-test-id='image-version' + type='text' + className='image-version' + label={i18n('Version')} + onChange={(version) => onQDataChanged({'version' : version})} + isValid={qgenericFieldInfo['version'].isValid} + errorText={qgenericFieldInfo['version'].errorText} + value={dataMap['version']}/> + </GridItem> + ); +}; +export default Version; + diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx index dc86771400..9ae9e359b0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancingRefView.jsx @@ -14,7 +14,7 @@ * permissions and limitations under the License. */ import React from 'react'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Form from 'nfvo-components/input/validation/Form.jsx'; @@ -56,7 +56,7 @@ const TextAreaItem = ({item, toggle, expanded, genericFieldInfo, dataMap, onQDat <div className={expanded ? 'title' : 'title add-padding'} data-test-id={`btn-${item.key}`} onClick={() => toggle(item.key)}> - <SVGIcon name={expanded ? 'chevron-up' : 'chevron-down'}/> + <SVGIcon name={expanded ? 'chevronUp' : 'chevronDown'}/> <span className='title-text'>{i18n(item.description)}</span> {item.added && <div className='new-line'>{i18n(item.added)}</div>} </div> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js index 293e252dca..730beba545 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js @@ -25,20 +25,19 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; export const mapStateToProps = ({softwareProduct}) => { let {softwareProductEditor: {data:currentVSP = {}}, softwareProductComponents: {monitoring}} = softwareProduct; - let {trapFilename, pollFilename} = monitoring; + let filenames = monitoring; let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentVSP); return { isReadOnlyMode, - trapFilename, - pollFilename + filenames }; }; const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => { return { onDropMibFileToUpload: (formData, type) => - SoftwareProductComponentsMonitoringAction.uploadSnmpFile(dispatch, { + SoftwareProductComponentsMonitoringAction.uploadFile(dispatch, { softwareProductId, version, componentId, @@ -46,7 +45,7 @@ const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) type }), - onDeleteSnmpFile: type => SoftwareProductComponentsMonitoringAction.deleteSnmpFile(dispatch, { + onDeleteFile: type => SoftwareProductComponentsMonitoringAction.deleteFile(dispatch, { softwareProductId, version, componentId, @@ -57,7 +56,7 @@ const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) type: modalActionTypes.GLOBAL_MODAL_ERROR, data: { title: i18n('Upload Failed'), - msg: i18n('Expected "zip" file. Please check the provided file type.') + msg: i18n('Expected "zip" file. Please check the provided file type.') } }), diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js index 64403faa78..3db708bc92 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js @@ -16,23 +16,13 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import SoftwareProductComponentsMonitoringConstants, {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js'; +import {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js'; import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -const UPLOAD = true; - function baseUrl(vspId, version, componentId) { const versionId = version.id; const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/components/${componentId}/monitors`; -} - -function snmpTrapUrl(vspId, version, componentId, isUpload) { - return `${baseUrl(vspId, version, componentId)}/snmp-trap${isUpload ? '/upload' : ''}`; -} - -function snmpPollUrl(vspId, version, componentId, isUpload) { - return `${baseUrl(vspId, version, componentId)}/snmp${isUpload ? '/upload' : ''}`; + return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/components/${componentId}/uploads`; } let onInvalidFileSizeUpload = (dispatch) => dispatch({ @@ -43,62 +33,42 @@ let onInvalidFileSizeUpload = (dispatch) => dispatch({ } }); -let uploadSnmpTrapFile = (dispatch, {softwareProductId, version, componentId, formData}) => { - RestAPIUtil.post(snmpTrapUrl(softwareProductId, version, componentId, UPLOAD), formData).then(()=> dispatch({ - type: actionTypes.SNMP_TRAP_UPLOADED, data: {filename: formData.get('upload').name} +let uploadFile = (dispatch, {softwareProductId, version, componentId, formData, type}) => { + return RestAPIUtil.post(`${baseUrl(softwareProductId, version, componentId)}/types/${type}`, formData).then(()=> dispatch({ + type: actionTypes.MONITOR_UPLOADED, data: {filename: formData.get('upload').name, type : type} })); }; -let uploadSnmpPollFile = (dispatch, {softwareProductId, version, componentId, formData}) => { - RestAPIUtil.post(snmpPollUrl(softwareProductId, version, componentId, UPLOAD), formData).then(()=> dispatch({ - type: actionTypes.SNMP_POLL_UPLOADED, data: {filename: formData.get('upload').name} +let deleteFile = (dispatch, {softwareProductId, version, componentId, type}) => { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/types/${type}`).then(()=> dispatch({ + type: actionTypes.MONITOR_DELETED, + data : { type: type} })); }; -let deleteSnmpTrapFile = (dispatch, {softwareProductId, version, componentId}) => { - RestAPIUtil.destroy(snmpTrapUrl(softwareProductId, version, componentId, !UPLOAD)).then(()=> dispatch({ - type: actionTypes.SNMP_TRAP_DELETED - })); -}; - -let deleteSnmpPollFile = (dispatch, {softwareProductId, version, componentId}) => { - RestAPIUtil.destroy(snmpPollUrl(softwareProductId, version, componentId, !UPLOAD)).then(()=> dispatch({ - type: actionTypes.SNMP_POLL_DELETED - })); -}; const SoftwareProductComponentsMonitoringAction = { fetchExistingFiles(dispatch, {softwareProductId, version, componentId}){ - RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/snmp`).then(response => + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`).then(response => dispatch({ - type: actionTypes.SNMP_FILES_DATA_CHANGE, - data: {trapFilename: response.snmpTrap, pollFilename: response.snmpPoll} + type: actionTypes.MONITOR_FILES_DATA_CHANGE, + data: response }) ); }, - uploadSnmpFile(dispatch, {softwareProductId, version, componentId, formData, type}){ + uploadFile(dispatch, {softwareProductId, version, componentId, formData, type}){ if (formData.get('upload').size) { - if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) { - uploadSnmpTrapFile(dispatch, {softwareProductId, version, componentId, formData}); - } - else { - uploadSnmpPollFile(dispatch, {softwareProductId, version, componentId, formData}); - } + return uploadFile(dispatch, {softwareProductId, version, componentId, formData, type}); } else { onInvalidFileSizeUpload(dispatch); } }, - deleteSnmpFile(dispatch, {softwareProductId, version, componentId, type}){ - if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) { - deleteSnmpTrapFile(dispatch, {softwareProductId, version, componentId}); - } - else { - deleteSnmpPollFile(dispatch, {softwareProductId, version, componentId}); - } + deleteFile(dispatch, {softwareProductId, version, componentId, type}){ + return deleteFile(dispatch, {softwareProductId, version, componentId, type}); } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js index d908d36aaa..bf2cbd2a3f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js @@ -14,20 +14,31 @@ * permissions and limitations under the License. */ import keyMirror from 'nfvo-utils/KeyMirror.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + export const actionTypes = keyMirror({ + MONITOR_FILES_DATA_CHANGE: null, + MONITOR_UPLOADED: null, + MONITOR_DELETED: null +}); - SNMP_FILES_DATA_CHANGE: null, +export const fileTypes = { + SNMP_TRAP: 'SNMP_TRAP', + SNMP_POLL: 'SNMP_POLL', + VES_EVENT: 'VES_EVENTS' +}; - SNMP_TRAP_UPLOADED: null, - SNMP_POLL_UPLOADED: null, +export const type2Name = { + SNMP_TRAP: 'snmpTrap', + SNMP_POLL: 'snmpPoll', + VES_EVENTS: 'vesEvent' +}; - SNMP_TRAP_DELETED: null, - SNMP_POLL_DELETED: null -}); -export default keyMirror({ - SNMP_TRAP: null, - SNMP_POLL: null -}); +export const type2Title = { + SNMP_TRAP : i18n('SNMP Trap'), + SNMP_POLL : i18n('SNMP Poll'), + VES_EVENTS: i18n('VES') +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js index 54513b9634..f5cfe6f06d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringReducer.js @@ -13,35 +13,21 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js'; +import {actionTypes, type2Name} from './SoftwareProductComponentsMonitoringConstants.js'; export default (state = {}, action) => { switch (action.type) { - case actionTypes.SNMP_FILES_DATA_CHANGE: + case actionTypes.MONITOR_FILES_DATA_CHANGE: + return action.data; + case actionTypes.MONITOR_UPLOADED: return { ...state, - trapFilename: action.data.trapFilename, - pollFilename: action.data.pollFilename + [type2Name[action.data.type]]: action.data.filename }; - case actionTypes.SNMP_TRAP_UPLOADED: + case actionTypes.MONITOR_DELETED: return { ...state, - trapFilename: action.data.filename - }; - case actionTypes.SNMP_POLL_UPLOADED: - return { - ...state, - pollFilename: action.data.filename - }; - case actionTypes.SNMP_TRAP_DELETED: - return { - ...state, - trapFilename: undefined - }; - case actionTypes.SNMP_POLL_DELETED: - return { - ...state, - pollFilename: undefined + [type2Name[action.data.type]]: undefined }; default: return state; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx index 329cc70353..2ad48ec84b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx @@ -19,14 +19,15 @@ import ButtonGroup from 'react-bootstrap/lib/ButtonGroup.js'; import ButtonToolbar from 'react-bootstrap/lib/ButtonToolbar.js'; import Button from 'react-bootstrap/lib/Button.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import SoftwareProductComponentsMonitoringConstants from './SoftwareProductComponentsMonitoringConstants.js'; +import {fileTypes, type2Title, type2Name} from './SoftwareProductComponentsMonitoringConstants.js'; + + class SoftwareProductComponentsMonitoringView extends Component { static propTypes = { isReadOnlyMode: PropTypes.bool, - trapFilename: PropTypes.string, - pollFilename: PropTypes.string, + filenames: PropTypes.object, softwareProductId: PropTypes.string, onDropMibFileToUpload: PropTypes.func, @@ -38,26 +39,24 @@ class SoftwareProductComponentsMonitoringView extends Component { }; + + render() { return ( <div className='vsp-component-monitoring'> - {this.renderDropzoneWithType(SoftwareProductComponentsMonitoringConstants.SNMP_TRAP)} - {this.renderDropzoneWithType(SoftwareProductComponentsMonitoringConstants.SNMP_POLL)} + {this.renderDropzoneWithType(fileTypes.VES_EVENT)} + {this.renderDropzoneWithType(fileTypes.SNMP_TRAP)} + {this.renderDropzoneWithType(fileTypes.SNMP_POLL)} </div> ); } renderDropzoneWithType(type) { - let {isReadOnlyMode, trapFilename, pollFilename} = this.props; - let fileName; - if (type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP) { - fileName = trapFilename; - } - else { - fileName = pollFilename; - } + let {isReadOnlyMode, filenames} = this.props; + let fileByType = type2Name[type]; + let fileName = (filenames) ? filenames[fileByType] : undefined; let refAndName = `fileInput${type.toString()}`; - let typeDisplayName = this.getFileTypeDisplayName(type); + let typeDisplayName = type2Title[type]; return ( <Dropzone className={`snmp-dropzone ${this.state.dragging ? 'active-dragging' : ''}`} @@ -97,7 +96,7 @@ class SoftwareProductComponentsMonitoringView extends Component { <ButtonToolbar> <ButtonGroup> <Button disabled>{filename}</Button> - <Button className='delete-button' onClick={()=>this.props.onDeleteSnmpFile(type)}>X</Button> + <Button className='delete-button' onClick={()=>this.props.onDeleteFile(type)}>X</Button> </ButtonGroup> </ButtonToolbar> ); @@ -126,11 +125,6 @@ class SoftwareProductComponentsMonitoringView extends Component { this.props.onFileUploadError(); } } - - getFileTypeDisplayName(type) { - return type === SoftwareProductComponentsMonitoringConstants.SNMP_TRAP ? 'SNMP Trap' : 'SNMP Poll'; - } - } export default SoftwareProductComponentsMonitoringView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js new file mode 100644 index 0000000000..865367a734 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreation.js @@ -0,0 +1,51 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import NICCreationActionHelper from './NICCreationActionHelper.js'; +import NICCreationView from './NICCreationView.jsx'; +import SoftwareProductComponentsNetworkActionHelper from '../SoftwareProductComponentsNetworkActionHelper.js'; +import {networkTypes, NIC_CREATION_FORM_NAME} from '../SoftwareProductComponentsNetworkConstants.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; + +export const mapStateToProps = ({softwareProduct}) => { + let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents} = softwareProduct; + let {network: {nicCreation = {}}} = softwareProductComponents; + let {data, genericFieldInfo, formReady} = nicCreation; + data = {...data, networkType: networkTypes.EXTERNAL}; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + + return { + currentSoftwareProduct, + data, + genericFieldInfo, + isFormValid, + formReady + }; +}; + +const mapActionsToProps = (dispatch) => { + return { + onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: NIC_CREATION_FORM_NAME}), + onCancel: () => NICCreationActionHelper.close(dispatch), + onSubmit: ({nic, softwareProductId, componentId, version}) => { + NICCreationActionHelper.close(dispatch); + SoftwareProductComponentsNetworkActionHelper.createNIC(dispatch, {nic, softwareProductId, componentId, version}); + }, + onValidateForm: () => ValidationHelper.validateForm(dispatch, NIC_CREATION_FORM_NAME) + }; +}; + +export default connect(mapStateToProps, mapActionsToProps)(NICCreationView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js new file mode 100644 index 0000000000..ad28c86b81 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationActionHelper.js @@ -0,0 +1,47 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes} from '../SoftwareProductComponentsNetworkConstants'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; + +export default { + + open(dispatch, {softwareProductId, componentId, modalClassName}) { + dispatch({ + type: actionTypes.NICCreation.OPEN + }); + + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.NIC_CREATION, + title: i18n('Create NEW NIC'), + modalClassName, + modalComponentProps: {softwareProductId, componentId} + } + }); + }, + + close(dispatch){ + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + dispatch({ + type: actionTypes.NICCreation.CLEAR_DATA + }); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js new file mode 100644 index 0000000000..c7e2495b3d --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationReducer.js @@ -0,0 +1,49 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes, NIC_CREATION_FORM_NAME} from '../SoftwareProductComponentsNetworkConstants.js'; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.NICCreation.OPEN: + return { + ...state, + data: {}, + formName: NIC_CREATION_FORM_NAME, + formReady: null, + genericFieldInfo: { + 'description' : { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 1000}] + }, + 'name' : { + isValid: true, + errorText: '', + validations: [{type: 'required', data : true}] + }, + 'networkDescription' : { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 50}] + } + } + }; + case actionTypes.NICCreation.CLEAR_DATA: + return {}; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx new file mode 100644 index 0000000000..3cb731a421 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/NICCreation/NICCreationView.jsx @@ -0,0 +1,123 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import Form from 'nfvo-components/input/validation/Form.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + +const NICPropType = React.PropTypes.shape({ + id: React.PropTypes.string, + name: React.PropTypes.string, + description: React.PropTypes.string, + networkId: React.PropTypes.string +}); + +class NICCreationView extends React.Component { + + static propTypes = { + data: NICPropType, + onDataChanged: React.PropTypes.func.isRequired, + onSubmit: React.PropTypes.func.isRequired, + onCancel: React.PropTypes.func.isRequired + }; + + render() { + let {data = {}, onDataChanged, genericFieldInfo, isFormValid, onValidateForm, formReady} = this.props; + let {name, description, networkDescription} = data; + return ( + <div> + {genericFieldInfo && <Form + ref={(form) => this.form = form} + hasButtons={true} + onSubmit={ () => this.submit() } + submitButtonText={data.id ? i18n('Save') : i18n('Create')} + onReset={ () => this.props.onCancel() } + labledButtons={true} + isValid={isFormValid} + onValidateForm={() => onValidateForm()} + formReady={formReady} > + <GridSection> + <GridItem colSpan={4}> + <Input + value={name} + label={i18n('Name')} + data-test-id='nic-name' + onChange={name => onDataChanged({name})} + isRequired={true} + type='text' + isValid={genericFieldInfo['name'].isValid} + errorText={genericFieldInfo['name'].errorText} + className='field-section'/> + <Input + value={description} + label={i18n('Description')} + data-test-id='nic-description' + onChange={description => onDataChanged({description})} + isValid={genericFieldInfo['description'].isValid} + errorText={genericFieldInfo['description'].errorText} + type='textarea' + className='field-section'/> + </GridItem> + </GridSection> + <GridSection title={i18n('Network')}> + <GridItem colSpan={2}> + <div className='form-group'> + <label className='control-label'>{i18n('Network Type')}</label> + <div className='network-type-radio'> + <Input + label={i18n('Internal')} + disabled + checked={false} + data-test-id='nic-internal' + className='network-radio disabled' + type='radio'/> + <Input + label={i18n('External')} + disabled + checked={true} + data-test-id='nic-external' + className='network-radio disabled' + type='radio'/> + </div> + </div> + </GridItem> + <GridItem colSpan={2}> + <Input + value={networkDescription} + label={i18n('Network Description')} + data-test-id='nic-network-description' + onChange={networkDescription => onDataChanged({networkDescription})} + isValid={genericFieldInfo['networkDescription'].isValid} + errorText={genericFieldInfo['networkDescription'].errorText} + type='text' + className='field-section'/> + </GridItem> + </GridSection> + </Form>} + </div> + ); + } + + + submit() { + const {data: nic, softwareProductId, componentId, currentSoftwareProduct} = this.props; + this.props.onSubmit({nic, softwareProductId, componentId, version: currentSoftwareProduct.version}); + } +} + +export default NICCreationView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js index 7cf1f0189e..b47c7e0f99 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditor.js @@ -20,6 +20,7 @@ import VersionControllerUtils from 'nfvo-components/panel/versionController/Vers import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js'; +import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; export const mapStateToProps = ({softwareProduct}) => { @@ -28,6 +29,7 @@ export const mapStateToProps = ({softwareProduct}) => { let {network: {nicEditor = {}}} = softwareProductComponents; let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = nicEditor; let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + let {onboardingMethod} = currentSoftwareProduct; let protocols = []; if(qdata && qdata.protocols && qdata.protocols.protocols && qdata.protocols.protocols.length){ protocols = qdata.protocols.protocols; @@ -47,7 +49,8 @@ export const mapStateToProps = ({softwareProduct}) => { genericFieldInfo, qgenericFieldInfo, isReadOnlyMode, - protocols + protocols, + isManual: onboardingMethod === onboardingMethodTypes.MANUAL }; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js index b3c9fe5d98..dd37135d77 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorReducer.js @@ -18,7 +18,7 @@ import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProdu export default (state = {}, action) => { switch (action.type) { - case actionTypes.NICEditor.OPEN: + case actionTypes.NICEditor.FILL_DATA: return { ...state, data: action.nic, @@ -31,12 +31,17 @@ export default (state = {}, action) => { 'name' : { isValid: true, errorText: '', + validations: [{type: 'required', data : true}] + }, + 'networkDescription' : { + isValid: true, + errorText: '', validations: [] } }, formName: forms.NIC_EDIT_FORM }; - case actionTypes.NICEditor.CLOSE: + case actionTypes.NICEditor.CLEAR_DATA: return {}; default: return state; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx index aad06c82f0..8a4c55a411 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICEditorView.jsx @@ -28,8 +28,9 @@ import NameAndPurpose from './nicEditorComponents/NameAndPurpose.jsx'; class SoftwareProductComponentsNetworkEditorView extends React.Component { render() { - let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, qgenericFieldInfo, dataMap, onDataChanged, protocols, onQDataChanged} = this.props; - let {name, description, networkName} = data; + let {onCancel, onValidateForm, isReadOnlyMode, isFormValid, formReady, data = {}, qgenericFieldInfo, + dataMap, onDataChanged, protocols, onQDataChanged, isManual, genericFieldInfo} = this.props; + let {name, description, networkName, networkType, networkDescription} = data; let netWorkValues = [{ enum: networkName, title: networkName @@ -48,10 +49,10 @@ class SoftwareProductComponentsNetworkEditorView extends React.Component { onValidateForm={() => onValidateForm() } className='vsp-components-network-editor'> <div className='editor-data'> - <NameAndPurpose name={name} description={description} onDataChanged={onDataChanged} isReadOnlyMode={isReadOnlyMode}/> + <NameAndPurpose isManual={isManual} name={name} description={description} onDataChanged={onDataChanged} isReadOnlyMode={isReadOnlyMode} genericFieldInfo={genericFieldInfo} /> <Protocols protocols={protocols} qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> <IpConfig dataMap={dataMap} onQDataChanged={onQDataChanged} /> - <Network networkValues={netWorkValues} /> + <Network networkDescription={networkDescription} onDataChanged={onDataChanged} networkValues={netWorkValues} isReadOnlyMode={isReadOnlyMode} networkType={networkType} /> <Sizing qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> <InFlowTraffic qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> <OutFlowTraffic qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js index bc061469b1..a3cfe65128 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js @@ -15,8 +15,11 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; import {actionTypes} from './SoftwareProductComponentsNetworkConstants.js'; +import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {modalContentMapper as modalPagesMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import {NIC_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js'; @@ -26,6 +29,14 @@ function baseUrl(softwareProductId, version, componentId) { return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components/${componentId}/nics`; } +function createNIC({nic, vspId, componentId, version}) { + return RestAPIUtil.post(baseUrl(vspId, version, componentId), { + name: nic.name, + description: nic.description, + networkDescription: nic.networkDescription, + networkType: nic.networkType + }); +} function fetchNICQuestionnaire({softwareProductId, version, componentId, nicId}) { return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${nicId}/questionnaire`); @@ -39,11 +50,16 @@ function fetchNICsList({softwareProductId, version, componentId}) { return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`); } -function saveNIC({softwareProductId, version, componentId, nic: {id, name, description, networkId}}) { +function deleteNIC({softwareProductId, componentId, nicId, version}) { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${nicId}`); +} +function saveNIC({softwareProductId, version, componentId, nic: {id, name, description, networkId, networkType, networkDescription}}) { return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${id}`,{ name, description, - networkId + networkId, + networkDescription, + networkType }); } @@ -62,23 +78,45 @@ const SoftwareProductComponentNetworkActionHelper = { }); }, - openNICEditor(dispatch, {nic = {}, data = {}}) { + openNICEditor(dispatch, {nic = {}, data = {}, softwareProductId, componentId, isReadOnlyMode, modalClassName}) { dispatch({ - type: actionTypes.NICEditor.OPEN, + type: actionTypes.NICEditor.FILL_DATA, nic: {...data, id: nic.id} }); + dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_SHOW, + data: { + modalClassName, + modalComponentProps: {softwareProductId, componentId, isReadOnlyMode}, + modalComponentName: modalPagesMapper.NIC_EDITOR, + title: i18n('Edit NIC') + } + }); }, closeNICEditor(dispatch) { dispatch({ - type: actionTypes.NICEditor.CLOSE + type: GlobalModalActions.GLOBAL_MODAL_CLOSE + }); + dispatch({ + type: actionTypes.NICEditor.CLEAR_DATA }); }, + createNIC(dispatch, {nic, softwareProductId, componentId, version}){ + return createNIC({nic, vspId: softwareProductId, componentId, version}).then(() => { + return SoftwareProductComponentNetworkActionHelper.fetchNICsList(dispatch, {softwareProductId, componentId, version}); + }); + }, loadNICData({softwareProductId, version, componentId, nicId}) { return fetchNIC({softwareProductId, version, componentId, nicId}); }, + deleteNIC(dispatch, {softwareProductId, componentId, nicId, version}) { + return deleteNIC({softwareProductId, componentId, nicId, version}).then(() => { + return SoftwareProductComponentNetworkActionHelper.fetchNICsList(dispatch, {softwareProductId, componentId, version}); + }); + }, loadNICQuestionnaire(dispatch, {softwareProductId, version, componentId, nicId}) { return fetchNICQuestionnaire({softwareProductId, version, componentId, nicId}).then((response) => { ValidationHelper.qDataLoaded(dispatch, {qName: NIC_QUESTIONNAIRE ,response: { diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js index 39c55d876c..8ef8fe8c18 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.js @@ -20,9 +20,19 @@ export const actionTypes = keyMirror({ NIC_LIST_UPDATE: null, NICEditor: { + FILL_DATA: null, + CLEAR_DATA: null, + }, + NICCreation: { OPEN: null, - CLOSE: null - } + CLEAR_DATA: null, + DATA_CHANGED: null + }, }); +export const networkTypes = { + EXTERNAL: 'External', + INTERNAL: 'Internal' +}; export const NIC_QUESTIONNAIRE = 'nic'; +export const NIC_CREATION_FORM_NAME = 'nicCreation'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js index c2bd8ce479..0fa877e90f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkList.js @@ -14,6 +14,7 @@ * permissions and limitations under the License. */ import {connect} from 'react-redux'; +import i18n from 'nfvo-utils/i18n/i18n.js'; import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; @@ -21,16 +22,17 @@ import SoftwareProductComponentsNetworkListView from './SoftwareProductComponent import SoftwareProductComponentsNetworkActionHelper from './SoftwareProductComponentsNetworkActionHelper.js'; import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; +import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import NICCreationActionHelper from './NICCreation/NICCreationActionHelper.js'; +import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; export const mapStateToProps = ({softwareProduct}) => { let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; - let {network: {nicEditor = {}, nicList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; - let {data} = nicEditor; + let {network: {nicList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); - let {version} = currentSoftwareProduct; - let isModalInEditMode = true; + let {version, onboardingMethod} = currentSoftwareProduct; return { version, @@ -40,9 +42,8 @@ export const mapStateToProps = ({softwareProduct}) => { qgenericFieldInfo, isValidityData, nicList, - isDisplayModal: Boolean(data), - isModalInEditMode, - isReadOnlyMode + isReadOnlyMode, + isManual: onboardingMethod === onboardingMethodTypes.MANUAL }; }; @@ -51,7 +52,16 @@ const mapActionsToProps = (dispatch, {softwareProductId, componentId}) => { return { onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_QUESTIONNAIRE}), - onEditNicClick: (nic, version) => { + onAddNic: () => NICCreationActionHelper.open(dispatch, {softwareProductId, componentId, modalClassName: 'network-nic-modal-create'}), + onDeleteNic: (nic, version) => dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_WARNING, + data:{ + msg: i18n(`Are you sure you want to delete "${nic.name}"?`), + onConfirmed: () => SoftwareProductComponentsNetworkActionHelper.deleteNIC(dispatch, {softwareProductId, + componentId, nicId: nic.id, version}) + } + }), + onEditNicClick: (nic, version, isReadOnlyMode) => { Promise.all([ SoftwareProductComponentsNetworkActionHelper.loadNICData({ softwareProductId, @@ -66,7 +76,8 @@ const mapActionsToProps = (dispatch, {softwareProductId, componentId}) => { nicId: nic.id }) ]).then( - ([{data}]) => SoftwareProductComponentsNetworkActionHelper.openNICEditor(dispatch, {nic, data}) + ([{data}]) => SoftwareProductComponentsNetworkActionHelper.openNICEditor(dispatch, {nic, data, + isReadOnlyMode, softwareProductId, componentId, modalClassName: 'network-nic-modal-edit'}) ); }, onSubmit: ({qdata, version}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx index f715016ba3..5a159b4a87 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkListView.jsx @@ -21,9 +21,7 @@ import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; import Input from'nfvo-components/input/validation/Input.jsx'; -import Modal from 'nfvo-components/modal/Modal.jsx'; -import SoftwareProductComponentsNICEditor from './SoftwareProductComponentsNICEditor.js'; class SoftwareProductComponentsNetworkView extends React.Component { @@ -32,7 +30,7 @@ class SoftwareProductComponentsNetworkView extends React.Component { }; render() { - let {dataMap, qgenericFieldInfo, onQDataChanged, isModalInEditMode, isDisplayModal, softwareProductId, componentId, isReadOnlyMode} = this.props; + let {dataMap, qgenericFieldInfo, onQDataChanged, isReadOnlyMode} = this.props; return( <div className='vsp-components-network'> @@ -85,26 +83,14 @@ class SoftwareProductComponentsNetworkView extends React.Component { </div> {this.renderNicList()} </div> - <Modal show={isDisplayModal} bsSize='large' animation={true} className='network-nic-modal'> - <Modal.Header> - <Modal.Title>{isModalInEditMode ? i18n('Edit NIC') : i18n('Create New NIC')}</Modal.Title> - </Modal.Header> - <Modal.Body> - { - <SoftwareProductComponentsNICEditor - softwareProductId={softwareProductId} - componentId={componentId} - isReadOnlyMode={isReadOnlyMode}/> - } - </Modal.Body> - </Modal> + </div> ); } renderNicList() { const {localFilter} = this.state; - let {isReadOnlyMode} = this.props; + let {isReadOnlyMode, onAddNic, isManual} = this.props; return ( <ListEditorView title={i18n('Interfaces')} @@ -112,6 +98,8 @@ class SoftwareProductComponentsNetworkView extends React.Component { placeholder={i18n('Filter NICs by Name')} isReadOnlyMode={isReadOnlyMode} onFilter={value => this.setState({localFilter: value})} + onAdd={isManual ? onAddNic : null} + plusButtonTitle={i18n('Add NIC')} twoColumns> {this.filterList().map(nic => this.renderNicListItem(nic, isReadOnlyMode))} </ListEditorView> @@ -120,25 +108,26 @@ class SoftwareProductComponentsNetworkView extends React.Component { renderNicListItem(nic, isReadOnlyMode) { let {id, name, description, networkName = ''} = nic; - let {onEditNicClick, version} = this.props; + let {onEditNicClick, version, isManual, onDeleteNic} = this.props; return ( <ListEditorItemView key={id} isReadOnlyMode={isReadOnlyMode} - onSelect={() => onEditNicClick(nic, version)}> + onSelect={() => onEditNicClick(nic, version, isReadOnlyMode)} + onDelete={isManual ? () => onDeleteNic(nic, version) : null}> <ListEditorItemViewField> <div className='name'>{name}</div> </ListEditorItemViewField> <ListEditorItemViewField> - <div className='details'> - <div className='title'>{i18n('Purpose of NIC')}</div> - <div className='description'>{description}</div> + <div className={isManual ? 'details-col' : 'details'}> + <div className={isManual ? 'manual-title' : 'title'}>{i18n('Purpose of NIC')}</div> + <div className={isManual ? 'description' : ''}>{description ? description : i18n('N/A')}</div> </div> - <div className='details'> + {!isManual && <div className='details'> <div className='title'>{i18n('Network')}</div> <div className='artifact-name'>{networkName}</div> - </div> + </div>} </ListEditorItemViewField> </ListEditorItemView> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx index 3dc153d27f..bc692e753c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/NameAndPurpose.jsx @@ -19,7 +19,7 @@ import Input from 'nfvo-components/input/validation/Input.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -const NameAndPurpose = ({onDataChanged, isReadOnlyMode, name, description}) => { +const NameAndPurpose = ({onDataChanged, genericFieldInfo, isReadOnlyMode, name, description, isManual}) => { return ( <GridSection> @@ -28,7 +28,11 @@ const NameAndPurpose = ({onDataChanged, isReadOnlyMode, name, description}) => { label={i18n('Name')} value={name} data-test-id='nic-name' - disabled={true} + disabled={!isManual} + isRequired={true} + onChange={name => onDataChanged({name})} + isValid={genericFieldInfo['name'].isValid} + errorText={genericFieldInfo['name'].errorText} type='text' /> </GridItem> <GridItem colSpan={2}> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx index 43afdbed3a..8d9b79e67f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Network.jsx @@ -18,15 +18,17 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; +import { networkTypes } from '../SoftwareProductComponentsNetworkConstants.js'; -const Network = ({networkValues}) => { +const Network = ({networkValues, networkType, networkDescription, onDataChanged, isReadOnlyMode}) => { + const isExternal = networkType === networkTypes.EXTERNAL; return ( <GridSection title={i18n('Network')}> <GridItem> <Input label={i18n('Internal')} disabled - checked={true} + checked={!isExternal} data-test-id='nic-internal' className='network-radio disabled' type='radio'/> @@ -35,12 +37,21 @@ const Network = ({networkValues}) => { <Input label={i18n('External')} disabled - checked={false} + checked={isExternal} data-test-id='nic-external' className='network-radio disabled' type='radio'/> </GridItem> <GridItem colSpan={2}> + {isExternal ? + <Input + label={i18n('Network Description')} + value={networkDescription} + data-test-id='nic-network-description' + onChange={networkDescription => onDataChanged({networkDescription})} + disabled={isReadOnlyMode} + type='text'/> + : <Input label={i18n('Network')} data-test-id='nic-network' @@ -48,8 +59,8 @@ const Network = ({networkValues}) => { className='input-options-select' groupClassName='bootstrap-input-options' disabled={true} > - {networkValues.map(val => <option key={val.enum} value={val.enum}>{val.title}</option>)} - </Input> + {networkValues.map(val => <option key={val.enum} value={val.enum}>{val.title}</option>)} + </Input>} </GridItem> </GridSection> ); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js index a8cb709194..826201162c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesList.js @@ -47,7 +47,7 @@ const mapActionsToProps = (dispatch, {componentId, softwareProductId}) => { onDeleteProcessClick: (process, version) => dispatch({ type: modalActionTypes.GLOBAL_MODAL_WARNING, data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}), + msg: i18n(`Are you sure you want to delete "${process.name}"?`), onConfirmed: ()=> SoftwareProductComponentProcessesActionHelper.deleteProcess(dispatch, {process, softwareProductId, version, componentId}) } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx index 650d6d5ebc..93d5ce886a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentsProcessesListView.jsx @@ -44,7 +44,7 @@ class SoftwareProductProcessesView extends React.Component { return ( <div className='vsp-processes-page'> <div className='software-product-view'> - <div className='software-product-landing-view-right-side flex-column'> + <div className='software-product-landing-view-right-side vsp-components-processes-page flex-column'> {this.renderEditor()} {this.renderProcessList()} </div> diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js index 3b434e3ba4..a22b517fa0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js @@ -17,7 +17,7 @@ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {actionTypes as modalActionTypes, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js'; import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; import {actionTypes} from './SoftwareProductCreationConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; @@ -48,9 +48,10 @@ const SoftwareProductCreationActionHelper = { type: modalActionTypes.GLOBAL_MODAL_SHOW, data: { modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_CREATION, - title: i18n('New Software Product'), + title: i18n('New Software Product'), modalComponentProps: { - vendorId + vendorId, + size: modalSizes.LARGE } } }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js index f7a738518e..a7db2b2357 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js @@ -15,6 +15,7 @@ */ import {actionTypes, SP_CREATION_FORM_NAME} from './SoftwareProductCreationConstants.js'; + export default (state = {}, action) => { switch (action.type) { case actionTypes.OPEN: @@ -50,6 +51,11 @@ export default (state = {}, action) => { isValid: true, errorText: '', validations: [{type: 'required', data: true}, {type: 'maxLength', data: 25}, {type: 'validateName', data: true}] + }, + 'onboardingMethod' : { + isValid: true, + errorText: '', + validations: [{type: 'requiredChooseOption', data: true}] } }, showModal: true diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx index 11b696855b..11f3543e39 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx @@ -18,10 +18,14 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import Validator from 'nfvo-utils/Validator.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; import Form from 'nfvo-components/input/validation/Form.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; + import {SP_CREATION_FORM_NAME} from './SoftwareProductCreationConstants.js'; import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js'; import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js'; +import {onboardingMethod as onboardingMethodConst} from '../SoftwareProductConstants.js'; const SoftwareProductPropType = React.PropTypes.shape({ id: React.PropTypes.string, @@ -46,7 +50,7 @@ class SoftwareProductCreationView extends React.Component { render() { let {softwareProductCategories, data = {}, onDataChanged, onCancel, genericFieldInfo, disableVendor} = this.props; - let {name, description, vendorId, subCategory} = data; + let {name, description, vendorId, subCategory, onboardingMethod} = data; const vendorList = this.getVendorList(); return ( @@ -58,10 +62,11 @@ class SoftwareProductCreationView extends React.Component { onReset={() => onCancel() } labledButtons={true} isValid={this.props.isFormValid} + submitButtonText={i18n('Create')} formReady={this.props.formReady} onValidateForm={() => this.validate() }> - <div className='software-product-form-row'> - <div className='software-product-inline-section'> + <GridSection> + <GridItem colSpan='2'> <Input value={name} label={i18n('Name')} @@ -76,6 +81,7 @@ class SoftwareProductCreationView extends React.Component { label={i18n('Vendor')} type='select' value={vendorId} + overlayPos='bottom' isRequired={true} disabled={disableVendor} onChange={e => this.onSelectVendor(e)} @@ -108,8 +114,8 @@ class SoftwareProductCreationView extends React.Component { </optgroup>) } </Input> - </div> - <div className='software-product-inline-section'> + </GridItem> + <GridItem colSpan='2' stretch> <Input value={description} label={i18n('Description')} @@ -120,9 +126,10 @@ class SoftwareProductCreationView extends React.Component { errorText={genericFieldInfo.description.errorText} type='textarea' className='field-section' - data-test-id='new-vsp-description' /> - </div> - </div> + data-test-id='new-vsp-description'/> + </GridItem> + </GridSection> + <OnboardingProcedure genericFieldInfo={genericFieldInfo} onboardingMethod={onboardingMethod} onDataChanged={onDataChanged} /> </Form>} </div> ); @@ -174,4 +181,33 @@ class SoftwareProductCreationView extends React.Component { } } +const OnboardingProcedure = ({onboardingMethod, onDataChanged, genericFieldInfo}) => { + return( + <GridSection title={i18n('Onboarding procedure')}> + <GridItem colSpan={4}> + <Input + label={i18n('HEAT file')} + overlayPos='top' + isValid={genericFieldInfo.onboardingMethod.isValid} + checked={onboardingMethod === onboardingMethodConst.HEAT} + errorText={genericFieldInfo.onboardingMethod.errorText} + onChange={() => onDataChanged({onboardingMethod:'HEAT'},SP_CREATION_FORM_NAME)} + type='radio' + data-test-id='new-vsp-creation-procedure-heat' /> + </GridItem> + <GridItem colSpan={4}> + <Input + label={i18n('Manual')} + overlayPos='bottom' + checked={onboardingMethod === onboardingMethodConst.MANUAL} + isValid={genericFieldInfo.onboardingMethod.isValid} + errorText={genericFieldInfo.onboardingMethod.errorText} + onChange={() => onDataChanged({onboardingMethod:'Manual'},SP_CREATION_FORM_NAME)} + type='radio' + data-test-id='new-vsp-creation-procedure-manual' /> + </GridItem> + </GridSection> + ); +}; + export default SoftwareProductCreationView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx index da975a7be2..2e0cd340de 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx @@ -60,6 +60,7 @@ export default class SoftwareProductDependenciesView extends React.Component { <div className='software-product-dependencies-title'>{i18n('Dependencies')}</div> <SelectActionTable columns={['Source', 'Relation Type', 'Target']} + numOfIcons={2} isReadOnlyMode={isReadOnlyMode} onAdd={canAdd ? onAddDependency : undefined} onAddItem={i18n('Add Rule')}> @@ -68,7 +69,8 @@ export default class SoftwareProductDependenciesView extends React.Component { key={dependency.id} onDelete={() => onDataChanged(softwareProductDependencies.filter(currentDependency => currentDependency.id !== dependency.id))} overlayMsg={i18n('There is a loop between selections')} - hasError={dependency.hasCycle}> + hasError={dependency.hasCycle} + hasErrorIndication> <SelectActionTableCell options={this.filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})} selected={dependency.sourceId} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js new file mode 100644 index 0000000000..98f773b465 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js @@ -0,0 +1,52 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import SoftwareProductDeploymentView from './SoftwareProductDeploymentView.jsx'; +import SoftwareProductDeploymentActionHelper from './SoftwareProductDeploymentActionHelper.js'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; + +export function mapStateToProps({softwareProduct}) { + let {softwareProductEditor: {data: currentSoftwareProduct = {}},softwareProductComponents: {componentsList}, softwareProductDeployment: {deploymentFlavors}} = softwareProduct; + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + return { + isReadOnlyMode, + deploymentFlavors, + componentsList + }; +} + +function mapActionToProps(dispatch, {softwareProductId, version}) { + let modalClassName = 'deployment-flavor-editor'; + return { + onAddDeployment: componentsList => SoftwareProductDeploymentActionHelper.openDeploymentFlavorEditor(dispatch, {softwareProductId, modalClassName, componentsList, version}), + onDeleteDeployment: ({id, model}) => dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data:{ + msg: i18n(`Are you sure you want to delete "${model}"?`), + onConfirmed: () => SoftwareProductDeploymentActionHelper.deleteDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId: id, version}) + } + }), + onEditDeployment: (deploymentFlavor, componentsList) => + SoftwareProductDeploymentActionHelper.fetchDeploymentFlavor({softwareProductId, deploymentFlavorId: deploymentFlavor.id, version}).then(response => + SoftwareProductDeploymentActionHelper + .openDeploymentFlavorEditor(dispatch, {softwareProductId, componentsList, modalClassName, deploymentFlavor: {...response.data, id: response.id}, isEdit: true, version}), + ) + }; +} + +export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(SoftwareProductDeploymentView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js new file mode 100644 index 0000000000..bd802b38f4 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js @@ -0,0 +1,101 @@ +import {actionTypes} from './SoftwareProductDeploymentConstants.js'; +import {actionTypes as GlobalModalActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; +import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import pickBy from 'lodash/pickBy'; + +function baseUrl(vspId, version) { + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/deployment-flavors`; +} + +function fetchDeploymentFlavorsList({softwareProductId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); +} + +function fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`); +} + +function deleteDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) { + return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`); +} + +function createDeploymentFlavor({softwareProductId, data, version}) { + return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, data); +} + +function editDeploymentFlavor({softwareProductId, deploymentFlavorId, data, version}) { + return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`, data); +} + +const SoftwareProductDeploymentActionHelper = { + fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}) { + return fetchDeploymentFlavorsList({softwareProductId, version}).then(response => { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS, + deploymentFlavors: response.results + }); + }); + }, + + fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) { + return fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}); + }, + + deleteDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId, version}) { + return deleteDeploymentFlavor({softwareProductId, deploymentFlavorId, version}).then(() => { + return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}); + }); + }, + + createDeploymentFlavor(dispatch, {softwareProductId, data, version}) { + return createDeploymentFlavor({softwareProductId, data, version}).then(() => { + return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}); + }); + }, + + editDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId, data, version}) { + let dataWithoutId = pickBy(data, (val, key) => key !== 'id'); + return editDeploymentFlavor({softwareProductId, deploymentFlavorId, data: dataWithoutId, version}).then(() => { + return SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}); + }); + }, + + closeDeploymentFlavorEditor(dispatch) { + dispatch({ + type: actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA + }); + dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_CLOSE + }); + }, + + openDeploymentFlavorEditor(dispatch, {softwareProductId, modalClassName, deploymentFlavor = {}, componentsList, isEdit = false, version}) { + let alteredDeploymentFlavor = {...deploymentFlavor}; + if (componentsList.length) { + alteredDeploymentFlavor = {...alteredDeploymentFlavor, componentComputeAssociations: deploymentFlavor.componentComputeAssociations ? + [{...deploymentFlavor.componentComputeAssociations[0], componentId: componentsList[0].id}] + : + [{componentId: componentsList[0].id, computeFlavorId: null}] + }; + } + dispatch({ + type: actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA, + deploymentFlavor: alteredDeploymentFlavor + }); + dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.DEPLOYMENT_FLAVOR_EDITOR, + modalComponentProps: {softwareProductId, version}, + modalClassName, + title: isEdit ? 'Edit Deployment Flavor' : 'Create a New Deployment Flavor' + } + }); + }, +}; + +export default SoftwareProductDeploymentActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js new file mode 100644 index 0000000000..51469b461c --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js @@ -0,0 +1,28 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import keyMirror from 'nfvo-utils/KeyMirror.js'; + +export const actionTypes = keyMirror({ + FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS: null, + + deploymentFlavorEditor: { + DATA_CHANGED: null, + SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA: null, + SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA: null + } +}); + +export const DEPLOYMENT_FLAVORS_FORM_NAME = 'DEPLOYMENT_FLAVORS_FORM_NAME'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js new file mode 100644 index 0000000000..8eb91e8fcb --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js @@ -0,0 +1,25 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes} from './SoftwareProductDeploymentConstants.js'; + +export default (state = [], action) => { + switch (action.type) { + case actionTypes.FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS: + return [...action.deploymentFlavors]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx new file mode 100644 index 0000000000..81477ecff7 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx @@ -0,0 +1,94 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; + +import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; +import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; +import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; + +export default class SoftwareProductDeployment extends React.Component { + state = { + localFilter: '' + }; + + static propTypes = { + onAddDeployment: React.PropTypes.func.isRequired, + onDeleteDeployment: React.PropTypes.func.isRequired, + onEditDeployment: React.PropTypes.func.isRequired, + isReadOnlyMode: React.PropTypes.bool.isRequired + }; + + render() { + return ( + <div> + {this.renderList()} + </div> + ); + } + + renderList() { + let {onAddDeployment, isReadOnlyMode, componentsList} = this.props; + return ( + <ListEditorView + plusButtonTitle={i18n('Add Deployment Flavor')} + filterValue={this.state.localFilter} + placeholder={i18n('Filter Deployment')} + onAdd={() => onAddDeployment(componentsList)} + isReadOnlyMode={isReadOnlyMode} + title={i18n('Deployment Flavors')} + onFilter={value => this.setState({localFilter: value})} + twoColumns> + {this.filterList().map(deploymentFlavor => this.renderListItem(deploymentFlavor, isReadOnlyMode))} + </ListEditorView> + ); + } + + renderListItem(deploymentFlavor, isReadOnlyMode) { + let {id, model, description} = deploymentFlavor; + let {onEditDeployment, onDeleteDeployment, componentsList} = this.props; + return ( + <ListEditorItemView + key={id} + className='list-editor-item-view' + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditDeployment(deploymentFlavor, componentsList)} + onDelete={() => onDeleteDeployment(deploymentFlavor)}> + <ListEditorItemViewField> + <div className='model'>{model}</div> + </ListEditorItemViewField> + <ListEditorItemViewField> + <div className='description'>{description}</div> + </ListEditorItemViewField> + </ListEditorItemView> + ); + } + + filterList() { + let {deploymentFlavors} = this.props; + let {localFilter} = this.state; + + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return deploymentFlavors.filter(({model = '', description = ''}) => { + return escape(model).match(filter) || escape(description).match(filter); + }); + } + else { + return deploymentFlavors; + } + } +} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js new file mode 100644 index 0000000000..6b924a2816 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js @@ -0,0 +1,88 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {connect} from 'react-redux'; +import SoftwareProductDeploymentEditorView from './SoftwareProductDeploymentEditorView.jsx'; +import SoftwareProdcutDeploymentActionHelper from '../SoftwareProductDeploymentActionHelper.js'; +import VersionControllerUtils from 'nfvo-components/panel/versionController/VersionControllerUtils.js'; +import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; + +import {DEPLOYMENT_FLAVORS_FORM_NAME} from '../SoftwareProductDeploymentConstants.js'; + +export function mapStateToProps({licenseModel, softwareProduct}) { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {} + }, + softwareProductComponents: { + componentsList, + computeFlavor: { + computesList + } + }, + softwareProductDeployment: { + deploymentFlavors, + deploymentFlavorEditor: { + data = {}, + genericFieldInfo, + formReady + } + } + } = softwareProduct; + + let { + featureGroup: { + featureGroupsList + } + } = licenseModel; + + let isReadOnlyMode = VersionControllerUtils.isReadOnly(currentSoftwareProduct); + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + let selectedFeatureGroupsIds = currentSoftwareProduct.licensingData ? currentSoftwareProduct.licensingData.featureGroups || [] : []; + let selectedFeatureGroupsList = featureGroupsList + .filter(featureGroup => selectedFeatureGroupsIds.includes(featureGroup.id)) + .map(featureGroup => ({value: featureGroup.id, label: featureGroup.name})); + + let DFNames = {}; + + deploymentFlavors.map(deployment => { + DFNames[deployment.model] = deployment.id; + }); + + return { + data, + selectedFeatureGroupsList, + genericFieldInfo, + DFNames, + isFormValid, + formReady, + isReadOnlyMode, + componentsList, + computesList, + isEdit: Boolean(data.id) + }; +} + +function mapActionsToProps(dispatch, {softwareProductId, version}) { + return { + onDataChanged: (deltaData, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: DEPLOYMENT_FLAVORS_FORM_NAME, customValidations}), + onClose: () => SoftwareProdcutDeploymentActionHelper.closeDeploymentFlavorEditor(dispatch), + onCreate: data => SoftwareProdcutDeploymentActionHelper.createDeploymentFlavor(dispatch, {softwareProductId, data, version}), + onEdit: data => SoftwareProdcutDeploymentActionHelper.editDeploymentFlavor(dispatch, {softwareProductId, deploymentFlavorId: data.id, data, version}), + onValidateForm: () => ValidationHelper.validateForm(dispatch, DEPLOYMENT_FLAVORS_FORM_NAME) + }; +} + +export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductDeploymentEditorView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js new file mode 100644 index 0000000000..70836e8ff9 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js @@ -0,0 +1,44 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {actionTypes, DEPLOYMENT_FLAVORS_FORM_NAME} from '../SoftwareProductDeploymentConstants.js';; + +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA: + return { + ...state, + data: action.deploymentFlavor, + formReady: null, + formName: DEPLOYMENT_FLAVORS_FORM_NAME, + genericFieldInfo: { + 'description' : { + isValid: true, + errorText: '', + validations: [{type: 'maxLength', data: 500}] + }, + 'model' : { + isValid: true, + errorText: '', + validations: [{type: 'required', data: true}] + } + } + }; + case actionTypes.deploymentFlavorEditor.SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA: + return {}; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx new file mode 100644 index 0000000000..2d621cd2f5 --- /dev/null +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx @@ -0,0 +1,137 @@ +import React from 'react'; +import i18n from 'nfvo-utils/i18n/i18n.js'; +import Input from 'nfvo-components/input/validation/Input.jsx'; +import Form from 'nfvo-components/input/validation/Form.jsx'; +import GridSection from 'nfvo-components/grid/GridSection.jsx'; +import GridItem from 'nfvo-components/grid/GridItem.jsx'; +import SelectInput from 'nfvo-components/input/SelectInput.jsx'; +import SelectActionTable from 'nfvo-components/table/SelectActionTable.jsx'; +import SelectActionTableRow from 'nfvo-components/table/SelectActionTableRow.jsx'; +import SelectActionTableCell from 'nfvo-components/table/SelectActionTableCell.jsx'; +import Validator from 'nfvo-utils/Validator.js'; + +export default class SoftwareProductDeploymentEditorView extends React.Component { + render() { + let {data, isEdit, onClose, onDataChanged, isReadOnlyMode, selectedFeatureGroupsList, componentsList, computesList, genericFieldInfo} = this.props; + let {model, description, featureGroupId, componentComputeAssociations = []} = data; + let featureGroupsExist = selectedFeatureGroupsList.length > 0; + return ( + <div> + {genericFieldInfo && <Form + ref='validationForm' + hasButtons={true} + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + onSubmit={ () => this.submit() } + submitButtonText={isEdit ? i18n('Save') : i18n('Create')} + onReset={ () => onClose() } + onValidateForm={() => this.validate() } + isValid={this.props.isFormValid} + formReady={this.props.formReady} + className='vsp-deployment-editor'> + <GridSection> + <GridItem colSpan={1}> + <Input + onChange={model => onDataChanged({model}, {model: model => this.validateName(model)})} + label={i18n('Model')} + value={model} + data-test-id='deployment-model' + isValid={genericFieldInfo.model.isValid} + errorText={genericFieldInfo.model.errorText} + isRequired={true} + type='text'/> + </GridItem> + <GridItem colSpan={3}> + <Input + onChange={description => onDataChanged({description})} + label={i18n('Description')} + value={description} + data-test-id='deployment-description' + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + type='text'/> + </GridItem> + </GridSection> + <GridSection className={`deployment-feature-groups-section${!featureGroupsExist ? ' no-feature-groups' : ''}`} title={i18n('License Details')}> + <GridItem colSpan={1}> + <SelectInput + data-test-id='deployment-feature-groups' + label={i18n('Feature Group')} + value={featureGroupId} + onChange={featureGroup => onDataChanged({featureGroupId: featureGroup ? featureGroup.value : null})} + type='select' + clearable={true} + disabled={isReadOnlyMode || !featureGroupsExist} + className='field-section' + options={selectedFeatureGroupsList}/> + </GridItem> + </GridSection> + {!featureGroupsExist && <GridSection className='deployment-feature-group-warning-section'> + <GridItem colSpan={3}> + <span>{i18n('Please assign Feature Groups in VSP General')}</span> + </GridItem> + </GridSection>} + <GridSection title={i18n('Assign VFCs and Compute Flavors')} className='vfc-table'> + <GridItem colSpan={4}> + <SelectActionTable + columns={['Virtual Function Components', 'Compute Flavors']} + numOfIcons={0}> + {componentComputeAssociations.map( (association, index) => + <SelectActionTableRow key={association.componentId}> + <SelectActionTableCell + options={ + componentsList + .map(component => ({value: component.id, label: component.displayName}) ) + } + selected={association.componentId} + onChange={componentId => { + let newAssociations = [...componentComputeAssociations]; + newAssociations[index] = {...newAssociations[index], componentId}; + onDataChanged({componentComputeAssociations: newAssociations}); + }} + disabled={true}/> + <SelectActionTableCell + options={ + computesList + .filter(compute => compute.componentId === association.componentId) + .map(compute => ({value: compute.computeFlavorId, label: compute.name}) ) + } + selected={association.computeFlavorId} + onChange={computeFlavorId => { + let newAssociations = [...componentComputeAssociations]; + newAssociations[index] = {...newAssociations[index], computeFlavorId}; + onDataChanged({componentComputeAssociations: newAssociations}); + }} + disabled={isReadOnlyMode}/> + </SelectActionTableRow> + )} + </SelectActionTable> + </GridItem> + </GridSection> + </Form>} + </div> + ); + } + + validateName(value) { + const {data: {id = ''}, DFNames} = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: DFNames}); + + return !isExists ? {isValid: true, errorText: ''} : + {isValid: false, errorText: i18n('Deployment flavor by the name \'' + value + '\' already exists. Deployment flavor name must be unique')}; + } + + submit(){ + let {isEdit, onCreate, onEdit, onClose, data} = this.props; + if (isEdit) { + onEdit(data); + } else { + onCreate(data); + } + onClose(); + } + + validate() { + this.props.onValidateForm(); + } +} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx index 1d52da38b0..98dd7730bd 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx @@ -65,7 +65,7 @@ class GeneralSection extends React.Component { isRequired={true} errorText={genericFieldInfo.name.errorText} isValid={genericFieldInfo.name.isValid} - onChange={name => this.props.onDataChanged({name}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/> + onChange={name => name.length <= 25 && this.props.onDataChanged({name}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/> <Input data-test-id='vsp-vendor-name' label={i18n('Vendor')} diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js index e8091bf8d1..8806ffd0bf 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js @@ -20,6 +20,7 @@ import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; import LandingPageView from './SoftwareProductLandingPageView.jsx'; import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import {onboardingMethod} from '../SoftwareProductConstants.js'; export const mapStateToProps = ({softwareProduct, licenseModel: {licenseAgreement}}) => { let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents, softwareProductCategories = []} = softwareProduct; @@ -52,7 +53,8 @@ export const mapStateToProps = ({softwareProduct, licenseModel: {licenseAgreemen fullCategoryDisplayName }, isReadOnlyMode, - componentsList + componentsList, + isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL }; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx index 5fbf1b74b0..d3738e3ea4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx @@ -19,11 +19,10 @@ import Dropzone from 'react-dropzone'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; -import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; -import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; -import SVGIcon from 'nfvo-components/icon/SVGIcon.jsx'; + +import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; +import SoftwareProductComponentsList from '../components/SoftwareProductComponentsList.js'; const SoftwareProductPropType = React.PropTypes.shape({ name: React.PropTypes.string, @@ -47,7 +46,7 @@ const ComponentPropType = React.PropTypes.shape({ class SoftwareProductLandingPageView extends React.Component { state = { - localFilter: '', + fileName: '', dragging: false, files: [] @@ -67,13 +66,13 @@ class SoftwareProductLandingPageView extends React.Component { }; render() { - let {currentSoftwareProduct, isReadOnlyMode, componentsList = []} = this.props; + let {currentSoftwareProduct, isReadOnlyMode, isManual, onDetailsSelect, componentsList} = this.props; return ( <div className='software-product-landing-wrapper'> <Dropzone className={classnames('software-product-landing-view', {'active-dragging': this.state.dragging})} - onDrop={files => this.handleImportSubmit(files, isReadOnlyMode)} - onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)} + onDrop={files => this.handleImportSubmit(files, isReadOnlyMode, isManual)} + onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode, isManual)} onDragLeave={() => this.setState({dragging:false})} multiple={false} disableClick={true} @@ -84,68 +83,29 @@ class SoftwareProductLandingPageView extends React.Component { <div className='draggable-wrapper'> <div className='software-product-landing-view-top'> <div className='row'> - {this.renderProductSummary(currentSoftwareProduct)} - {this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)} + <ProductSummary currentSoftwareProduct={currentSoftwareProduct} onDetailsSelect={onDetailsSelect} /> + {isManual ? + <div className='details-panel'/> + : this.renderProductDetails(currentSoftwareProduct, isReadOnlyMode)} </div> </div> </div> </Dropzone> - { - componentsList.length > 0 && this.renderComponents() - } + <SoftwareProductComponentsList + isReadOnlyMode={isReadOnlyMode} + componentsList={componentsList} + isManual={isManual} + currentSoftwareProduct={currentSoftwareProduct}/> </div> ); } - handleOnDragEnter(isReadOnlyMode) { - if (!isReadOnlyMode) { + handleOnDragEnter(isReadOnlyMode, isManual) { + if (!isReadOnlyMode && !isManual) { this.setState({dragging: true}); } } - renderProductSummary(currentSoftwareProduct) { - let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''} = currentSoftwareProduct; - let {onDetailsSelect} = this.props; - return ( - <div className='details-panel'> - <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div> - <div - className='software-product-landing-view-top-block clickable' - onClick={() => onDetailsSelect(currentSoftwareProduct)}> - <div className='details-container'> - <div className='single-detail-section title-section'> - <div className='single-detail-section title-text'> - {name} - </div> - </div> - <div className='details-section'> - <div className='multiple-details-section'> - <div className='detail-col' > - <div className='title'>{i18n('Vendor')}</div> - <div className='description'>{vendorName}</div> - </div> - <div className='detail-col'> - <div className='title'>{i18n('Category')}</div> - <div className='description'>{fullCategoryDisplayName}</div> - </div> - <div className='detail-col'> - <div className='title extra-large'>{i18n('License Agreement')}</div> - <div className='description'> - {this.renderLicenseAgreement(licenseAgreementName)} - </div> - </div> - </div> - <div className='single-detail-section'> - <div className='title'>{i18n('Description')}</div> - <div className='description'>{description}</div> - </div> - </div> - </div> - </div> - </div> - ); - } - renderProductDetails(currentSoftwareProduct, isReadOnlyMode) { let {validationData} = currentSoftwareProduct; let {onAttachmentsSelect} = this.props; @@ -181,64 +141,8 @@ class SoftwareProductLandingPageView extends React.Component { ); } - renderComponents() { - const {localFilter} = this.state; - - return ( - <ListEditorView - title={i18n('Virtual Function Components')} - filterValue={localFilter} - placeholder={i18n('Filter Components')} - onFilter={value => this.setState({localFilter: value})} - twoColumns> - {this.filterList().map(component => this.renderComponentsListItem(component))} - </ListEditorView> - ); - } - - renderComponentsListItem(component) { - let {id: componentId, name, displayName, description = ''} = component; - let {currentSoftwareProduct: {id}, onComponentSelect} = this.props; - return ( - <ListEditorItemView - key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()} - className='list-editor-item-view' - onSelect={() => onComponentSelect({id, componentId})}> - <ListEditorItemViewField> - <div className='name'>{displayName}</div> - </ListEditorItemViewField> - <ListEditorItemViewField> - <div className='description'>{description}</div> - </ListEditorItemViewField> - </ListEditorItemView> - ); - } - - renderLicenseAgreement(licenseAgreementName) { - if (licenseAgreementName !== null && !licenseAgreementName) { - return (<div className='missing-license'><SVGIcon name='exclamation-triangle-full'/><div className='warning-text'>{i18n('Missing')}</div></div>); - } - return (licenseAgreementName); - } - - - filterList() { - let {componentsList = []} = this.props; - - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return componentsList.filter(({displayName = '', description = ''}) => { - return escape(displayName).match(filter) || escape(description).match(filter); - }); - } - else { - return componentsList; - } - } - - handleImportSubmit(files, isReadOnlyMode) { - if (isReadOnlyMode) { + handleImportSubmit(files, isReadOnlyMode, isManual) { + if (isReadOnlyMode || isManual) { return; } if (files[0] && files[0].size) { @@ -280,4 +184,54 @@ class SoftwareProductLandingPageView extends React.Component { } } +const ProductSummary = ({currentSoftwareProduct, onDetailsSelect}) => { + let {name = '', description = '', vendorName = '', fullCategoryDisplayName = '', licenseAgreementName = ''} = currentSoftwareProduct; + return ( + <div className='details-panel'> + <div className='software-product-landing-view-heading-title'>{i18n('Software Product Details')}</div> + <div + className='software-product-landing-view-top-block clickable' + onClick={() => onDetailsSelect(currentSoftwareProduct)}> + <div className='details-container'> + <div className='single-detail-section title-section'> + <div className='single-detail-section title-text'> + {name} + </div> + </div> + <div className='details-section'> + <div className='multiple-details-section'> + <div className='detail-col' > + <div className='title'>{i18n('Vendor')}</div> + <div className='description'>{vendorName}</div> + </div> + <div className='detail-col'> + <div className='title'>{i18n('Category')}</div> + <div className='description'>{fullCategoryDisplayName}</div> + </div> + <div className='detail-col'> + <div className='title extra-large'>{i18n('License Agreement')}</div> + <div className='description'> + <LicenseAgreement licenseAgreementName={licenseAgreementName}/> + </div> + </div> + </div> + <div className='single-detail-section'> + <div className='title'>{i18n('Description')}</div> + <div className='description'>{description}</div> + </div> + </div> + </div> + </div> + </div> + ); +}; + + +const LicenseAgreement = ({licenseAgreementName}) => { + if (!licenseAgreementName) { + return (<div className='missing-license'><SVGIcon name='exclamationTriangleFull'/><div className='warning-text'>{i18n('Missing')}</div></div>); + } + return <div>{licenseAgreementName}</div>; +}; + export default SoftwareProductLandingPageView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js index 66926ce4b3..afd6331324 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js @@ -42,7 +42,7 @@ const mapActionsToProps = (dispatch, {softwareProductId}) => { onDeleteProcess: (process, version) => dispatch({ type: modalActionTypes.GLOBAL_MODAL_WARNING, data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}), + msg: i18n(`Are you sure you want to delete "${process.name}"?`), onConfirmed: ()=> SoftwareProductProcessesActionHelper.deleteProcess(dispatch, {process, softwareProductId, version}) } diff --git a/openecomp-ui/src/sdc-app/punch-outs.js b/openecomp-ui/src/sdc-app/punch-outs.js index 78b64da846..125050bfdb 100644 --- a/openecomp-ui/src/sdc-app/punch-outs.js +++ b/openecomp-ui/src/sdc-app/punch-outs.js @@ -13,6 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ +import 'sdc-ui/css/style.css'; import '../../resources/scss/onboarding.scss'; import 'dox-sequence-diagram-ui/src/main/webapp/res/sdc-sequencer.scss'; diff --git a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js index 58e5db7a7d..6e751dcc53 100644 --- a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js +++ b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js @@ -14,8 +14,9 @@ * permissions and limitations under the License. */ import {Factory} from 'rosie'; +import randomstring from 'randomstring'; -export default new Factory() +export const ComputeFlavorQData = new Factory() .attrs({ 'vmSizing':{ 'numOfCPUs': 3, @@ -26,6 +27,19 @@ export default new Factory() } }); +export const ComputeFlavorBaseData = new Factory() + .attrs({ + name: () => randomstring.generate(), + description: () => randomstring.generate(), + id: randomstring.generate() + }); + +export const ComponentComputeFactory = new Factory() + .attrs({ + computesList: [], + computeEditor: {} + }); + export const VSPComponentsComputeDataMapFactory = new Factory() .attrs({ diff --git a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js index a98249bf14..1a356be315 100644 --- a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js +++ b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js @@ -22,6 +22,8 @@ export const VSPComponentsFactory = new Factory() .attr('displayName', ['componentName', 'componentType'], (componentName, componentType) => `${componentName}_${componentType}`) .attr('name', ['displayName'], displayName => `com.ecomp.d2.resource.vfc.nodes.heat.${displayName}`) .attr('id', () => randomstring.generate()) + .attr('vfcCode', 'code') + .attr('nfcFunction', 'function') .attr('description', 'description'); export const VSPComponentsGeneralFactory = new Factory() diff --git a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js index 6bfa091fd3..550e1a6d6c 100644 --- a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js +++ b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js @@ -15,18 +15,24 @@ */ import {Factory} from 'rosie'; import randomstring from 'randomstring'; +import {type2Name, fileTypes} from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js'; + +export const trap = type2Name[fileTypes.SNMP_TRAP]; +export const poll = type2Name[fileTypes.SNMP_POLL]; +export const ves = type2Name[fileTypes.VES_EVENT]; export const VSPComponentsMonitoringRestFactory = new Factory() - .option('snmpTrapFlag', false) - .option('snmpPollFlag', false) - .attr('snmpTrap', ['snmpTrapFlag'], snmpTrapFlag => snmpTrapFlag ? randomstring.generate() : undefined) - .attr('snmpPoll', ['snmpPollFlag'], snmpPollFlag => snmpPollFlag ? randomstring.generate() : undefined); + .option('createTrap', false) + .option('createPoll', false) + .option('createVes', false) + + .attr(trap, ['createTrap'], (createTrap) => {return (createTrap) ? randomstring.generate() : undefined}) + .attr(poll, ['createPoll'], (createPoll) => {return (createPoll) ? randomstring.generate() : undefined}) + .attr(ves, ['createVes'], (createVes) => {return (createVes) ? randomstring.generate() : undefined}); + export const VSPComponentsMonitoringViewFactory = new Factory() - .extend(VSPComponentsMonitoringRestFactory) - .after(monitoring => { - monitoring['trapFilename'] = monitoring['snmpTrap']; - monitoring['pollFilename'] = monitoring['snmpPoll']; - delete monitoring['snmpTrap']; - delete monitoring['snmpPoll']; - }); + .extend(VSPComponentsMonitoringRestFactory); +// .after(monitoring => { + +// }); diff --git a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js index f08d282131..1226ec8317 100644 --- a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js +++ b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js @@ -17,6 +17,13 @@ import {Factory} from 'rosie'; import randomstring from 'randomstring'; import IdMixin from 'test-utils/factories/mixins/IdMixin.js'; +export const VSPComponentsNicPostFactory = new Factory() +.attrs({ + name: () => randomstring.generate(), + description: () => randomstring.generate(), + networkDescription: () => randomstring.generate(), + networkType: 'External' +}); export const VSPComponentsNicFactory = new Factory() .attrs({ name: () => randomstring.generate(), @@ -32,7 +39,8 @@ export const VSPComponentsNicWithIdFactory = new Factory() export const VSPComponentsNetworkFactory = new Factory() .attrs({ nicEditor: {}, - nicList: [] + nicList: [], + nicCreation: {} }); export const VSPComponentsNetworkQDataFactory = new Factory() @@ -57,13 +65,18 @@ export const VSPComponentsNicFactoryGenericFieldInfo = new Factory() .attrs({ 'description' : { isValid: true, - errorText: '', - validations: [] + errorText: '', + validations: [] }, 'name' : { isValid: true, - errorText: '', - validations: [] + errorText: '', + validations: [{type: 'required', data : true}] + }, + 'networkDescription' : { + isValid: true, + errorText: '', + validations: [] } }); diff --git a/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductDeploymentFactories.js b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductDeploymentFactories.js new file mode 100644 index 0000000000..0f81abae61 --- /dev/null +++ b/openecomp-ui/test-utils/factories/softwareProduct/SoftwareProductDeploymentFactories.js @@ -0,0 +1,33 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import {Factory} from 'rosie'; +import IdMixin from 'test-utils/factories/mixins/IdMixin.js'; +import randomstring from 'randomstring'; + +Factory.define('VSPDeploymentBaseFactory') + .attrs({ + name: () => randomstring.generate(), + selectedComponent: () => randomstring.generate(), + selectedFeatureGroup: () => randomstring.generate(), + description: 'string' + }); + +export const VSPDeploymentPostFactory = new Factory() + .extend('VSPDeploymentBaseFactory'); + +export const VSPDeploymentStoreFactory = new Factory() + .extend('VSPDeploymentBaseFactory') + .extend(IdMixin);
\ No newline at end of file diff --git a/openecomp-ui/test/nfvo-components/activity-log/ActivityLog.test.js b/openecomp-ui/test/activity-log/ActivityLog.test.js index 2f377a3539..00aff49b26 100644 --- a/openecomp-ui/test/nfvo-components/activity-log/ActivityLog.test.js +++ b/openecomp-ui/test/activity-log/ActivityLog.test.js @@ -17,10 +17,10 @@ import React from 'react'; import {mount} from 'enzyme'; import {cloneAndSet} from 'test-utils/Util.js'; -import ActivityLogView, {ActivityListItem} from 'nfvo-components/activity-log/ActivityLogView.jsx'; +import ActivityLogView, {ActivityListItem} from 'sdc-app/common/activity-log/ActivityLogView.jsx'; import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; -import ActivityLogActionHelper from 'nfvo-components/activity-log/ActivityLogActionHelper.js'; -import {mapStateToProps} from 'nfvo-components/activity-log/ActivityLog.js'; +import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js'; +import {mapStateToProps} from 'sdc-app/common/activity-log/ActivityLog.js'; import {storeCreator} from 'sdc-app/AppStore.js'; import mockRest from 'test-utils/MockRest.js'; import {ActivityLogStoreFactory} from 'test-utils/factories/activity-log/ActivityLogFactories.js'; diff --git a/openecomp-ui/test/nfvo-components/listEditor/listEditor.test.js b/openecomp-ui/test/nfvo-components/listEditor/listEditor.test.js index c1f823c3fc..029ea31889 100644 --- a/openecomp-ui/test/nfvo-components/listEditor/listEditor.test.js +++ b/openecomp-ui/test/nfvo-components/listEditor/listEditor.test.js @@ -71,7 +71,7 @@ describe('listEditor Module Tests', function () { </ListEditorItemView> ); expect(itemView).toBeTruthy(); - let sliderIcon = TestUtils.findRenderedDOMComponentWithClass(itemView, 'trash-o'); + let sliderIcon = TestUtils.findRenderedDOMComponentWithClass(itemView, 'trashO'); TestUtils.Simulate.click(sliderIcon); }); diff --git a/openecomp-ui/test/nfvo-components/panel/VersionController/versionController.test.js b/openecomp-ui/test/nfvo-components/panel/VersionController/versionController.test.js index 8f2b7e7e88..7d4d57eb35 100644 --- a/openecomp-ui/test/nfvo-components/panel/VersionController/versionController.test.js +++ b/openecomp-ui/test/nfvo-components/panel/VersionController/versionController.test.js @@ -131,8 +131,7 @@ describe('versionController UI Component', () => { let callVCActionProps = { ...props, version: '1.0', callVCAction: function(){} }; let versionController = mount(<VersionController isCheckedOut={true} status={statusEnum.CHECK_OUT_STATUS} {...callVCActionProps} />); let elem = versionController.find('[data-test-id="vc-checkout-btn"]'); - let svgIcon = versionController.find('.version-controller-lock-closed'); - + let svgIcon = versionController.find('.versionControllerLockClosed'); expect(elem).toBeTruthy(); expect(elem.length).toEqual(1); expect(svgIcon.hasClass('disabled')).toBe(true); @@ -142,7 +141,7 @@ describe('versionController UI Component', () => { let callVCActionProps = { ...props, version: '1.0', callVCAction: function(){} }; let versionController = mount(<VersionController isCheckedOut={false} status={statusEnum.CHECK_IN_STATUS} {...callVCActionProps} />); let elem = versionController.find('[data-test-id="vc-checkout-btn"]'); - let svgIcon = versionController.find('.version-controller-lock-closed'); + let svgIcon = versionController.find('.versionControllerLockClosed'); expect(elem).toBeTruthy(); expect(elem.length).toBe(1); diff --git a/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentComputeEditor.test.js b/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentComputeEditor.test.js new file mode 100644 index 0000000000..c14246f810 --- /dev/null +++ b/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentComputeEditor.test.js @@ -0,0 +1,85 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import {mapStateToProps as computeEditorMapStateToProps} from 'sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditor.js'; +import ComputeEditorView from 'sdc-app/onboarding/softwareProduct/components/compute/computeComponents/computeFlavor/ComputeFlavorEditorView.jsx'; + +import {SoftwareProductFactory} from 'test-utils/factories/softwareProduct/SoftwareProductFactory.js'; +import {VSPEditorFactory} from 'test-utils/factories/softwareProduct/SoftwareProductEditorFactories.js'; +import {ComputeFlavorBaseData, ComputeFlavorQData, VSPComponentsComputeDataMapFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js'; + + +describe('Software Product Component Compute-Editor Mapper and View Classes.', () => { + + it('Compute Editor - mapStateToProps mapper exists', () => { + expect(computeEditorMapStateToProps).toBeTruthy(); + }); + + it('Compute Editor - mapStateToProps data test', () => { + const currentSoftwareProduct = VSPEditorFactory.build(); + + var obj = { + softwareProduct: SoftwareProductFactory.build({ + softwareProductEditor: { + data: currentSoftwareProduct + }, + softwareProductComponents: { + computeFlavor: { + computeEditor: { + data: {}, + qdata: {}, + qgenericFieldInfo: {}, + dataMap: {}, + genericFieldInfo: {}, + formReady: true + } + } + } + }) + }; + + var results = computeEditorMapStateToProps(obj); + expect(results.data).toBeTruthy(); + expect(results.qdata).toBeTruthy(); + expect(results.qgenericFieldInfo).toBeTruthy(); + expect(results.dataMap).toBeTruthy(); + expect(results.genericFieldInfo).toBeTruthy(); + expect(results.isReadOnlyMode).toBeTruthy(); + expect(results.isFormValid).toBeTruthy(); + expect(results.formReady).toBeTruthy(); + }); + + it('Compute Editor - View Test', () => { + + const props = { + data: ComputeFlavorBaseData.build(), + qdata: ComputeFlavorQData.build(), + dataMap: VSPComponentsComputeDataMapFactory.build(), + isReadOnlyMode: false, + onDataChanged: () => {}, + onQDataChanged: () => {}, + onSubmit: () => {}, + onCancel: () => {} + }; + + var renderer = TestUtils.createRenderer(); + renderer.render(<ComputeEditorView {...props}/>); + var renderedOutput = renderer.getRenderOutput(); + expect(renderedOutput).toBeTruthy(); + + }); +}); diff --git a/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentsComputes.test.js b/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentsComputes.test.js new file mode 100644 index 0000000000..6d2361b20d --- /dev/null +++ b/openecomp-ui/test/softwareProduct/components/compute/SoftwareProductComponentsComputes.test.js @@ -0,0 +1,48 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import deepFreeze from 'deep-freeze'; +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import {storeCreator} from 'sdc-app/AppStore.js'; +import ComputeFlavors from 'sdc-app/onboarding/softwareProduct/components/compute/computeComponents/ComputeFlavors.js'; +import {ComputeFlavorBaseData} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js'; + +const softwareProductId = '123'; +const componentId = '111'; + +describe('Software Product Component ComputeFlavors - View Classes.', () => { + + it('ComputeFlavors List View Test', () => { + const store = storeCreator(); + deepFreeze(store.getState()); + + const ComputeFlavorsList = ComputeFlavorBaseData.buildList(1); + + var renderer = TestUtils.createRenderer(); + renderer.render( + <ComputeFlavors + store={store} + ComputeFlavorsList={ComputeFlavorsList} + softwareProductId={softwareProductId} + componentId={componentId} + isReadOnlyMode={false}/> + ); + var renderedOutput = renderer.getRenderOutput(); + expect(renderedOutput).toBeTruthy(); + }); +}); + diff --git a/openecomp-ui/test/softwareProduct/components/compute/test.js b/openecomp-ui/test/softwareProduct/components/compute/VSPComponentComputeActionHelperHeatMode.test.js index 8d2d1fbb2f..4fe9408e34 100644 --- a/openecomp-ui/test/softwareProduct/components/compute/test.js +++ b/openecomp-ui/test/softwareProduct/components/compute/VSPComponentComputeActionHelperHeatMode.test.js @@ -21,14 +21,14 @@ import {storeCreator} from 'sdc-app/AppStore.js'; import Configuration from 'sdc-app/config/Configuration.js'; import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; -import {default as VSPComponentsComputeFactory, VSPComponentsComputeDataMapFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js'; +import {ComputeFlavorQData, VSPComponentsComputeDataMapFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js'; import VersionControllerUtilsFactory from 'test-utils/factories/softwareProduct/VersionControllerUtilsFactory.js'; const softwareProductId = '123'; const vspComponentId = '111'; const version = VersionControllerUtilsFactory.build().version; -describe('Software Product Components Compute Module Tests', function () { +describe('Software Product Components Compute Module Tests - HEAT mode', function () { let restPrefix = ''; @@ -41,7 +41,7 @@ describe('Software Product Components Compute Module Tests', function () { const store = storeCreator(); deepFreeze(store.getState()); - const compute = VSPComponentsComputeFactory.build(); + const compute = ComputeFlavorQData.build(); const dataMap = VSPComponentsComputeDataMapFactory.build(); const softwareProductComponentCompute = { @@ -75,7 +75,7 @@ describe('Software Product Components Compute Module Tests', function () { const store = storeCreator(); deepFreeze(store.getState()); - const compute = VSPComponentsComputeFactory.build(); + const compute = ComputeFlavorQData.build(); const softwareProductComponentQuestionnaire = { data: null, diff --git a/openecomp-ui/test/softwareProduct/components/compute/VSPComponentComputeActionHelperManualMode.test.js b/openecomp-ui/test/softwareProduct/components/compute/VSPComponentComputeActionHelperManualMode.test.js new file mode 100644 index 0000000000..ca3d12f3e9 --- /dev/null +++ b/openecomp-ui/test/softwareProduct/components/compute/VSPComponentComputeActionHelperManualMode.test.js @@ -0,0 +1,198 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import deepFreeze from 'deep-freeze'; +import mockRest from 'test-utils/MockRest.js'; +import {cloneAndSet} from 'test-utils/Util.js'; +import {storeCreator} from 'sdc-app/AppStore.js'; +import Configuration from 'sdc-app/config/Configuration.js'; +import ComputeFlavorActionHelper from 'sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js'; +import {VSPEditorFactory} from 'test-utils/factories/softwareProduct/SoftwareProductEditorFactories.js'; + +import {ComputeFlavorQData, ComputeFlavorBaseData, ComponentComputeFactory, VSPComponentsComputeDataMapFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsComputeFactory.js'; + +const softwareProductId = '123'; +const vspComponentId = '111'; +const computeId = '111'; +const version = VSPEditorFactory.build().version; + + +describe('Software Product Components Compute Module Tests - Manual mode', function () { + + let restPrefix = ''; + + beforeAll(function() { + restPrefix = Configuration.get('restPrefix'); + deepFreeze(restPrefix); + }); + + + it('Close Compute Flavor editor', () => { + + const store = storeCreator(); + deepFreeze(store.getState()); + + const compute = ComponentComputeFactory.build(); + deepFreeze(compute); + + const expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.computeFlavor', compute); + + ComputeFlavorActionHelper.closeComputeEditor(store.dispatch); + expect(store.getState()).toEqual(expectedStore); + }); + + it('Get Computes List', () => { + const store = storeCreator(); + deepFreeze(store.getState()); + + const computesList = ComputeFlavorBaseData.buildList(2); + deepFreeze(computesList); + + const expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.computeFlavor.computesList', computesList); + + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return {results: computesList}; + }); + + return ComputeFlavorActionHelper.fetchComputesList(store.dispatch, {softwareProductId, componentId: vspComponentId, version}).then(() => { + expect(store.getState()).toEqual(expectedStore); + }); + }); + + it('Load Compute data & Questionnaire', () => { + const store = storeCreator(); + deepFreeze(store.getState()); + + const computeData = { + ...ComputeFlavorBaseData.build(), + id: computeId + }; + deepFreeze(computeData); + const qdata = ComputeFlavorQData.build(); + const dataMap = VSPComponentsComputeDataMapFactory.build(); + + const softwareProductComponentCompute = { + data: JSON.stringify(qdata), + schema: JSON.stringify(qdata) + }; + deepFreeze(softwareProductComponentCompute); + + + const expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.computeFlavor.computeEditor', { + data: computeData, + qdata, + dataMap, + qgenericFieldInfo: {}, + genericFieldInfo: {}, + formReady: true + }); + + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors/${computeId}`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return {data: computeData}; + }); + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors/${computeId}/questionnaire`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return softwareProductComponentCompute; + }); + + return ComputeFlavorActionHelper.loadComputeData({softwareProductId, componentId: vspComponentId, version, computeId}).then(() => { + ComputeFlavorActionHelper.loadComputeQuestionnaire(store.dispatch, {softwareProductId, componentId: vspComponentId, computeId, version}).then(() => + expect(store.getState()).toEqual(expectedStore)); + }); + }); + + it('Save Compute Flavor data and questionnaire', () => { + + const store = storeCreator(); + deepFreeze(store.getState()); + + const qdata = ComputeFlavorQData.build(); + const data = ComputeFlavorBaseData.build(); + + const compute = {...data, id: computeId}; + + const computeObj = { + computeEditor: {}, + computesList: [ + compute + ] + }; + + const expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.computeFlavor', computeObj); + deepFreeze(expectedStore); + + mockRest.addHandler('put', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors/${computeId}/questionnaire`); + expect(data).toEqual(qdata); + expect(options).toEqual(undefined); + return {returnCode: 'OK'}; + }); + + mockRest.addHandler('put', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors/${computeId}`); + expect(data).toEqual(data); + expect(options).toEqual(undefined); + return {returnCode: 'OK'}; + }); + + return ComputeFlavorActionHelper.saveComputeDataAndQuestionnaire(store.dispatch, {softwareProductId, componentId: vspComponentId, qdata, data: compute, version}).then(() => { + expect(store.getState()).toEqual(expectedStore); + }); + }); + + it('Delete Compute Flavor', () => { + const compute = ComponentComputeFactory.build(); + const computesList = [compute]; + deepFreeze(computesList); + + const store = storeCreator({ + softwareProduct: { + softwareProductComponents: { + computeFlavor: { + computesList: computesList + } + } + } + }); + deepFreeze(store.getState()); + + const computeId = compute.id; + + const expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.computeFlavor.computesList', []); + + mockRest.addHandler('destroy', ({data, options, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${vspComponentId}/compute-flavors/${computeId}`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return { + results: { + returnCode: 'OK' + } + }; + }); + + return ComputeFlavorActionHelper.deleteCompute(store.dispatch, {softwareProductId, componentId: vspComponentId, computeId, version}).then(() => { + expect(store.getState()).toEqual(expectedStore); + }); + }); +}); diff --git a/openecomp-ui/test/softwareProduct/components/general/ComponentGeneralActionHelper.test.js b/openecomp-ui/test/softwareProduct/components/general/ComponentGeneralActionHelper.test.js new file mode 100644 index 0000000000..cef4b3a16e --- /dev/null +++ b/openecomp-ui/test/softwareProduct/components/general/ComponentGeneralActionHelper.test.js @@ -0,0 +1,48 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ + +import deepFreeze from 'deep-freeze'; +import mockRest from 'test-utils/MockRest.js'; +import {storeCreator} from 'sdc-app/AppStore.js'; +import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; +import VersionControllerUtilsFactory from 'test-utils/factories/softwareProduct/VersionControllerUtilsFactory.js'; +import {VSPComponentsFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js'; + +const softwareProductId = '123'; +const version = VersionControllerUtilsFactory.build().version; + +describe('Software Product Components Action Helper Tests', function () { + + it('Load components list', () => { + const store = storeCreator(); + deepFreeze(store.getState()); + + const expectedComponentData = VSPComponentsFactory.build(); + deepFreeze(expectedComponentData); + + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return ({results: [expectedComponentData]}); + }); + + return SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(store.dispatch, {softwareProductId, version}).then(() => { + expect(store.getState().softwareProduct.softwareProductComponents.componentsList).toEqual([expectedComponentData]); + }); + + }); +}); diff --git a/openecomp-ui/test/softwareProduct/components/general/SoftwareProductComponentsGeneral.test.js b/openecomp-ui/test/softwareProduct/components/general/SoftwareProductComponentsGeneral.test.js index 4f6512ad15..edc7fca6a1 100644 --- a/openecomp-ui/test/softwareProduct/components/general/SoftwareProductComponentsGeneral.test.js +++ b/openecomp-ui/test/softwareProduct/components/general/SoftwareProductComponentsGeneral.test.js @@ -70,8 +70,7 @@ describe('SoftwareProductComponentsGeneral Mapper and View Classes', () => { const versionControllerData = VSPComponentsVersionControllerFactory.build(); const componentData = { - name: '', - description: '' + name: '' }; var renderer = TestUtils.createRenderer(); diff --git a/openecomp-ui/test/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.test.js b/openecomp-ui/test/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.test.js index 24658f1b30..423a7b39f6 100644 --- a/openecomp-ui/test/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.test.js +++ b/openecomp-ui/test/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.test.js @@ -19,11 +19,12 @@ import TestUtils from 'react-addons-test-utils'; import {mapStateToProps} from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoring.js'; import SoftwareProductComponentsMonitoringView from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringView.jsx'; -import {VSPComponentsMonitoringViewFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js'; +import {VSPComponentsMonitoringViewFactory, trap, poll, ves} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js'; import VersionControllerUtilsFactory from 'test-utils/factories/softwareProduct/VersionControllerUtilsFactory.js'; const version = VersionControllerUtilsFactory.build(); + describe('SoftwareProductComponentsMonitoring Module Tests', function () { it('should mapper exist', () => { @@ -33,24 +34,36 @@ describe('SoftwareProductComponentsMonitoring Module Tests', function () { it('should return empty file names', () => { let softwareProduct = {softwareProductEditor: {data: {...version}}, softwareProductComponents: {monitoring: {}}}; var results = mapStateToProps({softwareProduct}); - expect(results.trapFilename).toEqual(undefined); - expect(results.pollFilename).toEqual(undefined); + expect(results.filenames[trap]).toEqual(undefined); + expect(results.filenames[poll]).toEqual(undefined); + expect(results.filenames[ves]).toEqual(undefined); }); it('should return trap file name', () => { - const monitoring = VSPComponentsMonitoringViewFactory.build({}, {snmpTrapFlag: true}); + const monitoring = VSPComponentsMonitoringViewFactory.build({}, {createTrap: true}); + let softwareProduct = {softwareProductEditor: {data: {...version}}, softwareProductComponents: {monitoring}}; + var results = mapStateToProps({softwareProduct}); + expect(results.filenames[trap]).toEqual(monitoring[trap]); + expect(results.filenames[poll]).toEqual(undefined); + expect(results.filenames[ves]).toEqual(undefined); + }); + + it('should return ves events file name', () => { + const monitoring = VSPComponentsMonitoringViewFactory.build({}, {createVes: true}); let softwareProduct = {softwareProductEditor: {data: {...version}}, softwareProductComponents: {monitoring}}; var results = mapStateToProps({softwareProduct}); - expect(results.trapFilename).toEqual(monitoring.trapFilename); - expect(results.pollFilename).toEqual(undefined); + expect(results.filenames[ves]).toEqual(monitoring[ves]); + expect(results.filenames[poll]).toEqual(undefined); + expect(results.filenames[trap]).toEqual(undefined); }); it('should return poll file names', () => { - const monitoring = VSPComponentsMonitoringViewFactory.build({}, {snmpPollFlag: true}); + const monitoring = VSPComponentsMonitoringViewFactory.build({}, {createPoll: true}); let softwareProduct = {softwareProductEditor: {data: {...version}}, softwareProductComponents: {monitoring}}; var results = mapStateToProps({softwareProduct}); - expect(results.trapFilename).toEqual(undefined); - expect(results.pollFilename).toEqual(monitoring.pollFilename); + expect(results.filenames[poll]).toEqual(monitoring[poll]); + expect(results.filenames[trap]).toEqual(undefined); + expect(results.filenames[ves]).toEqual(undefined); let renderer = TestUtils.createRenderer(); renderer.render(<SoftwareProductComponentsMonitoringView {...results} />); @@ -58,12 +71,13 @@ describe('SoftwareProductComponentsMonitoring Module Tests', function () { expect(renderedOutput).toBeTruthy(); }); - it('should return both file names', () => { - const monitoring = VSPComponentsMonitoringViewFactory.build({}, {snmpTrapFlag: true, snmpPollFlag: true}); + it('should return all file names', () => { + const monitoring = VSPComponentsMonitoringViewFactory.build({}, {createTrap: true, createVes: true, createPoll: true}); let softwareProduct = {softwareProductEditor: {data: {...version}}, softwareProductComponents: {monitoring}}; var results = mapStateToProps({softwareProduct}); - expect(results.trapFilename).toEqual(monitoring.trapFilename); - expect(results.pollFilename).toEqual(monitoring.pollFilename); + expect(results.filenames[poll]).toEqual(monitoring[poll]); + expect(results.filenames[trap]).toEqual(monitoring[trap]); + expect(results.filenames[ves]).toEqual(monitoring[ves]); let renderer = TestUtils.createRenderer(); renderer.render(<SoftwareProductComponentsMonitoringView {...results} />); diff --git a/openecomp-ui/test/softwareProduct/components/monitoring/test.js b/openecomp-ui/test/softwareProduct/components/monitoring/test.js index dd0f850a89..8fafcdb968 100644 --- a/openecomp-ui/test/softwareProduct/components/monitoring/test.js +++ b/openecomp-ui/test/softwareProduct/components/monitoring/test.js @@ -18,8 +18,9 @@ import mockRest from 'test-utils/MockRest.js'; import {storeCreator} from 'sdc-app/AppStore.js'; import SoftwareProductComponentsMonitoringConstants from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js'; import SoftwareProductComponentsMonitoringActionHelper from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js'; +import {fileTypes} from 'sdc-app/onboarding/softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringConstants.js'; -import {VSPComponentsMonitoringRestFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js'; +import {VSPComponentsMonitoringRestFactory, trap, poll, ves} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsMonitoringFactories.js'; import VersionControllerUtilsFactory from 'test-utils/factories/softwareProduct/VersionControllerUtilsFactory.js'; const softwareProductId = '123'; @@ -40,171 +41,103 @@ describe('Software Product Components Monitoring Module Tests', function () { let emptyResult = VSPComponentsMonitoringRestFactory.build(); mockRest.addHandler('fetch', ({ baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp`); + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/uploads`); return emptyResult; }); - SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, { - softwareProductId, - version, - componentId - }); - setTimeout(()=> { + return SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, {softwareProductId, version, componentId}).then(() => { var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(emptyResult.snmpPoll); - expect(monitoring.trapFilename).toEqual(emptyResult.snmpTrap); + expect(monitoring[trap]).toEqual(emptyResult[trap]); + expect(monitoring[poll]).toEqual(emptyResult[poll]); + expect(monitoring[ves]).toEqual(emptyResult[ves]); done(); - }, 0); + }); + }); it('Fetch for existing files - only snmp trap file exists', done => { - let response = VSPComponentsMonitoringRestFactory.build({}, {snmpTrapFlag: true}); + let response = VSPComponentsMonitoringRestFactory.build({}, {createTrap: true}); mockRest.addHandler('fetch', ({ baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp`); + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/uploads`); return response; }); - SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, { - softwareProductId, - version, - componentId - }); - setTimeout(()=> { - var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(response.snmpPoll); - expect(monitoring.trapFilename).toEqual(response.snmpTrap); - done(); - }, 0); - }); - - it('Fetch for existing files - only snmp poll file exists', done => { - let response = VSPComponentsMonitoringRestFactory.build({}, {snmpPollFlag: true}); + return SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, {softwareProductId, version, componentId}).then(() => { - mockRest.addHandler('fetch', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp`); - return response; - }); - - SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, { - softwareProductId, - version, - componentId - }); - setTimeout(()=> { var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(response.snmpPoll); - expect(monitoring.trapFilename).toEqual(response.snmpTrap); + expect(monitoring[poll]).toEqual(undefined); + expect(monitoring[trap]).toEqual(response[trap]); + expect(monitoring[ves]).toEqual(undefined); done(); - }, 0); + }); }); - it('Fetch for existing files - both files exist', done => { - let response = VSPComponentsMonitoringRestFactory.build({}, {snmpTrapFlag: true, snmpPollFlag: true}); + + it('Fetch for existing files - all files exist', done => { + let response = VSPComponentsMonitoringRestFactory.build({}, {createSnmp: true, createPoll: true, createVes: true}); mockRest.addHandler('fetch', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp`); + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/uploads`); return response; }); - SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, { - softwareProductId, - version, - componentId - }); - setTimeout(()=> { + return SoftwareProductComponentsMonitoringActionHelper.fetchExistingFiles(store.dispatch, {softwareProductId, version, componentId}).then(() => { + var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(response.snmpPoll); - expect(monitoring.trapFilename).toEqual(response.snmpTrap); + expect(monitoring[trap]).toEqual(response[trap]); + expect(monitoring[poll]).toEqual(response[poll]); + expect(monitoring[ves]).toEqual(response[ves]); done(); - }, 0); + }); }); - it('Upload snmp trap file', done => { + it('Upload file', done => { mockRest.addHandler('post', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp-trap/upload`); + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/uploads/types/${fileTypes.SNMP_TRAP}`); return {}; }); var debug = {hello: 'world'}; let file = new Blob([JSON.stringify(debug, null, 2)], {type: 'application/json'});; let formData = new FormData(); formData.append('upload', file); - SoftwareProductComponentsMonitoringActionHelper.uploadSnmpFile(store.dispatch, { + return SoftwareProductComponentsMonitoringActionHelper.uploadFile(store.dispatch, { softwareProductId, version, componentId, formData, fileSize: file.size, - type: SoftwareProductComponentsMonitoringConstants.SNMP_TRAP - }); - setTimeout(()=> { + type: fileTypes.SNMP_TRAP + }).then(() => { var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(undefined); - expect(monitoring.trapFilename).toEqual('blob'); + expect(monitoring[poll]).toEqual(undefined); + expect(monitoring[ves]).toEqual(undefined); + expect(monitoring[trap]).toEqual('blob'); done(); - }, 0); - }); - it('Upload snmp poll file', done => { - mockRest.addHandler('post', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp/upload`); - return {}; - }); - var debug = {hello: 'world'}; - let file = new Blob([JSON.stringify(debug, null, 2)], {type: 'application/json'});; - let formData = new FormData(); - formData.append('upload', file); - SoftwareProductComponentsMonitoringActionHelper.uploadSnmpFile(store.dispatch, { - softwareProductId, - version, - componentId, - formData, - fileSize: file.size, - type: SoftwareProductComponentsMonitoringConstants.SNMP_POLL }); - setTimeout(()=> { - var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual('blob'); - expect(monitoring.trapFilename).toEqual(undefined); - done(); - }, 0); }); it('Delete snmp trap file', done => { mockRest.addHandler('destroy', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp-trap`); + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/uploads/types/${fileTypes.SNMP_TRAP}`); return {}; }); - SoftwareProductComponentsMonitoringActionHelper.deleteSnmpFile(store.dispatch, { - softwareProductId, - version, - componentId, - type: SoftwareProductComponentsMonitoringConstants.SNMP_TRAP - }); - setTimeout(()=> { - var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.trapFilename).toEqual(undefined); - done(); - }, 0); - }); - it('Delete snmp poll file', done => { - mockRest.addHandler('destroy', ({baseUrl}) => { - expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/monitors/snmp`); - return {}; - }); - SoftwareProductComponentsMonitoringActionHelper.deleteSnmpFile(store.dispatch, { + + return SoftwareProductComponentsMonitoringActionHelper.deleteFile(store.dispatch, { softwareProductId, version, componentId, - type: SoftwareProductComponentsMonitoringConstants.SNMP_POLL - }); - setTimeout(()=> { + type: fileTypes.SNMP_TRAP + }).then((dispatch) => { var {softwareProduct: {softwareProductComponents: {monitoring}}} = store.getState(); - expect(monitoring.pollFilename).toEqual(undefined); + expect(monitoring[trap]).toEqual(undefined); done(); - }, 0); + }); }); + + }); diff --git a/openecomp-ui/test/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.test.js b/openecomp-ui/test/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.test.js index f5a10e23c9..b6050265a6 100644 --- a/openecomp-ui/test/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.test.js +++ b/openecomp-ui/test/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.test.js @@ -19,7 +19,7 @@ import {cloneAndSet} from 'test-utils/Util.js'; import {storeCreator} from 'sdc-app/AppStore.js'; import SoftwareProductComponentsNetworkActionHelper from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkActionHelper.js'; -import {VSPComponentsNicFactory, VSPComponentsNetworkFactory, VSPComponentsNetworkQDataFactory, VSPComponentsNetworkDataMapFactory, VSPComponentsNicFactoryGenericFieldInfo} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js'; +import {VSPComponentsNicPostFactory, VSPComponentsNicFactory, VSPComponentsNetworkFactory, VSPComponentsNetworkQDataFactory, VSPComponentsNetworkDataMapFactory, VSPComponentsNicFactoryGenericFieldInfo} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsNetworkFactories.js'; import VersionControllerUtilsFactory from 'test-utils/factories/softwareProduct/VersionControllerUtilsFactory.js'; import VSPQSchemaFactory from 'test-utils/factories/softwareProduct/SoftwareProductQSchemaFactory.js'; import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; @@ -55,7 +55,60 @@ describe('Software Product Components Network Action Helper Tests', function () }); }); - + it('Add NIC', () => { + const store = storeCreator(); + deepFreeze(store.getState()); + + const NICPostRequest = VSPComponentsNicPostFactory.build(); + + const expectedNIC = VSPComponentsNicFactory.build({...NICPostRequest, id: nicId}); + + mockRest.addHandler('post', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/nics`); + expect(data).toEqual(NICPostRequest); + expect(options).toEqual(undefined); + return { + nicId + }; + }); + + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/nics`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return {results: [expectedNIC]}; + }); + + mockRest.addHandler('destroy', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/nics/${nicId}`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return {}; + }); + + mockRest.addHandler('fetch', ({options, data, baseUrl}) => { + expect(baseUrl).toEqual(`/onboarding-api/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/nics`); + expect(data).toEqual(undefined); + expect(options).toEqual(undefined); + return {results: []}; + }); + + const network = VSPComponentsNetworkFactory.build({ + nicList: [expectedNIC] + }); + + const networkAfterDelete = VSPComponentsNetworkFactory.build(); + + let expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.network', network); + + return SoftwareProductComponentsNetworkActionHelper.createNIC(store.dispatch, {nic: NICPostRequest, softwareProductId, componentId, version}).then(() => { + expect(store.getState()).toEqual(expectedStore); + return SoftwareProductComponentsNetworkActionHelper.deleteNIC(store.dispatch, {softwareProductId, componentId, nicId, version}); + }).then(() => { + let expectedStore = cloneAndSet(store.getState(), 'softwareProduct.softwareProductComponents.network', networkAfterDelete); + expect(store.getState()).toEqual(expectedStore); + }); + }); it('open NICE editor', () => { const store = storeCreator(); @@ -83,7 +136,7 @@ describe('Software Product Components Network Action Helper Tests', function () SoftwareProductComponentsNetworkActionHelper.openNICEditor(store.dispatch, {nic, data}); - expect(store.getState()).toEqual(expectedStore); + expect(store.getState().softwareProduct.softwareProductComponents.network).toEqual(expectedStore.softwareProduct.softwareProductComponents.network); }); it('close NICE editor', () => { @@ -102,7 +155,7 @@ describe('Software Product Components Network Action Helper Tests', function () }); it('Load NIC data', () => { - + mockRest.resetQueue(); const expectedData = VSPComponentsNicFactory.build(); deepFreeze(expectedData); @@ -121,7 +174,7 @@ describe('Software Product Components Network Action Helper Tests', function () it('load NIC Questionnaire', () => { - + mockRest.resetQueue(); const store = storeCreator(); deepFreeze(store.getState()); @@ -171,6 +224,7 @@ describe('Software Product Components Network Action Helper Tests', function () const network = { nicEditor: {}, + nicCreation: {}, nicList: [ expectedData ] diff --git a/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentEditor.test.js b/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentEditor.test.js new file mode 100644 index 0000000000..4277f28ee8 --- /dev/null +++ b/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentEditor.test.js @@ -0,0 +1,81 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import { mapStateToProps } from 'sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js'; +import SoftwareProductDeploymentEditorView from 'sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx'; +import { VSPComponentsFactory } from 'test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js'; +import { VSPEditorFactoryWithLicensingData } from 'test-utils/factories/softwareProduct/SoftwareProductEditorFactories.js'; +import { FeatureGroupStoreFactory } from 'test-utils/factories/licenseModel/FeatureGroupFactories.js'; + +describe('Software Product Deployment Editor Module Tests', function () { + + it('should mapper exist', () => { + expect(mapStateToProps).toBeTruthy(); + }); + + it('should return empty data', () => { + + const currentSoftwareProduct = VSPEditorFactoryWithLicensingData.build(); + const componentsList = VSPComponentsFactory.buildList(1); + const featureGroupsList = FeatureGroupStoreFactory.buildList(2); + + var state = { + softwareProduct: { + softwareProductEditor: { + data: currentSoftwareProduct + }, + softwareProductDeployment: + { + deploymentFlavors: [], + deploymentFlavorEditor: {data: {}} + }, + softwareProductComponents: { + componentsList, + computeFlavor: { + computesList: [] + } + } + }, + licenseModel: { + featureGroup: { + featureGroupsList + } + } + }; + + var results = mapStateToProps(state); + expect(results.data).toEqual({}); + }); + + it('jsx view test', () => { + const componentsList = VSPComponentsFactory.buildList(1); + var renderer = TestUtils.createRenderer(); + renderer.render( + <SoftwareProductDeploymentEditorView + isReadOnlyMode={true} + selectedFeatureGroupsList={[]} + componentsList={componentsList} + data={{}} + onDataChanged={() => {}} + onSubmit={() => {}} + onClose={() => {}}/> + ); + var renderedOutput = renderer.getRenderOutput(); + expect(renderedOutput).toBeTruthy(); + }); + +}); diff --git a/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentView.test.js b/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentView.test.js new file mode 100644 index 0000000000..9700efe98a --- /dev/null +++ b/openecomp-ui/test/softwareProduct/deployment/SoftwareProductDeploymentView.test.js @@ -0,0 +1,77 @@ +/*! + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * + * 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. + */ +import React from 'react'; +import TestUtils from 'react-addons-test-utils'; +import {mapStateToProps} from 'sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js'; +import SoftwareProductDeploymentView from 'sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx'; + +import {VSPDeploymentStoreFactory} from 'test-utils/factories/softwareProduct/SoftwareProductDeploymentFactories.js'; +import {VSPComponentsFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js'; +import {VSPEditorFactory} from 'test-utils/factories/softwareProduct/SoftwareProductEditorFactories.js'; + +describe('SoftwareProductDeployment Mapper and View Classes', () => { + it ('mapStateToProps mapper exists', () => { + expect(mapStateToProps).toBeTruthy(); + }); + + it ('mapStateToProps data test', () => { + + const currentSoftwareProduct = VSPEditorFactory.build(); + + const deploymentFlavors = VSPDeploymentStoreFactory.buildList(2); + + const componentsList = VSPComponentsFactory.buildList(1); + + var state = { + softwareProduct: { + softwareProductEditor: { + data: currentSoftwareProduct + }, + softwareProductDeployment: + { + deploymentFlavors, + deploymentFlavorsEditor: {data: {}} + }, + softwareProductComponents: { + componentsList + } + } + }; + var results = mapStateToProps(state); + expect(results.deploymentFlavors).toBeTruthy(); + }); + + it ('view simple test', () => { + + const currentSoftwareProduct = VSPEditorFactory.build(); + + const deploymentFlavors = VSPDeploymentStoreFactory.buildList(2); + + var renderer = TestUtils.createRenderer(); + renderer.render( + <SoftwareProductDeploymentView + deploymentFlavors={deploymentFlavors} + currentSoftwareProduct={currentSoftwareProduct} + onAddDeployment={() => {}} + onEditDeployment={() => {}} + onDeleteDeployment={() => {}} + isReadOnlyMode={false} /> + ); + var renderedOutput = renderer.getRenderOutput(); + expect(renderedOutput).toBeTruthy(); + + }); +}); diff --git a/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js b/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js index f06ad61e4f..4da0ec98d4 100644 --- a/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js +++ b/openecomp-ui/test/softwareProduct/landingPage/landingPage.test.js @@ -28,6 +28,8 @@ import {default as VspQdataFactory} from 'test-utils/factories/softwareProduct/ import {VSPComponentsFactory} from 'test-utils/factories/softwareProduct/SoftwareProductComponentsFactories.js'; import {FinalizedLicenseModelFactory} from 'test-utils/factories/licenseModel/LicenseModelFactories.js'; +import { Provider } from 'react-redux'; +import {storeCreator} from 'sdc-app/AppStore.js'; import {mapStateToProps} from 'sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js'; import SoftwareProductLandingPageView from 'sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx'; @@ -95,8 +97,9 @@ describe('Software Product Landing Page: ', function () { componentsList: VSPComponentsFactory.buildList(2) }; - let vspLandingView = TestUtils.renderIntoDocument(<SoftwareProductLandingPageView - {...params}/>); + const store = storeCreator(); + let vspLandingView = TestUtils.renderIntoDocument(<Provider store={store}><SoftwareProductLandingPageView + {...params}/></Provider>); expect(vspLandingView).toBeTruthy(); }); @@ -108,11 +111,16 @@ describe('Software Product Landing Page: ', function () { componentsList: VSPComponentsFactory.buildList(2) }; - let vspLandingView = TestUtils.renderIntoDocument(<SoftwareProductLandingPageView - {...params}/>); + const store = storeCreator(); + let vspLandingView = TestUtils.renderIntoDocument(<Provider store={store}><SoftwareProductLandingPageView + {...params}/></Provider>); + let vspLandingViewWrapper = TestUtils.findRenderedComponentWithType( + vspLandingView, + SoftwareProductLandingPageView + ); expect(vspLandingView).toBeTruthy(); - vspLandingView.handleOnDragEnter(false); - expect(vspLandingView.state.dragging).toEqual(true); + vspLandingViewWrapper.handleOnDragEnter(false); + expect(vspLandingViewWrapper.state.dragging).toEqual(true); }); @@ -126,10 +134,7 @@ describe('Software Product Landing Page: ', function () { onUpload: dummyFunc, onInvalidFileSizeUpload: dummyFunc }; - - let vspLandingView = TestUtils.renderIntoDocument(<SoftwareProductLandingPageView - {...params}/>); - expect(vspLandingView).toBeTruthy(); + const files = [ { name: 'aaa', @@ -137,16 +142,24 @@ describe('Software Product Landing Page: ', function () { } ]; - vspLandingView.handleImportSubmit(files, false); - expect(vspLandingView.state.dragging).toEqual(false); - expect(vspLandingView.state.fileName).toEqual(files[0].name); + const store = storeCreator(); + + let vspLandingView = TestUtils.renderIntoDocument(<Provider store={store}><SoftwareProductLandingPageView {...params}/></Provider>); + let vspLandingViewWrapper = TestUtils.findRenderedComponentWithType( + vspLandingView, + SoftwareProductLandingPageView + ); + expect(vspLandingView).toBeTruthy(); + vspLandingViewWrapper.handleImportSubmit(files, false); + expect(vspLandingViewWrapper.state.dragging).toEqual(false); + expect(vspLandingViewWrapper.state.fileName).toEqual(files[0].name); const files1 = [ { name: 'bbb', size: 0 } ]; - vspLandingView.handleImportSubmit(files1, false); + vspLandingViewWrapper.handleImportSubmit(files1, false); }); it('vsp landing handleImportSubmit with damaged file test ', () => { @@ -160,8 +173,15 @@ describe('Software Product Landing Page: ', function () { onInvalidFileSizeUpload: dummyFunc }; - let vspLandingView = TestUtils.renderIntoDocument(<SoftwareProductLandingPageView - {...params}/>); + const store = storeCreator(); + + let vspLandingView = TestUtils.renderIntoDocument(<Provider store={store}><SoftwareProductLandingPageView + {...params}/></Provider>); + + let vspLandingViewWrapper = TestUtils.findRenderedComponentWithType( + vspLandingView, + SoftwareProductLandingPageView + ); expect(vspLandingView).toBeTruthy(); const files = [ { @@ -170,8 +190,8 @@ describe('Software Product Landing Page: ', function () { } ]; - vspLandingView.handleImportSubmit(files, false); - expect(vspLandingView.state.dragging).toEqual(false); - expect(vspLandingView.state.fileName).toEqual(''); + vspLandingViewWrapper.handleImportSubmit(files, false); + expect(vspLandingViewWrapper.state.dragging).toEqual(false); + expect(vspLandingViewWrapper.state.fileName).toEqual(''); }); }); diff --git a/openecomp-ui/tools/gulp/deployment/package.json b/openecomp-ui/tools/gulp/deployment/package.json deleted file mode 100644 index 5f049057fc..0000000000 --- a/openecomp-ui/tools/gulp/deployment/package.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "name": "sdc-client-tools", - "version": "9.3.0", - "description": "Service Designer & Catalog Client Tools", - "dependencies": {}, - "devDependencies": { - "bluebird": "^2.10.1", - "gulp": "^3.9.0", - "gulp-rename": "^1.2.2", - "gulp-replace": "^0.5.4", - "prompt": "^0.2.14" - }, - "author": "OPENECOMP", - "license": "LicenseRef-LICENSE", - "scripts": { - "start": "gulp run", - "test": "echo \"Error: no test specified\" && exit 1" - }, - "engines": { - "node": ">=0.12.7", - "npm": ">=2.11.3" - } -} diff --git a/openecomp-ui/tools/gulp/deployment/tools/gulp/tasks/i18nUpdate.js b/openecomp-ui/tools/gulp/deployment/tools/gulp/tasks/i18nUpdate.js deleted file mode 100644 index d35ae2dafc..0000000000 --- a/openecomp-ui/tools/gulp/deployment/tools/gulp/tasks/i18nUpdate.js +++ /dev/null @@ -1,166 +0,0 @@ -/*! - * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. - * - * 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. - */ -var gulp, replace, rename, fs, prompt, Promise; - -function mergePromptOptions(options) { - - return new Promise(function(resolve, reject) { - var lang = options.lang; - var warDir = options.warDir; - prompt.start(); - prompt.get([ - { - description: 'Enter war directory', - default: warDir, - name: 'warDir' - }, - { - description: 'Enter locale.json parent directory name', - default: lang, - name: 'lang' - } - ], function (err, result) { - - if(err) { - reject(new Error('mergePromptOptions::>\n ' + err)); - return; - } - - var warDir = result.warDir; - var lang = result.lang; - - console.log('\nlocale.json parent directory name> "' + lang + '"'); - console.log('war director>"' + warDir + '"'); - - resolve({ - warDir: warDir, - lang: lang - }); - }); - }); -} - -function isBundleExists(path) { - return new Promise(function(resolve) { - fs.stat(path, function(err) { - resolve(null == err); - /*if null == err then file exists.*/ - }); - }); -} - -function copyEnglishBundle(enBundlePath, lang) { - return new Promise(function(resolve, reject) { - gulp.src(enBundlePath, {base: './'}) - .pipe(rename({basename: 'bundle_' + lang})) - .pipe(gulp.dest('./')) - .on('end', function() { - resolve(); - }) - .on('error', function(err) { - reject(new Error('copyEnglishBundle::>\n ' + err)); - }); - }); -} - -function getLocaleContent(localePath) { - - return new Promise(function(resolve, reject) { - fs.readFile(localePath, {encoding: 'utf-8'}, function(err,data){ - if(err) { - reject('getLocaleContent()::>\n ' + err); - return; - } - resolve(data); - }); - }); - -} - -function extractLocaleJsonContent(localeDataStr) { - - var localeJsonStrI18nStartIdx = localeDataStr.indexOf('I18N_IDENTIFIER_START'); - var localeJsonStrI18nEndIdx = localeDataStr.indexOf('I18N_IDENTIFIER_END'); - - if(-1 === localeJsonStrI18nStartIdx || -1 === localeJsonStrI18nEndIdx) { - return Promise.reject(new Error('extractLocaleJsonContent::> localeDataStr must contain %I18N_IDENTIFIER_START% and %I18N_IDENTIFIER_END%')); - } - - var localeJsonStr = localeDataStr.substring( - localeDataStr.indexOf('{', localeJsonStrI18nStartIdx), - localeDataStr.lastIndexOf('}', localeJsonStrI18nEndIdx) + 1 - ); - - try { - JSON.parse(localeJsonStr); - } catch(e) { - return Promise.reject(new Error('extractLocaleJsonContent::> localeDataStr must contain a valid json between %I18N_IDENTIFIER_START% and %I18N_IDENTIFIER_END%=>' + e)); - } - - return Promise.resolve(localeJsonStr); -} - -function setBundleLocaleContent(bundlePath, localeJsonStr) { - return new Promise(function(resolve, reject) { - gulp.src(bundlePath, {base: './'}) - .pipe(replace(/I18N_IDENTIFIER_START(.|[\r\n])*?I18N_IDENTIFIER_END/i, function(expr) { - return expr.substring(0, expr.indexOf('{')) + localeJsonStr + expr.substring(expr.lastIndexOf('}') + 1); - })) - .pipe(gulp.dest('./')) - .on('end', function() { - resolve(); - }) - .on('error', function(err) { - reject(new Error('setBundleLocaleContent::>\n ' + err)); - }); - }); -} - - -function update(options) { - - gulp = require('gulp'); - replace = require('gulp-replace'); - rename = require('gulp-rename'); - fs = require('fs'); - prompt = require('prompt'); - Promise = require('bluebird'); - - return mergePromptOptions(options).then(function(mergedOptions) { - var lang = mergedOptions.lang; - var warDir = mergedOptions.warDir; - - var bundlePath = warDir + '/js/bundle_' + lang + '.js'; - var localePath = warDir + '/i18n/' + lang + '/locale.json'; - - return isBundleExists(bundlePath) - .then(function(isBundleExist) { - var englishBundlePath; - if(!isBundleExist) { - englishBundlePath = warDir + '/js/bundle_en.js'; - return copyEnglishBundle(englishBundlePath, lang); - } - }) - .then(getLocaleContent.bind(null, localePath)) - .then(extractLocaleJsonContent) - .then(setBundleLocaleContent.bind(null, bundlePath)); - }); - -} - - - -module.exports = update;
\ No newline at end of file diff --git a/openecomp-ui/tools/gulp/tasks/i18n.js b/openecomp-ui/tools/gulp/tasks/i18n.js index a17e8466b7..85d5c37734 100644 --- a/openecomp-ui/tools/gulp/tasks/i18n.js +++ b/openecomp-ui/tools/gulp/tasks/i18n.js @@ -17,56 +17,13 @@ var gulp = require('gulp'); var fs = require('fs'); var replace = require('gulp-replace'); var clean = require('gulp-clean'); -var mkdirp = require('mkdirp'); - -/** - * - * @param options.localesPath - * @param options.lang = options.lang - * - * @returns {string} - */ -function composeLocalesDirPath(options) { - return options.localesPath + options.lang; -} - -/** - * - * @param options.localesPath - * @param options.lang - * - * @returns {string} - */ -function composeLocaleFilePath(options) { - return composeLocalesDirPath(options) + '/locale.json'; -} - - -/** - * - * @param options.localesPath - * @param options.lang = options.lang - */ -function ensureLocalesDir(options) { - - return new Promise(function (resolve, reject) { - mkdirp(composeLocalesDirPath(options), function (err) { - if (err) { - reject(err); - } - else { - resolve(); - } - }); - }); -} - +var tap = require('gulp-tap'); /** * * @param options - * @param options.outputPath - * @param options.localesPath - * @param options.lang = options.lang + * @param options.outDir + * @param options.srcDir + * @param options.i18nBundles - optional. if given will check the that all keys from js are mapped * */ function i18nTask(options) { @@ -75,31 +32,66 @@ function i18nTask(options) { function addWord(expr) { var word = expr.substring('i18n(\''.length, expr.length - 1); - i18nJson[word] = word; + if (word !== '') { + i18nJson[word] = word; + } return expr; } - return ensureLocalesDir(options).then(function () { - return new Promise(function(resolve, reject) { - gulp.src(options.outputPath + '**/*.js', {base: './'}) - .pipe(replace(/i18n\('.*?'/g, addWord)) - .pipe(clean()) - .pipe(gulp.dest('./')) - .on('end', function () { - - var i18nJsonWrapper = { dataWrapperArr: ["I18N_IDENTIFIER_START", i18nJson, "I18N_IDENTIFIER_END"] , i18nDataIdx: 1}; - - fs.writeFile(composeLocaleFilePath(options), JSON.stringify(i18nJsonWrapper), function (err) { + let createBundle = new Promise(function(resolve, reject) { + gulp.src(options.srcDir + '**/*.{js,jsx}', {base: './'}) + .pipe(replace(/i18n\('.*?'/g, addWord)) + .pipe(clean()) + .pipe(gulp.dest('./')) + .on('end', function () { + console.log('Retrieved keys from static references.'); + if (options.i18nBundles === undefined) { + // creating the file from the words saved during the replace + let outfile = options.outDir + '/bundleForStaticKeys.json'; + fs.writeFile(outfile,JSON.stringify(i18nJson, null, '\t'), function (err) { if (err) { reject(err); } else resolve(); }); - }).on('error', function (err) { - reject(err); - }); + console.log('Bundle with static keys was created under: ' + outfile); + } + resolve(); + }).on('error', function (err) { + reject(err); }); }); + + + if (options.i18nBundles === undefined) { + return createBundle; + } else { + return createBundle.then(() => { + new Promise(function (resolve, reject) { + gulp.src(options.i18nBundles) + .pipe(tap(function (file) { + console.log('Checking against bundle: ' + file.path); + let bundle = JSON.parse(file.contents.toString()); + for (entry in i18nJson) { + if (!bundle[entry]) { + console.log('Missing Key: ' + entry); + } else { + delete bundle[entry]; + } + } + for (entry in bundle) { + console.log('Unused in static files: ' + entry); + } + })) + .pipe(gulp.dest('./')) + .on('end', function () { + console.log('done'); + }).on('error', function (err) { + reject(err); + }); + }); + }); + } } module.exports = i18nTask; diff --git a/openecomp-ui/tools/gulp/tasks/prod.js b/openecomp-ui/tools/gulp/tasks/prod.js index cb6e251430..509bec857a 100644 --- a/openecomp-ui/tools/gulp/tasks/prod.js +++ b/openecomp-ui/tools/gulp/tasks/prod.js @@ -15,65 +15,51 @@ */ 'use strict'; -let gulp, replace, Promise, webpack, webpackProductionConfig; +let gulp, replace, Promise, webpack, webpackProductionConfig,cloneDeep, tap; +let langs = []; -const supportedLanguages = ['en']; - -function start(options) { - - let promises = [buildIndex(options)]; - supportedLanguages.forEach(function (lang) { - promises.push(bundleJS(options, lang)); - }); - return Promise.all(promises); -} - -function bundleJS(options, lang) { +/* +Runs the webpack build. +Will first seach for the resource bundles to see how many languages are supported and then run a build per langauage + */ +function buildWebPackForLanguage(prodConfig, lang) { return new Promise(function (resolve, reject) { - let prodConfig = webpackProductionConfig; - prodConfig.resolve.alias.i18nJson = options.outDir + '/i18n/' + lang + '/locale.json'; - prodConfig.output.filename = jsFileByLang(options.outFileName, lang); webpack(prodConfig, function (err, stats) { - console.log('[webpack:build]', stats.toString()); + console.log('[webpack:build ' + prodConfig.output.filename + ']', stats.toString()); if (err || stats.hasErrors()) { - console.log('bundleJS : Failure!!', '\n -language: ', lang); + console.log('webpack:build : Failure!! ' + prodConfig.output.filename + ']'); reject(err || stats.toJson().errors); } else { - console.log('bundleJS : Done', '\n -language: ', lang); + console.log('webpack:build : Done ' + prodConfig.output.filename + ']'); resolve(); } }); }); } - -function buildIndex(options) { - - return new Promise(function (resolve, reject) { - - // gulp.src returns a stream object - gulp.src(options.outDir + '/index.html') - .pipe(replace(/\/\/<!--prod:delete-->(.|[\r\n])*?<!--\/prod:delete-->/g, ''))//in script occurrences. - .pipe(replace(/<!--prod:delete-->(.|[\r\n])*?<!--\/prod:delete-->/g, ''))//out of script occurrences. - .pipe(replace(/<!--prod:add(-->)?/g, '')) - .pipe(replace(/\/\/<!--prod:supported-langs-->(.|[\r\n])*?<!--\/prod:supported-langs-->/g, supportedLanguages.map(function (val) { - return "'" + val + "'"; - }).toString())) +/* + // this will check in the src directory which language bundles we have and will + // create the array to that we can run a webpack build per language afterwards + */ +function getSupportedLanguages(options) { + return new Promise((resolve, reject) => { + gulp.src(options.i18nBundles) + .pipe(tap(function(file) { + let languageStartIndex = file.path.lastIndexOf('i18n') + 5; + let languageStr = file.path.indexOf('.json') - languageStartIndex; + let currentLang = file.path.substr(languageStartIndex, languageStr); + console.log('Found bundle ' + file.path + ' for [' + currentLang + ']'); + langs[currentLang] = file.path; + })) .pipe(gulp.dest(options.outDir)) .on('end', function () { - console.log('buildIndex : Done'); resolve(); }) .on('error', function (e) { - console.log('buildIndex : Failure!!'); + console.log('getLanguages : Failure!!'); reject(e); }); }); - -} - -function jsFileByLang(fileName, lang) { - return fileName.replace(/.js$/, '_' + lang + '.js'); } /** @@ -85,22 +71,27 @@ function prodTask(options) { replace = require('gulp-replace'); Promise = require('bluebird'); webpack = require('webpack'); + cloneDeep = require('lodash/cloneDeep'); + tap = require('gulp-tap'); + + // updating webpack for the production build. no need for sourcemaps in this case. webpackProductionConfig = require('../../../webpack.production'); - webpackProductionConfig.module.rules = webpackProductionConfig.module.rules.filter(rule => ((rule.enforce !== 'pre') || (rule.enforce === 'pre' && rule.loader !== 'source-map-loader'))); - webpackProductionConfig.module.rules.forEach(loader => { - if (loader.use && loader.use[0].loader === 'style-loader') { - loader.use = loader.use.map(loaderObj => loaderObj.loader.replace('?sourceMap', '')); + + // get the languages so that we can bulid per language with the correct bundle + let getLanguages =getSupportedLanguages(options); + // this will run a webpack build per language + return getLanguages.then(() => { + let promises = []; + for (var lang in langs) { + let prodConfig = cloneDeep(webpackProductionConfig); + prodConfig.resolve.alias.i18nJson = langs[lang]; + prodConfig.output.filename = (options.outFileName || '[name].js').replace(/.js$/, '_' + lang + '.js'); + promises.push(buildWebPackForLanguage(prodConfig, lang)); } + return Promise.all(promises); }); - - webpackProductionConfig.module.rules.push({test: /config.json$/, use: [{loader:'config-json-loader'}]}); - - return start({ - outFileName: options.outFileName || '[name].js', - outDir: options.outDir - }); } module.exports = prodTask; diff --git a/openecomp-ui/webapp-onboarding/WEB-INF/web.xml b/openecomp-ui/webapp-onboarding/WEB-INF/web.xml index 6dd619fbbc..7840279895 100644 --- a/openecomp-ui/webapp-onboarding/WEB-INF/web.xml +++ b/openecomp-ui/webapp-onboarding/WEB-INF/web.xml @@ -41,6 +41,12 @@ <param-name>etags</param-name> <param-value>true</param-value> </init-param> + <init-param> + <param-name>redirects-list</param-name> + <param-value> + /v1.0/healthcheck + </param-value> + </init-param> </servlet> <servlet-mapping> diff --git a/openecomp-ui/webpack.common.js b/openecomp-ui/webpack.common.js index 01f6d98b21..ebe4a8454a 100644 --- a/openecomp-ui/webpack.common.js +++ b/openecomp-ui/webpack.common.js @@ -13,7 +13,7 @@ module.exports = { resolve: { modules: [path.resolve('.'), path.join(__dirname, 'node_modules')], alias: { - i18nJson: 'nfvo-utils/i18n/locale.json', + i18nJson: 'nfvo-utils/i18n/en.json', // only for default build, not through gulp 'nfvo-utils': 'src/nfvo-utils', 'nfvo-components': 'src/nfvo-components', 'sdc-app': 'src/sdc-app', diff --git a/openecomp-ui/webpack.production.js b/openecomp-ui/webpack.production.js index 1bb9420d33..2dea2170ae 100644 --- a/openecomp-ui/webpack.production.js +++ b/openecomp-ui/webpack.production.js @@ -3,9 +3,14 @@ let path = require('path'); let webpack = require('webpack'); +let cloneDeep = require('lodash/cloneDeep'); +let assign = require('lodash/assign'); let webpackCommon = require('./webpack.common'); -let webpackDevConfig = Object.assign({}, webpackCommon, { +// copying the common config +let webpackProdConfig = cloneDeep(webpackCommon); +// setting production settings +assign( webpackProdConfig, { devtool: undefined, cache: true, output: { @@ -42,4 +47,11 @@ let webpackDevConfig = Object.assign({}, webpackCommon, { ] }); -module.exports = webpackDevConfig; +webpackProdConfig.module.rules = webpackProdConfig.module.rules.filter(rule => ((rule.enforce !== 'pre') || (rule.enforce === 'pre' && rule.loader !== 'source-map-loader'))); +webpackProdConfig.module.rules.forEach(loader => { + if (loader.use && loader.use[0].loader === 'style-loader') { + loader.use = loader.use.map(loaderObj => loaderObj.loader.replace('?sourceMap', '')); + } +}); +webpackProdConfig.module.rules.push({test: /config.json$/, use: [{loader:'config-json-loader'}]}); +module.exports = webpackProdConfig; |