diff options
author | Einav Weiss Keidar <einavw@amdocs.com> | 2018-03-20 14:45:40 +0200 |
---|---|---|
committer | Avi Gaffa <avi.gaffa@amdocs.com> | 2018-03-20 13:52:31 +0000 |
commit | 7fdf733a64670fceefc3ded35cfa581e1c458179 (patch) | |
tree | b3623ac9a331473830cb0167c0b487f2a176427c | |
parent | c7916a4e5955ccc5f0f5252307363b791ec5c7b9 (diff) |
Adding Prettier and fixing up eslint version
Issue-ID: SDC-1094
Change-Id: Ie83ad95a03899345dd90235daf0323cbe3bc6afd
Signed-off-by: Einav Weiss Keidar <einavw@amdocs.com>
414 files changed, 38166 insertions, 27110 deletions
diff --git a/dox-sequence-diagram-ui/.prettierrc b/dox-sequence-diagram-ui/.prettierrc new file mode 100644 index 0000000000..40321d4ab2 --- /dev/null +++ b/dox-sequence-diagram-ui/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 +}
\ No newline at end of file diff --git a/dox-sequence-diagram-ui/eslintrc.json b/dox-sequence-diagram-ui/eslintrc.json index b2a3f24aaa..01b65f3845 100644 --- a/dox-sequence-diagram-ui/eslintrc.json +++ b/dox-sequence-diagram-ui/eslintrc.json @@ -1,32 +1,110 @@ { - "parserOptions": { - "ecmaVersion": 6, - "sourceType": "module", - "ecmaFeatures": { - "jsx": true + "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "classes": true, + "modules": true, + "experimentalDecorators": true + } + }, + "env": { + "es6": true, + "jquery": true, + "node": true, + "jest": true + }, + "plugins": ["react", "import", "prettier"], + "extends": ["prettier"], + "globals": { + "Event": true, + "window": true, + "navigator": true, + "System": true, + "document": true, + "localStorage": true, + "sessionStorage": true, + "Image": true, + "requestAnimationFrame": true, + "cancelAnimationFrame": true, + "DEBUG": true, + "SVGElement": true, + "FormData": true, + "DEV": true, + "Blob": true, + "XMLHttpRequest": true, + "WebSocket": true, + "URL": true, + "PunchOutRegistry": true, + "it": true, + "describe": true + }, + "rules": { + "prettier/prettier": [ + "error", + { + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 + } + ], + "linebreak-style": 0, + "no-unused-vars": 2, + "no-bitwise": 0, + "no-eq-null": 2, + "eqeqeq": 2, + "no-unused-expressions": 2, + "no-use-before-define": 2, + "new-cap": [ + 2, + { + "capIsNewExceptions": ["DataTable", "V"] + } + ], + "no-caller": 2, + "no-empty": 2, + "no-undef": 2, + "quotes": [2, "single", "avoid-escape"], + "no-plusplus": 0, + "no-cond-assign": [2, "except-parens"], + "no-invalid-this": 0, + "dot-notation": 0, + "camelcase": [ + 2, + { + "properties": "never" + } + ], + "curly": 2, + "semi": [2, "always"], + "import/default": 0, + "import/no-unresolved": 0, + "import/no-named-as-default": 2, + "import/no-duplicates": 0, + "import/imports-first": 2, + "import/export": 2, + "react/display-name": 0, + "react/forbid-prop-types": 0, + "react/jsx-boolean-value": 0, + "react/jsx-no-duplicate-props": 1, + "react/jsx-no-literals": 0, + "react/jsx-no-undef": 1, + "react/jsx-sort-prop-types": 0, + "react/jsx-sort-props": 0, + "react/jsx-uses-react": 1, + "react/jsx-uses-vars": 1, + "react/no-danger": 1, + "react/no-did-mount-set-state": 2, + "react/no-did-update-set-state": 2, + "react/no-direct-mutation-state": 1, + "react/no-multi-comp": 0, + "react/no-set-state": 0, + "react/no-unknown-property": 1, + "react/prop-types": 0, + "react/react-in-jsx-scope": 1, + "react/self-closing-comp": 1, + "react/sort-comp": 0 } - }, - "env": { - "browser": true - }, - "plugins": [ - "react" - ], - "extends": [ - "airbnb" - ], - "rules": { - "padded-blocks": 0, - "max-len": ["error", 160, 4], - "no-underscore-dangle": 0, - "global-require": 0, - "react/sort-comp": 0, - "new-cap": 0 - }, - "settings": { - "react": { - "pragma": "React", - "version": "0.14.8" - } - } } diff --git a/dox-sequence-diagram-ui/package.json b/dox-sequence-diagram-ui/package.json index aa9976e31e..dbbfd8465f 100644 --- a/dox-sequence-diagram-ui/package.json +++ b/dox-sequence-diagram-ui/package.json @@ -1,57 +1,59 @@ { - "name": "dox-sequence-diagram-ui", - "version": "1.0.0", - "description": "", - "main": "dist/index.js", - "scripts": { - "build": "webpack", - "start": "webpack-dev-server", - "lint": "eslint . --ext .js --ext .jsx --cache" - }, - "author": "ONAP", - "license": "SEE LICENSE IN LICENSE", - "dependencies": { - "d3": "^4.10.0", - "lodash": "^4.12.0", - "prop-types": "^15.6.0", - "react": "^15.6.2", - "react-dnd": "^2.5.4", - "react-dnd-html5-backend": "^2.5.4", - "react-dom": "^15.6.2", - "react-redux": "^5.0.6", - "react-select": "1.2.1", - "redux": "^3.7.2" - }, - "devDependencies": { - "babel-core": "^6.26.0", - "babel-eslint": "^8.2.1", - "babel-loader": "^7.1.2", - "babel-plugin-lodash": "^3.3.2", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.5.0", - "copy": "^0.2.0", - "css-loader": "^0.28.7", - "eslint": "^2.10.2", - "eslint-config-airbnb": "^9.0.1", - "eslint-loader": "^1.3.0", - "eslint-plugin-import": "^1.8.0", - "eslint-plugin-jsx-a11y": "^1.2.2", - "eslint-plugin-react": "^5.1.1", - "file-loader": "^1.1.6", - "node-sass": "^4.7.2", - "path": "^0.12.7", - "raw-loader": "^0.5.1", - "redux-devtools": "^3.3.1", - "sass-loader": "^6.0.6", - "style-loader": "^0.19.1", - "svg-sprite-loader": "0.0.19", - "url-loader": "^0.6.2", - "webpack": "^2.2.1", - "webpack-dev-server": "^2.4.2" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0", - "yarn": "^1.3.2" - } -}
\ No newline at end of file + "name": "dox-sequence-diagram-ui", + "version": "1.0.0", + "description": "", + "main": "dist/index.js", + "scripts": { + "build": "webpack", + "start": "webpack-dev-server", + "lint": "eslint . --ext .js --ext .jsx --cache -c eslintrc.json", + "lint-fix": "eslint --fix -c eslintrc.json --ext .js --ext .jsx src" + }, + "author": "ONAP", + "license": "SEE LICENSE IN LICENSE", + "dependencies": { + "d3": "^4.10.0", + "lodash": "^4.12.0", + "prop-types": "^15.6.0", + "react": "^15.6.2", + "react-dnd": "^2.5.4", + "react-dnd-html5-backend": "^2.5.4", + "react-dom": "^15.6.2", + "react-redux": "^5.0.6", + "react-select": "1.2.1", + "redux": "^3.7.2" + }, + "devDependencies": { + "babel-core": "^6.26.0", + "babel-eslint": "^8.2.1", + "babel-loader": "^7.1.2", + "babel-plugin-lodash": "^3.3.2", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.5.0", + "copy": "^0.2.0", + "css-loader": "^0.28.7", + "eslint": "^4.18.1", + "eslint-config-prettier": "^2.9.0", + "eslint-loader": "^1.9.0", + "eslint-plugin-import": "^2.9.0", + "eslint-plugin-prettier": "^2.6.0", + "eslint-plugin-react": "^7.7.0", + "file-loader": "^1.1.6", + "node-sass": "^4.7.2", + "path": "^0.12.7", + "prettier": "^1.10.2", + "raw-loader": "^0.5.1", + "redux-devtools": "^3.3.1", + "sass-loader": "^6.0.6", + "style-loader": "^0.19.1", + "svg-sprite-loader": "0.0.19", + "url-loader": "^0.6.2", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.4.2" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0", + "yarn": "^1.3.2" + } +} diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx index fc2bfbc0e3..c0e9483e92 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/Sequencer.jsx @@ -28,176 +28,177 @@ import '../../../../res/sdc-sequencer.scss'; * ASDC Sequencer entry point. */ class Sequencer extends React.Component { + // ////////////////////////////////////////////////////////////////////////////////////////////// - // ////////////////////////////////////////////////////////////////////////////////////////////// - - constructor(props, context) { - super(props, context); - - - this.setMetamodel.bind(this); - this.setModel.bind(this); - this.getModel.bind(this); - this.getMetamodel.bind(this); - this.getSVG.bind(this); - this.getDemoScenarios.bind(this); - this.newModel.bind(this); - - // Parse options. - - this.options = new Options(props.options); - - // Default scenarios. - - const scenarios = this.getDemoScenarios(); - this.setMetamodel(scenarios.getMetamodels()); - - // this.setModel(scenarios.getBlank()); - this.setModel(scenarios.getDimensions()); - // this.setModel(scenarios.getECOMP()); - - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Optionally save known metamodels so that subsequent loading and unloading - * of models needn't include the corresponding metamodel. - * @param metamodels array of conformant metamodel JSON definitions. - * @return this. - */ - setMetamodel(metamodels) { - Common.assertType(metamodels, 'Array'); - this.metamodels = new Metamodels(metamodels); - return this; - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set current diagram. - * @param modelJSON JSON diagram spec. - * @param metamodelIdOrDefinition optional metamodel definition or reference. Defaults to - * the model's metadata @ref, or the default (permissive) metamodel. - * @return this. - */ - setModel(modelJSON, metamodelIdOrDefinition) { - Common.assertType(modelJSON, 'Object'); - const ref = (modelJSON.metadata) ? modelJSON.metadata.ref : undefined; - const metamodel = this.getMetamodel(metamodelIdOrDefinition || ref); - Common.assertInstanceOf(metamodel, Metamodel); - this.model = new Model(modelJSON, metamodel); - if (this.application) { - this.application.setModel(this.model); + constructor(props, context) { + super(props, context); + + this.setMetamodel.bind(this); + this.setModel.bind(this); + this.getModel.bind(this); + this.getMetamodel.bind(this); + this.getSVG.bind(this); + this.getDemoScenarios.bind(this); + this.newModel.bind(this); + + // Parse options. + + this.options = new Options(props.options); + + // Default scenarios. + + const scenarios = this.getDemoScenarios(); + this.setMetamodel(scenarios.getMetamodels()); + + // this.setModel(scenarios.getBlank()); + this.setModel(scenarios.getDimensions()); + // this.setModel(scenarios.getECOMP()); } - return this; - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get current diagram state. At any given instant the diagram might not make *sense* - * but it should always be syntactically valid. - * @return current Model. - */ - getModel() { - - if (this.application) { - const model = this.application.getModel(); - if (model) { - return model.unwrap(); - } + + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Optionally save known metamodels so that subsequent loading and unloading + * of models needn't include the corresponding metamodel. + * @param metamodels array of conformant metamodel JSON definitions. + * @return this. + */ + setMetamodel(metamodels) { + Common.assertType(metamodels, 'Array'); + this.metamodels = new Metamodels(metamodels); + return this; } - return this.model; - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Extract SVG element. - * @return stringified SVG element. - */ - getSVG() { - return this.application.getSVG(); - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get demo scenarios, allowing initialization in demo mode from the outside. - * @returns {Scenarios} - */ - getDemoScenarios() { - return new Scenarios(); - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Create new model. - * @param metamodelIdOrDefinition - * @return newly-created model. - */ - newModel(metamodelIdOrDefinition) { - const metamodel = this.getMetamodel(metamodelIdOrDefinition); - Common.assertInstanceOf(metamodel, Metamodel); - const model = new Model({}, metamodel); - if (this.application) { - this.application.setModel(model); + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set current diagram. + * @param modelJSON JSON diagram spec. + * @param metamodelIdOrDefinition optional metamodel definition or reference. Defaults to + * the model's metadata @ref, or the default (permissive) metamodel. + * @return this. + */ + setModel(modelJSON, metamodelIdOrDefinition) { + Common.assertType(modelJSON, 'Object'); + const ref = modelJSON.metadata ? modelJSON.metadata.ref : undefined; + const metamodel = this.getMetamodel(metamodelIdOrDefinition || ref); + Common.assertInstanceOf(metamodel, Metamodel); + this.model = new Model(modelJSON, metamodel); + if (this.application) { + this.application.setModel(this.model); + } + return this; } - return model; - } - - // ////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get Metamodel instance corresponding to an ID or JSON definition. - * @param metamodelIdOrDefinition String ID or JSON definition. - * @returns Metamodel instance. - * @private - */ - getMetamodel(metamodelIdOrDefinition) { - const metamodelType = Common.getType(metamodelIdOrDefinition); - if (metamodelType === 'Object') { - return new Metamodel(metamodelIdOrDefinition); + + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get current diagram state. At any given instant the diagram might not make *sense* + * but it should always be syntactically valid. + * @return current Model. + */ + getModel() { + if (this.application) { + const model = this.application.getModel(); + if (model) { + return model.unwrap(); + } + } + + return this.model; } - return this.metamodels.getMetamodelOrDefault(metamodelIdOrDefinition); - } - // ////////////////////////////////////////////////////////////////////////////////////////////// + // ////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Render current diagram state. - */ - render() { + /** + * Extract SVG element. + * @return stringified SVG element. + */ + getSVG() { + return this.application.getSVG(); + } - if (this.props.model) { + // ////////////////////////////////////////////////////////////////////////////////////////////// - // If a model was specified as a property, apply it. Otherwise - // fall back to the demo model. + /** + * Get demo scenarios, allowing initialization in demo mode from the outside. + * @returns {Scenarios} + */ + getDemoScenarios() { + return new Scenarios(); + } - const scenarios = this.getDemoScenarios(); - const metamodel = [scenarios.getBlankMetamodel(), scenarios.getECOMPMetamodel()]; - if (this.props.metamodel) { - metamodel.push(this.props.metamodel); - } - this.setMetamodel(metamodel); - this.setModel(this.props.model); + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Create new model. + * @param metamodelIdOrDefinition + * @return newly-created model. + */ + newModel(metamodelIdOrDefinition) { + const metamodel = this.getMetamodel(metamodelIdOrDefinition); + Common.assertInstanceOf(metamodel, Metamodel); + const model = new Model({}, metamodel); + if (this.application) { + this.application.setModel(model); + } + return model; } - return ( - <Application options={this.options} sequencer={this} ref={(a) => { this.application = a; }} /> - ); - } + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get Metamodel instance corresponding to an ID or JSON definition. + * @param metamodelIdOrDefinition String ID or JSON definition. + * @returns Metamodel instance. + * @private + */ + getMetamodel(metamodelIdOrDefinition) { + const metamodelType = Common.getType(metamodelIdOrDefinition); + if (metamodelType === 'Object') { + return new Metamodel(metamodelIdOrDefinition); + } + return this.metamodels.getMetamodelOrDefault(metamodelIdOrDefinition); + } + // ////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render current diagram state. + */ + render() { + if (this.props.model) { + // If a model was specified as a property, apply it. Otherwise + // fall back to the demo model. + + const scenarios = this.getDemoScenarios(); + const metamodel = [ + scenarios.getBlankMetamodel(), + scenarios.getECOMPMetamodel() + ]; + if (this.props.metamodel) { + metamodel.push(this.props.metamodel); + } + this.setMetamodel(metamodel); + this.setModel(this.props.model); + } + + return ( + <Application + options={this.options} + sequencer={this} + ref={a => { + this.application = a; + }} + /> + ); + } } Sequencer.propTypes = { - options: PropTypes.object.isRequired, - model: PropTypes.object, - metamodel: PropTypes.object, + options: PropTypes.object.isRequired, + model: PropTypes.object, + metamodel: PropTypes.object }; - export default Sequencer; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js index 7337367dca..1c6bd69dc2 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Common.js @@ -18,339 +18,347 @@ * Common operations. */ export default class Common { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Retrieve and start a simple timer. Retrieve elapsed time by calling #ms(). + * @returns {*} + */ + static timer() { + const start = new Date().getTime(); + return { + ms() { + return new Date().getTime() - start; + } + }; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Retrieve and start a simple timer. Retrieve elapsed time by calling #ms(). - * @returns {*} - */ - static timer() { - const start = new Date().getTime(); - return { - ms() { - return (new Date().getTime() - start); - }, - }; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get datatype, stripping '[object Boolean]' to just 'Boolean'. - * @param o JS object. - * @return String like String, Number, Date, Null, Undefined, stuff like that. - */ - static getType(o) { - const str = Object.prototype.toString.call(o); - const prefix = '[object '; - if (str.substr(str, prefix.length) === prefix) { - return str.substr(prefix.length, str.length - (prefix.length + 1)); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get datatype, stripping '[object Boolean]' to just 'Boolean'. + * @param o JS object. + * @return String like String, Number, Date, Null, Undefined, stuff like that. + */ + static getType(o) { + const str = Object.prototype.toString.call(o); + const prefix = '[object '; + if (str.substr(str, prefix.length) === prefix) { + return str.substr(prefix.length, str.length - (prefix.length + 1)); + } + return str; } - return str; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert that an argument was provided. - * @param value to be checked. - * @param message message on assertion failure. - * @return value. - */ - static assertNotNull(value, message = 'Unexpected null value') { - if (!value) { - throw new Error(message); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert that an argument was provided. + * @param value to be checked. + * @param message message on assertion failure. + * @return value. + */ + static assertNotNull(value, message = 'Unexpected null value') { + if (!value) { + throw new Error(message); + } + return value; } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert argument type. - * @param value to be checked. - * @param expected expected type string, e,g. Number from [object Number]. - * @return value. - */ - static assertType(value, expected) { - const type = this.getType(value); - if (type !== expected) { - throw new Error(`Expected type ${expected}, got ${type}`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert argument type. + * @param value to be checked. + * @param expected expected type string, e,g. Number from [object Number]. + * @return value. + */ + static assertType(value, expected) { + const type = this.getType(value); + if (type !== expected) { + throw new Error(`Expected type ${expected}, got ${type}`); + } + return value; } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert argument type. - * @param value to be checked. - * @param unexpected unexpected type string, e,g. Number from [object Number]. - * @return value. - */ - static assertNotType(value, unexpected) { - const type = this.getType(value); - if (type === unexpected) { - throw new Error(`Forbidden type "${unexpected}"`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert argument type. + * @param value to be checked. + * @param unexpected unexpected type string, e,g. Number from [object Number]. + * @return value. + */ + static assertNotType(value, unexpected) { + const type = this.getType(value); + if (type === unexpected) { + throw new Error(`Forbidden type "${unexpected}"`); + } + return value; } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert argument is a simple JSON object, and specifically not (something like an) ES6 class. - * @param value to be checked. - * @return value. - */ - static assertPlainObject(value) { - Common.assertType(value, 'Object'); - // TODO - /* + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert argument is a simple JSON object, and specifically not (something like an) ES6 class. + * @param value to be checked. + * @return value. + */ + static assertPlainObject(value) { + Common.assertType(value, 'Object'); + // TODO + /* if (!($.isPlainObject(value))) { throw new Error(`Expected plain object: ${value}`); } */ - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert argument type. - * @param value to be checked. - * @param c expected class. - * @return value. - */ - static assertInstanceOf(value, c) { - Common.assertNotNull(value); - if (!(value instanceof c)) { - throw new Error(`Expected instanceof ${c}: ${value}`); - } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert that a string matches a regex. - * @param value value to be tested. - * @param re pattern to be applied. - * @return value. - */ - static assertMatches(value, re) { - this.assertType(value, 'String'); - this.assertType(re, 'RegExp'); - if (!re.test(value)) { - throw new Error(`Value ${value} doesn't match pattern ${re}`); + return value; } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Assert the value of a boolean. - * - * @param bool to be checked. - * @param message optional message on assertion failure. - * @return value. - */ - static assertThat(bool, message) { - if (!bool) { - throw new Error(message || `Unexpected: ${bool}`); - } - return bool; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Verify that a value, generally a function arg, is a DOM element. - * @param value to be checked. - * @return value. - */ - static assertHTMLElement(value) { - if (!Common.isHTMLElement(value)) { - throw new Error(`Expected HTMLElement: ${value}`); - } - return value; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Check whether a value, generally a function arg, is an HTML DOM element. - * @param o to be checked. - * @return true if DOM element. - */ - static isHTMLElement(o) { - if (typeof HTMLElement === 'object') { - return o instanceof HTMLElement; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert argument type. + * @param value to be checked. + * @param c expected class. + * @return value. + */ + static assertInstanceOf(value, c) { + Common.assertNotNull(value); + if (!(value instanceof c)) { + throw new Error(`Expected instanceof ${c}: ${value}`); + } + return value; } - return o && typeof o === 'object' && o !== null - && o.nodeType === 1 && typeof o.nodeName === 'string'; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Check if a string is non-empty. - * @param s string to be checked. - * @returns false if non-blank string, true otherwise. - */ - static isBlank(s) { - if (Common.getType(s) === 'String') { - return (s.trim().length === 0); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert that a string matches a regex. + * @param value value to be tested. + * @param re pattern to be applied. + * @return value. + */ + static assertMatches(value, re) { + this.assertType(value, 'String'); + this.assertType(re, 'RegExp'); + if (!re.test(value)) { + throw new Error(`Value ${value} doesn't match pattern ${re}`); + } + return value; } - return true; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Detect dates that are numbers, milli/seconds since epoch.. - * - * @param n candidate number. - * @returns {boolean} - */ - static isNumber(n) { - return !isNaN(parseFloat(n)) && isFinite(n); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Parse the text output from a template to a DOM element. - * @param txt input text. - * @returns {Element} - */ - static txt2dom(txt) { - return new DOMParser().parseFromString(txt, 'image/svg+xml').documentElement; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Recursively convert a DOM element to an SVG (namespaced) element. Otherwise - * you get HTML elements that *happen* to have SVG names, but which aren't actually SVG. - * - * @param node DOM node to be converted. - * @param svg to be updated. - * @returns {*} for chaining. - */ - static dom2svg(node, svg) { - - Common.assertNotType(node, 'String'); - - if (node.childNodes && node.childNodes.length > 0) { - - for (const c of node.childNodes) { - switch (c.nodeType) { - case document.TEXT_NODE: - svg.text(c.nodeValue); - break; - default: - break; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Assert the value of a boolean. + * + * @param bool to be checked. + * @param message optional message on assertion failure. + * @return value. + */ + static assertThat(bool, message) { + if (!bool) { + throw new Error(message || `Unexpected: ${bool}`); } - } - - for (const c of node.childNodes) { - switch (c.nodeType) { - case document.ELEMENT_NODE: - Common.dom2svg(c, svg.append(`svg:${c.nodeName.toLowerCase()}`)); - break; - default: - break; + return bool; + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Verify that a value, generally a function arg, is a DOM element. + * @param value to be checked. + * @return value. + */ + static assertHTMLElement(value) { + if (!Common.isHTMLElement(value)) { + throw new Error(`Expected HTMLElement: ${value}`); } - } + return value; } - if (node.hasAttributes()) { - for (let i = 0; i < node.attributes.length; i++) { - const a = node.attributes.item(i); - svg.attr(a.name, a.value); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Check whether a value, generally a function arg, is an HTML DOM element. + * @param o to be checked. + * @return true if DOM element. + */ + static isHTMLElement(o) { + /* eslint-disable no-undef */ + if (typeof HTMLElement === 'object') { + return o instanceof HTMLElement; + } + /* eslint-enable no-undef */ + return ( + o && + typeof o === 'object' && + o !== null && + o.nodeType === 1 && + typeof o.nodeName === 'string' + ); } - return svg; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get the lines to be shown in the label. - * - * @param labelText original label text. - * @param wordWrapAt chars at which to break words. - * @param lineWrapAt chars at which to wrap. - * @param maximumLines lines at which to truncate. - * @returns {Array} - */ - static tokenize(labelText = '', wordWrapAt, lineWrapAt, maximumLines) { - - let l = labelText; - - // Hyphenate and break long words. - - const regex = new RegExp(`(\\w{${wordWrapAt - 1}})(?=\\w)`, 'g'); - l = l.replace(regex, '$1- '); - - const labelTokens = l.split(/\s+/); - const lines = []; - let label = ''; - for (const labelToken of labelTokens) { - if (label.length > 0) { - const length = label.length + labelToken.length + 1; - if (length > lineWrapAt) { - lines.push(label.trim()); - label = labelToken; - continue; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Check if a string is non-empty. + * @param s string to be checked. + * @returns false if non-blank string, true otherwise. + */ + static isBlank(s) { + if (Common.getType(s) === 'String') { + return s.trim().length === 0; } - } - label = `${label} ${labelToken}`; + return true; } - if (label) { - lines.push(label.trim()); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Detect dates that are numbers, milli/seconds since epoch.. + * + * @param n candidate number. + * @returns {boolean} + */ + static isNumber(n) { + return !isNaN(parseFloat(n)) && isFinite(n); } - const truncated = lines.slice(0, maximumLines); - if (truncated.length < lines.length) { - let finalLine = truncated[maximumLines - 1]; - if (finalLine.length > (lineWrapAt - 4)) { - finalLine = finalLine.substring(0, lineWrapAt - 4); - } - finalLine = `${finalLine} ...`; - truncated[maximumLines - 1] = finalLine; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Parse the text output from a template to a DOM element. + * @param txt input text. + * @returns {Element} + */ + static txt2dom(txt) { + /* eslint-disable no-undef */ + return new DOMParser().parseFromString(txt, 'image/svg+xml') + .documentElement; + /* eslint-enable no-undef */ } - return truncated; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Brutally sanitize an input string. We have no syntax rules, and hence no specific - * rules to apply, but we have very few unconstrained fields, so we can implement a - * crude default and devolve the rest to options. - * @param value value to be sanitized. - * @param options control options including validation rules. - * @param type validation type. - * @returns {*} sanitized string. - * @private - */ - static sanitizeText(value, options, type) { - const rules = Common.assertNotNull(options.validation[type]); - let v = value || rules.defaultValue || ''; - if (rules.replace) { - v = v.replace(rules.replace, ''); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Recursively convert a DOM element to an SVG (namespaced) element. Otherwise + * you get HTML elements that *happen* to have SVG names, but which aren't actually SVG. + * + * @param node DOM node to be converted. + * @param svg to be updated. + * @returns {*} for chaining. + */ + static dom2svg(node, svg) { + Common.assertNotType(node, 'String'); + + if (node.childNodes && node.childNodes.length > 0) { + for (const c of node.childNodes) { + switch (c.nodeType) { + case document.TEXT_NODE: + svg.text(c.nodeValue); + break; + default: + break; + } + } + + for (const c of node.childNodes) { + switch (c.nodeType) { + case document.ELEMENT_NODE: + Common.dom2svg( + c, + svg.append(`svg:${c.nodeName.toLowerCase()}`) + ); + break; + default: + break; + } + } + } + + if (node.hasAttributes()) { + for (let i = 0; i < node.attributes.length; i++) { + const a = node.attributes.item(i); + svg.attr(a.name, a.value); + } + } + + return svg; } - if (v.length > rules.maxLength) { - v = `${v.substring(0, rules.maxLength)}...`; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get the lines to be shown in the label. + * + * @param labelText original label text. + * @param wordWrapAt chars at which to break words. + * @param lineWrapAt chars at which to wrap. + * @param maximumLines lines at which to truncate. + * @returns {Array} + */ + static tokenize(labelText = '', wordWrapAt, lineWrapAt, maximumLines) { + let l = labelText; + + // Hyphenate and break long words. + + const regex = new RegExp(`(\\w{${wordWrapAt - 1}})(?=\\w)`, 'g'); + l = l.replace(regex, '$1- '); + + const labelTokens = l.split(/\s+/); + const lines = []; + let label = ''; + for (const labelToken of labelTokens) { + if (label.length > 0) { + const length = label.length + labelToken.length + 1; + if (length > lineWrapAt) { + lines.push(label.trim()); + label = labelToken; + continue; + } + } + label = `${label} ${labelToken}`; + } + + if (label) { + lines.push(label.trim()); + } + + const truncated = lines.slice(0, maximumLines); + if (truncated.length < lines.length) { + let finalLine = truncated[maximumLines - 1]; + if (finalLine.length > lineWrapAt - 4) { + finalLine = finalLine.substring(0, lineWrapAt - 4); + } + finalLine = `${finalLine} ...`; + truncated[maximumLines - 1] = finalLine; + } + + return truncated; } - return v; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Brutally sanitize an input string. We have no syntax rules, and hence no specific + * rules to apply, but we have very few unconstrained fields, so we can implement a + * crude default and devolve the rest to options. + * @param value value to be sanitized. + * @param options control options including validation rules. + * @param type validation type. + * @returns {*} sanitized string. + * @private + */ + static sanitizeText(value, options, type) { + const rules = Common.assertNotNull(options.validation[type]); + let v = value || rules.defaultValue || ''; + if (rules.replace) { + v = v.replace(rules.replace, ''); + } + if (v.length > rules.maxLength) { + v = `${v.substring(0, rules.maxLength)}...`; + } + return v; + } } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js index 187f49bb08..8b6ae67ca7 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Logger.js @@ -23,108 +23,107 @@ import Common from './Common'; * disable them for production. */ export default class Logger { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * No-op call so that we can leave imports in place, + * even when there's no debugging. + */ + static noop() { + // Nothing. + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set debug level. + * @param level threshold. + */ + static setLevel(level) { + this.level = Logger.OFF; + if (Common.getType(level) === 'Number') { + this.level = level; + } else { + this.level = Logger[level]; + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get debug level. + * @returns {number|*} + */ + static getLevel() { + return this.level; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * No-op call so that we can leave imports in place, - * even when there's no debugging. - */ - static noop() { - // Nothing. - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set debug level. - * @param level threshold. - */ - static setLevel(level) { - this.level = Logger.OFF; - if (Common.getType(level) === 'Number') { - this.level = level; - } else { - this.level = Logger[level]; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Write DEBUG-level log. + * @param msg message or tokens. + */ + static debug(...msg) { + if (this.level >= Logger.DEBUG) { + const out = this.serialize(msg); + console.info(`ASDCS [DEBUG] ${out}`); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get debug level. - * @returns {number|*} - */ - static getLevel() { - return this.level; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Write DEBUG-level log. - * @param msg message or tokens. - */ - static debug(...msg) { - if (this.level >= Logger.DEBUG) { - const out = this.serialize(msg); - console.info(`ASDCS [DEBUG] ${out}`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Write INFO-level log. + * @param msg message or tokens. + */ + static info(...msg) { + if (this.level >= Logger.INFO) { + const out = this.serialize(msg); + console.info(`ASDCS [INFO] ${out}`); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Write INFO-level log. - * @param msg message or tokens. - */ - static info(...msg) { - if (this.level >= Logger.INFO) { - const out = this.serialize(msg); - console.info(`ASDCS [INFO] ${out}`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Write debug. + * @param msg message or tokens. + */ + static warn(msg) { + if (this.level >= Logger.WARN) { + const out = this.serialize(msg); + console.warn(`ASDCS [WARN] ${out}`); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Write debug. - * @param msg message or tokens. - */ - static warn(msg) { - if (this.level >= Logger.WARN) { - const out = this.serialize(msg); - console.warn(`ASDCS [WARN] ${out}`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Write error. + * @param msg message or tokens. + */ + static error(...msg) { + if (this.level >= Logger.ERROR) { + const out = this.serialize(msg); + console.error(`ASDCS [ERROR] ${out}`); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Write error. - * @param msg message or tokens. - */ - static error(...msg) { - if (this.level >= Logger.ERROR) { - const out = this.serialize(msg); - console.error(`ASDCS [ERROR] ${out}`); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Serialize msg. + * @param msg message or tokens. + * @returns {string} + */ + static serialize(...msg) { + let out = ''; + msg.forEach(token => { + out = `${out}${token}`; + }); + return out; } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Serialize msg. - * @param msg message or tokens. - * @returns {string} - */ - static serialize(...msg) { - let out = ''; - msg.forEach((token) => { - out = `${out}${token}`; - }); - return out; - } } // ///////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js index 15897d7ee3..b054cb26e7 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/common/Options.js @@ -23,26 +23,25 @@ import Logger from './Logger'; * and the result -- runtime options -- are available by calling #getOptions(). */ export default class Options { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Construct options, applying defaults. + * @param options optional override options. + */ + constructor(options = {}) { + this.options = _merge({}, Options.DEFAULTS, options); + } - /** - * Construct options, applying defaults. - * @param options optional override options. - */ - constructor(options = {}) { - this.options = _merge({}, Options.DEFAULTS, options); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Unwrap options. - * @returns {*} - */ - unwrap() { - return this.options; - } + /** + * Unwrap options. + * @returns {*} + */ + unwrap() { + return this.options; + } } // ///////////////////////////////////////////////////////////////////////////////////////////////// @@ -51,86 +50,86 @@ export default class Options { * Default options, overridden by anything of the same name. */ Options.DEFAULTS = { - log: { - level: Logger.WARN, - }, - demo: false, - useHtmlSelect: true, - diagram: { - svg: { - x: 0, - y: 0, - width: 1600, - height: 1200, - margin: 50, - floodColor: '#009fdb', - scale: { - height: true, - width: true, - minimum: 0.25, - }, - }, - title: { - height: 0, - }, - metadata: false, - lifelines: { - header: { - height: 225, - width: 350, - wrapWords: 14, - wrapLines: 18, - maxLines: 5, - }, - occurrences: { - marginTop: 50, - marginBottom: 75, - foreshortening: 5, - width: 50, - }, - spacing: { - horizontal: 400, - vertical: 400, - }, - }, - messages: { - label: { - wrapWords: 14, - wrapLines: 18, - maxLines: 4, - }, - }, - fragments: { - leftMargin: 150, - topMargin: 200, - widthMargin: 300, - heightMargin: 350, - label: { - wrapWords: 50, - wrapLines: 50, - maxLines: 2, - }, - }, - }, - validation: { - lifeline: { - maxLength: 100, - defaultValue: '', - replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g, - }, - message: { - maxLength: 100, - defaultValue: '', - replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g, - }, - notes: { - maxLength: 255, - defaultValue: '', + log: { + level: Logger.WARN }, - guard: { - maxLength: 80, - defaultValue: '', - replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g, + demo: false, + useHtmlSelect: true, + diagram: { + svg: { + x: 0, + y: 0, + width: 1600, + height: 1200, + margin: 50, + floodColor: '#009fdb', + scale: { + height: true, + width: true, + minimum: 0.25 + } + }, + title: { + height: 0 + }, + metadata: false, + lifelines: { + header: { + height: 225, + width: 350, + wrapWords: 14, + wrapLines: 18, + maxLines: 5 + }, + occurrences: { + marginTop: 50, + marginBottom: 75, + foreshortening: 5, + width: 50 + }, + spacing: { + horizontal: 400, + vertical: 400 + } + }, + messages: { + label: { + wrapWords: 14, + wrapLines: 18, + maxLines: 4 + } + }, + fragments: { + leftMargin: 150, + topMargin: 200, + widthMargin: 300, + heightMargin: 350, + label: { + wrapWords: 50, + wrapLines: 50, + maxLines: 2 + } + } }, - }, + validation: { + lifeline: { + maxLength: 100, + defaultValue: '', + replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g + }, + message: { + maxLength: 100, + defaultValue: '', + replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g + }, + notes: { + maxLength: 255, + defaultValue: '' + }, + guard: { + maxLength: 80, + defaultValue: '', + replace: /[^\-\.\+ &%#@\?\(\)\[\]<>\w\d]/g + } + } }; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx index 6889e0ab9f..b63e69a4ed 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/application/Application.jsx @@ -28,258 +28,274 @@ import Overlay from '../overlay/Overlay'; * Application controller, also a view. */ class Application extends React.Component { + /** + * Construct application view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + + this.sequencer = Common.assertNotNull(props.sequencer); + this.model = this.sequencer.getModel(); + this.metamodel = this.sequencer.getMetamodel(); + this.options = props.options; + Logger.setLevel(this.options.unwrap().log.level); + + // Bindings. + + this.showInfoDialog = this.showInfoDialog.bind(this); + this.showEditDialog = this.showEditDialog.bind(this); + this.showConfirmDialog = this.showConfirmDialog.bind(this); + this.hideOverlay = this.hideOverlay.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Construct application view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - - this.sequencer = Common.assertNotNull(props.sequencer); - this.model = this.sequencer.getModel(); - this.metamodel = this.sequencer.getMetamodel(); - this.options = props.options; - Logger.setLevel(this.options.unwrap().log.level); - - // Bindings. - - this.showInfoDialog = this.showInfoDialog.bind(this); - this.showEditDialog = this.showEditDialog.bind(this); - this.showConfirmDialog = this.showConfirmDialog.bind(this); - this.hideOverlay = this.hideOverlay.bind(this); - this.onMouseMove = this.onMouseMove.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get application options. - * @returns JSON options, see Options.js. - */ - getOptions() { - return this.options.unwrap(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set diagram name. - * @param n diagram (human-readable) name. - */ - setName(n) { - this.diagram.setName(n); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set diagram model. - * @param model diagram instance. - */ - setModel(model) { - - Common.assertNotNull(model); - - this.model = model; - - if (this.editor) { - this.editor.render(); + /** + * Get application options. + * @returns JSON options, see Options.js. + */ + getOptions() { + return this.options.unwrap(); } - if (this.diagram) { - this.diagram.render(); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set diagram name. + * @param n diagram (human-readable) name. + */ + setName(n) { + this.diagram.setName(n); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get Model wrapper. - * @returns Model. - */ - getModel() { - return this.model; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get SVG element. - * @returns {*} - */ - getSVG() { - return this.diagram.getSVG(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get top-level widget. Provides the demo toolbar with access to the public API. - * @returns {*} - */ - getSequencer() { - return this.sequencer; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Present info dialog. - * @param msg info message. - */ - showInfoDialog(msg) { - this.dialog.showInfoDialog(msg); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Present error dialog. - * @param msg error message. - */ - showErrorDialog(msg) { - this.dialog.showErrorDialog(msg); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Present confirmation dialog. - * @param msg info message. - * @param cb callback function to be invoked on OK. - */ - showConfirmDialog(msg, cb) { - Common.assertType(cb, 'Function'); - this.dialog.showConfirmDialog(msg, cb); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Present edit (textarea) dialog. - * @param msg prompt. - * @param text current edit text. - * @param cb callback function to be invoked on OK, taking the updated text - * as an argument. - */ - showEditDialog(msg, text, cb) { - this.dialog.showEditDialog(msg, text, cb); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Select lifeline by ID. - * @param id lifeline ID. - */ - selectLifeline(id) { - if (this.editor) { - this.editor.selectLifeline(id); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Set diagram model. + * @param model diagram instance. + */ + setModel(model) { + Common.assertNotNull(model); + + this.model = model; + + if (this.editor) { + this.editor.render(); + } + + if (this.diagram) { + this.diagram.render(); + } } - if (this.diagram) { - this.diagram.selectLifeline(id); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get Model wrapper. + * @returns Model. + */ + getModel() { + return this.model; } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Select message by ID. - * @param id message ID. - */ - selectMessage(id) { - if (this.editor) { - this.editor.selectMessage(id); + /** + * Get SVG element. + * @returns {*} + */ + getSVG() { + return this.diagram.getSVG(); } - if (this.diagram) { - this.diagram.selectMessage(id); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get top-level widget. Provides the demo toolbar with access to the public API. + * @returns {*} + */ + getSequencer() { + return this.sequencer; } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * (Re)render just the diagram. - */ - renderDiagram() { - this.diagram.redraw(); - } + /** + * Present info dialog. + * @param msg info message. + */ + showInfoDialog(msg) { + this.dialog.showInfoDialog(msg); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Show overlay between application and modal dialog. - */ - showOverlay() { - if (this.overlay) { - this.overlay.setVisible(true); + /** + * Present error dialog. + * @param msg error message. + */ + showErrorDialog(msg) { + this.dialog.showErrorDialog(msg); } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Present confirmation dialog. + * @param msg info message. + * @param cb callback function to be invoked on OK. + */ + showConfirmDialog(msg, cb) { + Common.assertType(cb, 'Function'); + this.dialog.showConfirmDialog(msg, cb); + } - /** - * Hide overlay between application and modal dialog. - */ - hideOverlay() { - if (this.overlay) { - this.overlay.setVisible(false); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Present edit (textarea) dialog. + * @param msg prompt. + * @param text current edit text. + * @param cb callback function to be invoked on OK, taking the updated text + * as an argument. + */ + showEditDialog(msg, text, cb) { + this.dialog.showEditDialog(msg, text, cb); } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select lifeline by ID. + * @param id lifeline ID. + */ + selectLifeline(id) { + if (this.editor) { + this.editor.selectLifeline(id); + } + if (this.diagram) { + this.diagram.selectLifeline(id); + } + } - /** - * Capture mouse move events, for resize. - * @param event move event. - */ - onMouseMove(event) { - if (this.editor) { - this.editor.onMouseMove(event); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select message by ID. + * @param id message ID. + */ + selectMessage(id) { + if (this.editor) { + this.editor.selectMessage(id); + } + if (this.diagram) { + this.diagram.selectMessage(id); + } } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Propagate mouse event to the editor that manages the resize. - */ - onMouseUp() { - if (this.editor) { - this.editor.onMouseUp(); + /** + * (Re)render just the diagram. + */ + renderDiagram() { + this.diagram.redraw(); } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Render current model state. - */ - render() { + /** + * Show overlay between application and modal dialog. + */ + showOverlay() { + if (this.overlay) { + this.overlay.setVisible(true); + } + } - return ( + // /////////////////////////////////////////////////////////////////////////////////////////////// - <div className="asdcs-control" onMouseMove={this.onMouseMove} onMouseUp={this.onMouseUp}> + /** + * Hide overlay between application and modal dialog. + */ + hideOverlay() { + if (this.overlay) { + this.overlay.setVisible(false); + } + } - <Editor application={this} ref={(r) => { this.editor = r; }} /> - <Diagram application={this} ref={(r) => { this.diagram = r; }} /> - <Dialog application={this} ref={(r) => { this.dialog = r; }} /> - <Export /> - <Overlay application={this} ref={(r) => { this.overlay = r; }} /> + // /////////////////////////////////////////////////////////////////////////////////////////////// - </div> - ); - } + /** + * Capture mouse move events, for resize. + * @param event move event. + */ + onMouseMove(event) { + if (this.editor) { + this.editor.onMouseMove(event); + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Propagate mouse event to the editor that manages the resize. + */ + onMouseUp() { + if (this.editor) { + this.editor.onMouseUp(); + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render current model state. + */ + render() { + return ( + <div + className="asdcs-control" + onMouseMove={this.onMouseMove} + onMouseUp={this.onMouseUp}> + <Editor + application={this} + ref={r => { + this.editor = r; + }} + /> + <Diagram + application={this} + ref={r => { + this.diagram = r; + }} + /> + <Dialog + application={this} + ref={r => { + this.dialog = r; + }} + /> + <Export /> + <Overlay + application={this} + ref={r => { + this.overlay = r; + }} + /> + </div> + ); + } } /** React properties. */ Application.propTypes = { - options: PropTypes.object.isRequired, - sequencer: PropTypes.object.isRequired, + options: PropTypes.object.isRequired, + sequencer: PropTypes.object.isRequired }; export default Application; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx index b3544d7066..129a1afc2b 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/Diagram.jsx @@ -28,898 +28,1013 @@ import Popup from './components/popup/Popup'; * SVG diagram view. */ class Diagram extends React.Component { - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct React view. - * @param props properties. - * @param context context. - */ - constructor(props, context) { - super(props, context); - - this.application = Common.assertNotNull(props.application); - this.options = this.application.getOptions().diagram; - - this.events = {}; - this.state = { - height: 0, - width: 0, - }; - - this.templates = { - diagram: _template(require('./templates/diagram.html')), - lifeline: _template(require('./templates/lifeline.html')), - message: _template(require('./templates/message.html')), - occurrence: _template(require('./templates/occurrence.html')), - fragment: _template(require('./templates/fragment.html')), - title: _template(require('./templates/title.html')), - }; - - this.handleResize = this.handleResize.bind(this); - this.initialTransformX = 0; - this.initialTransformY = 0; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Set diagram name. - * @param n name. - */ - setName(n) { - this.svg.select('').text(n); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get SVG from diagram. - * @returns {*|string} - */ - getSVG() { - const svg = this.svg.node().outerHTML; - return svg.replace('<svg ', '<svg xmlns="http://www.w3.org/2000/svg" '); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Select message by ID. - * @param id message ID. - */ - selectMessage(id) { - const sel = this.svg.selectAll('g.asdcs-diagram-message-container'); - sel.classed('asdcs-active', false); - sel.selectAll('rect.asdcs-diagram-message-bg').attr('filter', null); - if (id) { - const parent = this.svg.select(`g.asdcs-diagram-message-container[data-id="${id}"]`); - parent.classed('asdcs-active', true); - parent.selectAll('rect.asdcs-diagram-message-bg').attr('filter', 'url(#asdcsSvgHighlight)'); - } - this._showNotesPopup(id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Select lifeline by ID. - * @param id lifeline ID. - */ - selectLifeline(id) { - const sel = this.svg.selectAll('g.asdcs-diagram-lifeline-container'); - sel.classed('asdcs-active', false); - sel.selectAll('rect').attr('filter', null); - if (id) { - const parent = this.svg.select(`g.asdcs-diagram-lifeline-container[data-id="${id}"]`); - parent.selectAll('rect').attr('filter', 'url(#asdcsSvgHighlight)'); - parent.classed('asdcs-active', true); - } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle resize, including initial sizing. - */ - handleResize() { - if (this.wrapper) { - const height = this.wrapper.offsetHeight; - const width = this.wrapper.offsetWidth; - if (this.state.height !== height || this.state.width !== width) { - this.setState({ height, width }); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct React view. + * @param props properties. + * @param context context. + */ + constructor(props, context) { + super(props, context); + + this.application = Common.assertNotNull(props.application); + this.options = this.application.getOptions().diagram; + + this.events = {}; + this.state = { + height: 0, + width: 0 + }; + + this.templates = { + diagram: _template(require('./templates/diagram.html')), + lifeline: _template(require('./templates/lifeline.html')), + message: _template(require('./templates/message.html')), + occurrence: _template(require('./templates/occurrence.html')), + fragment: _template(require('./templates/fragment.html')), + title: _template(require('./templates/title.html')) + }; + + this.handleResize = this.handleResize.bind(this); + this.initialTransformX = 0; + this.initialTransformY = 0; } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * (Re)render diagram. - */ - render() { - - const model = this.application.getModel(); - const modelJSON = model.unwrap(); - const name = modelJSON.diagram.metadata.name; - const options = this.application.getOptions(); - const titleHeight = options.diagram.title.height; - const titleClass = (titleHeight && titleHeight > 0) ? `height:${titleHeight}` : 'asdcs-hidden'; - - return ( - <div className="asdcs-diagram"> - <div className={`asdcs-diagram-name ${titleClass}`}>{name}</div> - <div className="asdcs-diagram-svg" ref={(r) => { this.wrapper = r; }}></div> - <Popup visible={false} ref={(r) => { this.popup = r; }} /> - </div> - ); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - redraw() { - this.updateSVG(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Initial render. - */ - componentDidMount() { - window.addEventListener('resize', this.handleResize); - this.updateSVG(); - - // Insurance: - - setTimeout(() => { - this.handleResize(); - }, 500); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - componentWillUnmount() { - window.removeEventListener('resize', this.handleResize); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render on update. - */ - componentDidUpdate() { - this.updateSVG(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Redraw SVG diagram. So far it's fast enough that it doesn't seem to matter whether - * it's completely redrawn. - */ - updateSVG() { - - if (!this.svg) { - const svgparams = _merge({}, this.options.svg); - this.wrapper.innerHTML = this.templates.diagram(svgparams); - this.svg = d3.select(this.wrapper).select('svg'); - } - - if (this.state.height === 0) { - - // We'll get a resize event, and the height will be non-zero when it's actually time. - return; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - if (this.state.height && this.state.width) { - const margin = this.options.svg.margin; - const x = -margin; - const y = -margin; - const height = this.state.height + (margin * 2); - const width = this.state.width + (margin * 2); - const viewBox = `${x} ${y} ${width} ${height}`; - this.svg.attr('viewBox', viewBox); + /** + * Set diagram name. + * @param n name. + */ + setName(n) { + this.svg.select('').text(n); } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // If we've already rendered, then save the current scale/translate so that we - // can reapply it after rendering. - - const gContentSelection = this.svg.selectAll('g.asdcs-diagram-content'); - if (gContentSelection.size() === 1) { - const transform = gContentSelection.attr('transform'); - if (transform) { - this.savedTransform = transform; - } + /** + * Get SVG from diagram. + * @returns {*|string} + */ + getSVG() { + const svg = this.svg.node().outerHTML; + return svg.replace('<svg ', '<svg xmlns="http://www.w3.org/2000/svg" '); } - // Empty the document. We're starting again. - - this.svg.selectAll('.asdcs-diagram-content').remove(); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select message by ID. + * @param id message ID. + */ + selectMessage(id) { + const sel = this.svg.selectAll('g.asdcs-diagram-message-container'); + sel.classed('asdcs-active', false); + sel.selectAll('rect.asdcs-diagram-message-bg').attr('filter', null); + if (id) { + const parent = this.svg.select( + `g.asdcs-diagram-message-container[data-id="${id}"]` + ); + parent.classed('asdcs-active', true); + parent + .selectAll('rect.asdcs-diagram-message-bg') + .attr('filter', 'url(#asdcsSvgHighlight)'); + } + this._showNotesPopup(id); + } - // Extract the model. + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select lifeline by ID. + * @param id lifeline ID. + */ + selectLifeline(id) { + const sel = this.svg.selectAll('g.asdcs-diagram-lifeline-container'); + sel.classed('asdcs-active', false); + sel.selectAll('rect').attr('filter', null); + if (id) { + const parent = this.svg.select( + `g.asdcs-diagram-lifeline-container[data-id="${id}"]` + ); + parent.selectAll('rect').attr('filter', 'url(#asdcsSvgHighlight)'); + parent.classed('asdcs-active', true); + } + } - const model = this.application.getModel(); - if (!model) { - return; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle resize, including initial sizing. + */ + handleResize() { + if (this.wrapper) { + const height = this.wrapper.offsetHeight; + const width = this.wrapper.offsetWidth; + if (this.state.height !== height || this.state.width !== width) { + this.setState({ height, width }); + } + } } - const modelJSON = model.unwrap(); - // Extract dimension options. + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * (Re)render diagram. + */ + render() { + const model = this.application.getModel(); + const modelJSON = model.unwrap(); + const name = modelJSON.diagram.metadata.name; + const options = this.application.getOptions(); + const titleHeight = options.diagram.title.height; + const titleClass = + titleHeight && titleHeight > 0 + ? `height:${titleHeight}` + : 'asdcs-hidden'; + + return ( + <div className="asdcs-diagram"> + <div className={`asdcs-diagram-name ${titleClass}`}>{name}</div> + <div + className="asdcs-diagram-svg" + ref={r => { + this.wrapper = r; + }} + /> + <Popup + visible={false} + ref={r => { + this.popup = r; + }} + /> + </div> + ); + } - const header = this.options.lifelines.header; - const spacing = this.options.lifelines.spacing; + // /////////////////////////////////////////////////////////////////////////////////////////////// - // Make separate container elements so that we can control Z order. + redraw() { + this.updateSVG(); + } - const gContent = this.svg.append('g').attr('class', 'asdcs-diagram-content'); - const gLifelines = gContent.append('g').attr('class', 'asdcs-diagram-lifelines'); - const gCanvas = gContent.append('g').attr('class', 'asdcs-diagram-canvas'); - gCanvas.append('g').attr('class', 'asdcs-diagram-occurrences'); - gCanvas.append('g').attr('class', 'asdcs-diagram-fragments'); - gCanvas.append('g').attr('class', 'asdcs-diagram-messages'); + // /////////////////////////////////////////////////////////////////////////////////////////////// - // Lifelines ----------------------------------------------------------------------------------- + /** + * Initial render. + */ + componentDidMount() { + window.addEventListener('resize', this.handleResize); + this.updateSVG(); - const actorsById = {}; - const positionsByMessageId = {}; - const lifelines = []; - for (const actor of modelJSON.diagram.lifelines) { - const x = (header.width / 2) + (lifelines.length * spacing.horizontal); - Diagram._processLifeline(actor, x); - lifelines.push({ x, actor }); - actorsById[actor.id] = actor; - } + // Insurance: - // Messages ------------------------------------------------------------------------------------ - - // Analyze occurrence information. - - const occurrences = model.analyzeOccurrences(); - const fragments = model.analyzeFragments(); - let y = this.options.lifelines.header.height + spacing.vertical; - let messageIndex = 0; - for (const step of modelJSON.diagram.steps) { - if (step.message) { - positionsByMessageId[step.message.id] = positionsByMessageId[step.message.id] || {}; - positionsByMessageId[step.message.id].y = y; - this._drawMessage(gCanvas, step.message, y, actorsById, - positionsByMessageId, ++messageIndex, occurrences, fragments); - } - y += spacing.vertical; + setTimeout(() => { + this.handleResize(); + }, 500); } - // --------------------------------------------------------------------------------------------- - - // Draw the actual (dashed) lifelines in a background <g>. - - this._drawLifelines(gLifelines, lifelines, y); - - // Initialize mouse event handlers. - - this._initMouseEvents(gLifelines, gCanvas); - - // Scale to fit. - - const bb = gContent.node().getBBox(); - this._initZoom(gContent, bb.width, bb.height); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Draw message into SVG canvas. - * @param gCanvas container. - * @param message message to be rendered. - * @param y current y position. - * @param actorsById actor lookup. - * @param positionsByMessageId x- and y-position of each message. - * @param messageIndex where we are in the set of messages to be rendered. - * @param oData occurrences info. - * @param fData fragments info. - * @private - */ - _drawMessage(gCanvas, message, y, actorsById, positionsByMessageId, - messageIndex, oData, fData) { - - Common.assertNotNull(oData); - - const request = message.type === 'request'; - const fromActor = request ? actorsById[message.from] : actorsById[message.to]; - const toActor = request ? actorsById[message.to] : actorsById[message.from]; - - if (!fromActor) { - Logger.warn(`Cannot draw message ${JSON.stringify(message)}: 'from' not found.`); - return; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - if (!toActor) { - Logger.warn(`Cannot draw message ${JSON.stringify(message)}: 'to' not found.`); - return; + componentWillUnmount() { + window.removeEventListener('resize', this.handleResize); } - // Occurrences. -------------------------------------------------------------------------------- + // /////////////////////////////////////////////////////////////////////////////////////////////// - if (message.occurrence) { - Logger.debug(`Found occurrence for ${message.name}: ${JSON.stringify(message.occurrence)}`); + /** + * Render on update. + */ + componentDidUpdate() { + this.updateSVG(); } - const activeTo = Diagram._calcActive(oData, toActor.id); - this._drawOccurrence(gCanvas, oData, positionsByMessageId, fromActor, message.id); - this._drawOccurrence(gCanvas, oData, positionsByMessageId, toActor, message.id); - const activeFrom = Diagram._calcActive(oData, fromActor.id); - - // Messages. ----------------------------------------------------------------------------------- - - const gMessages = gCanvas.select('g.asdcs-diagram-messages'); - - // Save positions for later. - - const positions = positionsByMessageId[message.id]; - positions.x0 = fromActor.x; - positions.x1 = toActor.x; - - // Calculate. - const leftToRight = fromActor.x < toActor.x; - const loopback = (message.to === message.from); - const x1 = this._calcMessageX(activeTo, toActor.x, true, leftToRight); - const x0 = loopback ? x1 : this._calcMessageX(activeFrom, fromActor.x, false, leftToRight); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Redraw SVG diagram. So far it's fast enough that it doesn't seem to matter whether + * it's completely redrawn. + */ + updateSVG() { + if (!this.svg) { + const svgparams = _merge({}, this.options.svg); + this.wrapper.innerHTML = this.templates.diagram(svgparams); + this.svg = d3.select(this.wrapper).select('svg'); + } - let messagePath; - if (loopback) { + if (this.state.height === 0) { + // We'll get a resize event, and the height will be non-zero when it's actually time. - // To self. + return; + } - messagePath = `M${x1},${y}`; - messagePath = `${messagePath} L${x1 + 200},${y}`; - messagePath = `${messagePath} L${x1 + 200},${y + 50}`; - messagePath = `${messagePath} L${x1},${y + 50}`; - } else { + if (this.state.height && this.state.width) { + const margin = this.options.svg.margin; + const x = -margin; + const y = -margin; + const height = this.state.height + margin * 2; + const width = this.state.width + margin * 2; + const viewBox = `${x} ${y} ${width} ${height}`; + this.svg.attr('viewBox', viewBox); + } - // Between lifelines. + // If we've already rendered, then save the current scale/translate so that we + // can reapply it after rendering. - messagePath = `M${x0},${y}`; - messagePath = `${messagePath} L${x1},${y}`; - } + const gContentSelection = this.svg.selectAll('g.asdcs-diagram-content'); + if (gContentSelection.size() === 1) { + const transform = gContentSelection.attr('transform'); + if (transform) { + this.savedTransform = transform; + } + } - const styles = Diagram._getMessageStyles(message); + // Empty the document. We're starting again. - // Split message over lines. + this.svg.selectAll('.asdcs-diagram-content').remove(); - const messageWithPrefix = `${messageIndex}. ${message.name}`; - const maxLines = this.options.messages.label.maxLines; - const wrapWords = this.options.messages.label.wrapWords; - const wrapLines = this.options.messages.label.wrapLines; - const messageLines = Common.tokenize(messageWithPrefix, wrapWords, wrapLines, maxLines); + // Extract the model. - const messageTxt = this.templates.message({ - id: message.id, - classes: styles.css, - marker: styles.marker, - dasharray: styles.dasharray, - labels: messageLines, - lines: maxLines, - path: messagePath, - index: messageIndex, - x0, x1, y, - }); + const model = this.application.getModel(); + if (!model) { + return; + } + const modelJSON = model.unwrap(); + + // Extract dimension options. + + const header = this.options.lifelines.header; + const spacing = this.options.lifelines.spacing; + + // Make separate container elements so that we can control Z order. + + const gContent = this.svg + .append('g') + .attr('class', 'asdcs-diagram-content'); + const gLifelines = gContent + .append('g') + .attr('class', 'asdcs-diagram-lifelines'); + const gCanvas = gContent + .append('g') + .attr('class', 'asdcs-diagram-canvas'); + gCanvas.append('g').attr('class', 'asdcs-diagram-occurrences'); + gCanvas.append('g').attr('class', 'asdcs-diagram-fragments'); + gCanvas.append('g').attr('class', 'asdcs-diagram-messages'); + + // Lifelines ----------------------------------------------------------------------------------- + + const actorsById = {}; + const positionsByMessageId = {}; + const lifelines = []; + for (const actor of modelJSON.diagram.lifelines) { + const x = header.width / 2 + lifelines.length * spacing.horizontal; + Diagram._processLifeline(actor, x); + lifelines.push({ x, actor }); + actorsById[actor.id] = actor; + } - const messageEl = Common.txt2dom(messageTxt); - const gMessage = gMessages.append('g'); - Common.dom2svg(messageEl, gMessage); + // Messages ------------------------------------------------------------------------------------ + + // Analyze occurrence information. + + const occurrences = model.analyzeOccurrences(); + const fragments = model.analyzeFragments(); + let y = this.options.lifelines.header.height + spacing.vertical; + let messageIndex = 0; + for (const step of modelJSON.diagram.steps) { + if (step.message) { + positionsByMessageId[step.message.id] = + positionsByMessageId[step.message.id] || {}; + positionsByMessageId[step.message.id].y = y; + this._drawMessage( + gCanvas, + step.message, + y, + actorsById, + positionsByMessageId, + ++messageIndex, + occurrences, + fragments + ); + } + y += spacing.vertical; + } - // Set the background's bounding box to that of the text, - // so that they fit snugly. + // --------------------------------------------------------------------------------------------- - const labelBB = gMessage.select('.asdcs-diagram-message-label').node().getBBox(); - gMessage.select('.asdcs-diagram-message-label-bg') - .attr('x', labelBB.x) - .attr('y', labelBB.y) - .attr('height', labelBB.height) - .attr('width', labelBB.width); + // Draw the actual (dashed) lifelines in a background <g>. - // Fragments. ---------------------------------------------------------------------------------- + this._drawLifelines(gLifelines, lifelines, y); - const fragment = fData[message.id]; - if (fragment) { + // Initialize mouse event handlers. - // It ends on this message. + this._initMouseEvents(gLifelines, gCanvas); - this._drawFragment(gCanvas, fragment, positionsByMessageId); + // Scale to fit. + const bb = gContent.node().getBBox(); + this._initZoom(gContent, bb.width, bb.height); } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Draw message into SVG canvas. + * @param gCanvas container. + * @param message message to be rendered. + * @param y current y position. + * @param actorsById actor lookup. + * @param positionsByMessageId x- and y-position of each message. + * @param messageIndex where we are in the set of messages to be rendered. + * @param oData occurrences info. + * @param fData fragments info. + * @private + */ + _drawMessage( + gCanvas, + message, + y, + actorsById, + positionsByMessageId, + messageIndex, + oData, + fData + ) { + Common.assertNotNull(oData); + + const request = message.type === 'request'; + const fromActor = request + ? actorsById[message.from] + : actorsById[message.to]; + const toActor = request + ? actorsById[message.to] + : actorsById[message.from]; + + if (!fromActor) { + Logger.warn( + `Cannot draw message ${JSON.stringify( + message + )}: 'from' not found.` + ); + return; + } - /** - * Draw a single occurrence. - * @param gCanvas container. - * @param oData occurrence data. - * @param positionsByMessageId map of y positions by message ID. - * @param actor wrapper containing lifeline ID (.id), position (.x) and name (.name). - * @param messageId message identifier. - * @private - */ - _drawOccurrence(gCanvas, oData, positionsByMessageId, actor, messageId) { + if (!toActor) { + Logger.warn( + `Cannot draw message ${JSON.stringify( + message + )}: 'to' not found.` + ); + return; + } - Common.assertType(oData, 'Object'); - Common.assertType(positionsByMessageId, 'Object'); - Common.assertType(actor, 'Object'); - Common.assertType(messageId, 'String'); + // Occurrences. -------------------------------------------------------------------------------- - const gOccurrences = gCanvas.select('g.asdcs-diagram-occurrences'); + if (message.occurrence) { + Logger.debug( + `Found occurrence for ${message.name}: ${JSON.stringify( + message.occurrence + )}` + ); + } + const activeTo = Diagram._calcActive(oData, toActor.id); + this._drawOccurrence( + gCanvas, + oData, + positionsByMessageId, + fromActor, + message.id + ); + this._drawOccurrence( + gCanvas, + oData, + positionsByMessageId, + toActor, + message.id + ); + const activeFrom = Diagram._calcActive(oData, fromActor.id); + + // Messages. ----------------------------------------------------------------------------------- + + const gMessages = gCanvas.select('g.asdcs-diagram-messages'); + + // Save positions for later. + + const positions = positionsByMessageId[message.id]; + positions.x0 = fromActor.x; + positions.x1 = toActor.x; + + // Calculate. + + const leftToRight = fromActor.x < toActor.x; + const loopback = message.to === message.from; + const x1 = this._calcMessageX(activeTo, toActor.x, true, leftToRight); + const x0 = loopback + ? x1 + : this._calcMessageX(activeFrom, fromActor.x, false, leftToRight); + + let messagePath; + if (loopback) { + // To self. + + messagePath = `M${x1},${y}`; + messagePath = `${messagePath} L${x1 + 200},${y}`; + messagePath = `${messagePath} L${x1 + 200},${y + 50}`; + messagePath = `${messagePath} L${x1},${y + 50}`; + } else { + // Between lifelines. - const oOptions = this.options.lifelines.occurrences; - const oWidth = oOptions.width; - const oHalfWidth = oWidth / 2; - const oForeshortening = oOptions.foreshortening; - const oMarginTop = oOptions.marginTop; - const oMarginBottom = oOptions.marginBottom; - const o = oData[actor.id]; + messagePath = `M${x0},${y}`; + messagePath = `${messagePath} L${x1},${y}`; + } - const active = Diagram._calcActive(oData, actor.id); + const styles = Diagram._getMessageStyles(message); + + // Split message over lines. + + const messageWithPrefix = `${messageIndex}. ${message.name}`; + const maxLines = this.options.messages.label.maxLines; + const wrapWords = this.options.messages.label.wrapWords; + const wrapLines = this.options.messages.label.wrapLines; + const messageLines = Common.tokenize( + messageWithPrefix, + wrapWords, + wrapLines, + maxLines + ); + + const messageTxt = this.templates.message({ + id: message.id, + classes: styles.css, + marker: styles.marker, + dasharray: styles.dasharray, + labels: messageLines, + lines: maxLines, + path: messagePath, + index: messageIndex, + x0, + x1, + y + }); + + const messageEl = Common.txt2dom(messageTxt); + const gMessage = gMessages.append('g'); + Common.dom2svg(messageEl, gMessage); + + // Set the background's bounding box to that of the text, + // so that they fit snugly. + + const labelBB = gMessage + .select('.asdcs-diagram-message-label') + .node() + .getBBox(); + gMessage + .select('.asdcs-diagram-message-label-bg') + .attr('x', labelBB.x) + .attr('y', labelBB.y) + .attr('height', labelBB.height) + .attr('width', labelBB.width); - const x = (actor.x - oHalfWidth) + (active * oWidth); - const positions = positionsByMessageId[messageId]; - const y = positions.y; + // Fragments. ---------------------------------------------------------------------------------- - let draw = true; - if (o) { + const fragment = fData[message.id]; + if (fragment) { + // It ends on this message. - if (o.start[messageId]) { + this._drawFragment(gCanvas, fragment, positionsByMessageId); + } + } - // Starting, but drawing nothing until we find the end. + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Draw a single occurrence. + * @param gCanvas container. + * @param oData occurrence data. + * @param positionsByMessageId map of y positions by message ID. + * @param actor wrapper containing lifeline ID (.id), position (.x) and name (.name). + * @param messageId message identifier. + * @private + */ + _drawOccurrence(gCanvas, oData, positionsByMessageId, actor, messageId) { + Common.assertType(oData, 'Object'); + Common.assertType(positionsByMessageId, 'Object'); + Common.assertType(actor, 'Object'); + Common.assertType(messageId, 'String'); + + const gOccurrences = gCanvas.select('g.asdcs-diagram-occurrences'); + + const oOptions = this.options.lifelines.occurrences; + const oWidth = oOptions.width; + const oHalfWidth = oWidth / 2; + const oForeshortening = oOptions.foreshortening; + const oMarginTop = oOptions.marginTop; + const oMarginBottom = oOptions.marginBottom; + const o = oData[actor.id]; + + const active = Diagram._calcActive(oData, actor.id); + + const x = actor.x - oHalfWidth + active * oWidth; + const positions = positionsByMessageId[messageId]; + const y = positions.y; + + let draw = true; + if (o) { + if (o.start[messageId]) { + // Starting, but drawing nothing until we find the end. + + o.active.push(messageId); + draw = false; + } else if (active > 0) { + const startMessageId = o.stop[messageId]; + if (startMessageId) { + // OK, it ends here. Draw the occurrence box. + + o.active.pop(); + const foreshorteningY = active * oForeshortening; + const startY = positionsByMessageId[startMessageId].y; + const height = + oMarginTop + + oMarginBottom + + (y - startY) - + foreshorteningY * 2; + const oProps = { + x: actor.x - oHalfWidth + (active - 1) * oWidth, + y: startY - oMarginTop + foreshorteningY, + height, + width: oWidth + }; + + const occurrenceTxt = this.templates.occurrence(oProps); + const occurrenceEl = Common.txt2dom(occurrenceTxt); + Common.dom2svg(occurrenceEl, gOccurrences.append('g')); + } + draw = false; + } + } - o.active.push(messageId); - draw = false; + if (draw) { + // Seems this is a singleton occurrence. We just draw a wee box around it. + + const height = oMarginTop + oMarginBottom; + const occurrenceProperties = { + x, + y: y - oMarginTop, + height, + width: oWidth + }; + const defaultTxt = this.templates.occurrence(occurrenceProperties); + const defaultEl = Common.txt2dom(defaultTxt); + Common.dom2svg(defaultEl, gOccurrences.append('g')); + } + } - } else if (active > 0) { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Draw box(es) around fragment(s). + * @param gCanvas container. + * @param fragment fragment definition, corresponding to its final (stop) message. + * @param positionsByMessageId message dimensions. + * @private + */ + _drawFragment(gCanvas, fragment, positionsByMessageId) { + const optFragments = this.options.fragments; + const gFragments = gCanvas.select('g.asdcs-diagram-fragments'); + const p1 = positionsByMessageId[fragment.stop]; + if (p1 && fragment.start && fragment.start.length > 0) { + for (const start of fragment.start) { + const message = this.application + .getModel() + .getMessageById(start); + const bounds = this._calcFragmentBounds( + message, + fragment, + positionsByMessageId + ); + if (bounds) { + const maxLines = this.options.fragments.label.maxLines; + const wrapWords = this.options.fragments.label.wrapWords; + const wrapLines = this.options.fragments.label.wrapLines; + const lines = Common.tokenize( + message.fragment.guard, + wrapWords, + wrapLines, + maxLines + ); + + const params = { + id: start, + x: bounds.x0 - optFragments.leftMargin, + y: bounds.y0 - optFragments.topMargin, + height: + bounds.y1 - bounds.y0 + optFragments.heightMargin, + width: bounds.x1 - bounds.x0 + optFragments.widthMargin, + operator: message.fragment.operator || 'alt', + lines + }; + + const fragmentTxt = this.templates.fragment(params); + const fragmentEl = Common.txt2dom(fragmentTxt); + const gFragment = gFragments.append('g'); + Common.dom2svg(fragmentEl, gFragment); + + const labelBB = gFragment + .select('.asdcs-diagram-fragment-guard') + .node() + .getBBox(); + gFragment + .select('.asdcs-diagram-fragment-guard-bg') + .attr('x', labelBB.x) + .attr('y', labelBB.y) + .attr('height', labelBB.height) + .attr('width', labelBB.width); + } else { + Logger.warn(`Bad fragment: ${JSON.stringify(fragment)}`); + } + } + } + } - const startMessageId = o.stop[messageId]; - if (startMessageId) { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + _calcFragmentBounds(startMessage, fragment, positionsByMessageId) { + if (startMessage) { + const steps = this.application.getModel().unwrap().diagram.steps; + const bounds = { x0: 99999, x1: 0, y0: 99999, y1: 0 }; + let foundStart = false; + let foundStop = false; + for (const step of steps) { + const message = step.message; + if (message) { + if (message.id === startMessage.id) { + foundStart = true; + } + if (foundStart && !foundStop) { + const positions = positionsByMessageId[message.id]; + if (positions) { + bounds.x0 = Math.min( + bounds.x0, + Math.min(positions.x0, positions.x1) + ); + bounds.y0 = Math.min(bounds.y0, positions.y); + bounds.x1 = Math.max( + bounds.x1, + Math.max(positions.x0, positions.x1) + ); + bounds.y1 = Math.max(bounds.y1, positions.y); + } else { + // This probably means it hasn't been recorded yet, which is fine, because + // we draw fragments from where they END. + foundStop = true; + } + } + + if (message.id === fragment.stop) { + foundStop = true; + } + } + } + return bounds; + } + return undefined; + } - // OK, it ends here. Draw the occurrence box. + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Draw all lifelines. + * @param gLifelines lifelines container. + * @param lifelines lifelines definitions. + * @param y height. + * @private + */ + _drawLifelines(gLifelines, lifelines, y) { + const maxLines = this.options.lifelines.header.maxLines; + const wrapWords = this.options.lifelines.header.wrapWords; + const wrapLines = this.options.lifelines.header.wrapLines; + + for (const lifeline of lifelines) { + const lines = Common.tokenize( + lifeline.actor.name, + wrapWords, + wrapLines, + maxLines + ); + const lifelineTxt = this.templates.lifeline({ + x: lifeline.x, + y0: 0, + y1: y, + lines, + rows: maxLines, + headerHeight: this.options.lifelines.header.height, + headerWidth: this.options.lifelines.header.width, + id: lifeline.actor.id + }); + + const lifelineEl = Common.txt2dom(lifelineTxt); + Common.dom2svg(lifelineEl, gLifelines.append('g')); + } + } - o.active.pop(); - const foreshorteningY = active * oForeshortening; - const startY = positionsByMessageId[startMessageId].y; - const height = ((oMarginTop + oMarginBottom) + (y - startY)) - (foreshorteningY * 2); - const oProps = { - x: (actor.x - oHalfWidth) + ((active - 1) * oWidth), - y: ((startY - oMarginTop) + foreshorteningY), - height, - width: oWidth, - }; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Initialize all mouse events. + * @param gLifelines lifelines container. + * @param gCanvas top-level canvas container. + * @private + */ + _initMouseEvents(gLifelines, gCanvas) { + const self = this; + const source = 'asdcs'; + const origin = `${window.location.protocol}//${window.location.host}`; + + let timer; + gLifelines + .selectAll('.asdcs-diagram-lifeline-selectable') + .on('mouseenter', function f() { + timer = setTimeout(() => { + self.application.selectLifeline( + d3.select(this.parentNode).attr('data-id') + ); + }, 150); + }) + .on('mouseleave', () => { + clearTimeout(timer); + self.application.selectLifeline(); + }) + .on('click', function f() { + const id = d3.select(this.parentNode).attr('data-id'); + window.postMessage({ source, id, type: 'lifeline' }, origin); + }); + + gLifelines + .selectAll('.asdcs-diagram-lifeline-heading-box') + .on('mouseenter', function f() { + timer = setTimeout(() => { + self.application.selectLifeline( + d3.select(this.parentNode).attr('data-id') + ); + }, 150); + }) + .on('mouseleave', () => { + clearTimeout(timer); + self.application.selectLifeline(); + }) + .on('click', function f() { + const id = d3.select(this.parentNode).attr('data-id'); + window.postMessage( + { source, id, type: 'lifelineHeader' }, + origin + ); + }); + + gCanvas + .selectAll('.asdcs-diagram-message-selectable') + .on('mouseenter', function f() { + self.events.message = { x: d3.event.pageX, y: d3.event.pageY }; + timer = setTimeout(() => { + self.application.selectMessage( + d3.select(this.parentNode).attr('data-id') + ); + }, 200); + }) + .on('mouseleave', () => { + delete self.events.message; + clearTimeout(timer); + self.application.selectMessage(); + }) + .on('click', function f() { + const id = d3.select(this.parentNode).attr('data-id'); + window.postMessage({ source, id, type: 'message' }, origin); + }); + } - const occurrenceTxt = this.templates.occurrence(oProps); - const occurrenceEl = Common.txt2dom(occurrenceTxt); - Common.dom2svg(occurrenceEl, gOccurrences.append('g')); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get CSS classes to be applied to a message, according to whether request/response + * or synchronous/asynchronous. + * @param message message being rendered. + * @returns CSS class name(s). + * @private + */ + static _getMessageStyles(message) { + let marker = 'asdcsDiagramArrowSolid'; + let dasharray = ''; + let css = 'asdcs-diagram-message'; + if (message.type === 'request') { + css = `${css} asdcs-diagram-message-request`; + } else { + css = `${css} asdcs-diagram-message-response`; + marker = 'asdcsDiagramArrowOpen'; + dasharray = '30, 10'; + } + if (message.asynchronous) { + css = `${css} asdcs-diagram-message-asynchronous`; + marker = 'asdcsDiagramArrowOpen'; + } else { + css = `${css} asdcs-diagram-message-synchronous`; } - draw = false; - } + + return { css, marker, dasharray }; } - if (draw) { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Initialize or reinitialize zoom. This sets the initial zoom in the case of + * a re-rendering, and initializes the eventhandling in all cases. + * + * It does some fairly risky parsing of the 'transform' attribute, assuming that it + * can contain scale() and translate(). But only the zoom handler and us are writing + * the transform values, so that's probably OK. + * + * @param gContent container. + * @param width diagram width. + * @param height diagram height. + * @private + */ + _initZoom(gContent, width, height) { + const zoomed = function zoomed() { + if (!this.initialTransformX && !this.initialTransformY) { + this.initialTransformX = d3.event.transform.x; + this.initialTransformY = d3.event.transform.y; + } - // Seems this is a singleton occurrence. We just draw a wee box around it. + gContent.attr( + 'transform', + `translate(${d3.event.transform.x - + this.initialTransformX}, ${d3.event.transform.y - + this.initialTransformY})scale(${d3.event.transform.k}, ${ + d3.event.transform.k + })` + ); + }; + + const viewWidth = this.state.width || this.options.svg.width; + const viewHeight = this.state.height || this.options.svg.height; + const scaleMinimum = this.options.svg.scale.minimum; + const scaleWidth = viewWidth / width; + const scaleHeight = viewHeight / height; + + let scale = scaleMinimum; + if (this.options.svg.scale.width) { + scale = Math.max(scale, scaleWidth); + } + if (this.options.svg.scale.height) { + scale = Math.min(scale, scaleHeight); + } - const height = (oMarginTop + oMarginBottom); - const occurrenceProperties = { x, y: y - oMarginTop, height, width: oWidth }; - const defaultTxt = this.templates.occurrence(occurrenceProperties); - const defaultEl = Common.txt2dom(defaultTxt); - Common.dom2svg(defaultEl, gOccurrences.append('g')); - } + scale = Math.max(scale, scaleMinimum); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Draw box(es) around fragment(s). - * @param gCanvas container. - * @param fragment fragment definition, corresponding to its final (stop) message. - * @param positionsByMessageId message dimensions. - * @private - */ - _drawFragment(gCanvas, fragment, positionsByMessageId) { - - const optFragments = this.options.fragments; - const gFragments = gCanvas.select('g.asdcs-diagram-fragments'); - const p1 = positionsByMessageId[fragment.stop]; - if (p1 && fragment.start && fragment.start.length > 0) { - - for (const start of fragment.start) { - - const message = this.application.getModel().getMessageById(start); - const bounds = this._calcFragmentBounds(message, fragment, positionsByMessageId); - if (bounds) { - - const maxLines = this.options.fragments.label.maxLines; - const wrapWords = this.options.fragments.label.wrapWords; - const wrapLines = this.options.fragments.label.wrapLines; - const lines = Common.tokenize(message.fragment.guard, wrapWords, wrapLines, maxLines); - - const params = { - id: start, - x: bounds.x0 - optFragments.leftMargin, - y: bounds.y0 - optFragments.topMargin, - height: (bounds.y1 - bounds.y0) + optFragments.heightMargin, - width: (bounds.x1 - bounds.x0) + optFragments.widthMargin, - operator: (message.fragment.operator || 'alt'), - lines, - }; - - const fragmentTxt = this.templates.fragment(params); - const fragmentEl = Common.txt2dom(fragmentTxt); - const gFragment = gFragments.append('g'); - Common.dom2svg(fragmentEl, gFragment); - - const labelBB = gFragment.select('.asdcs-diagram-fragment-guard').node().getBBox(); - gFragment.select('.asdcs-diagram-fragment-guard-bg') - .attr('x', labelBB.x) - .attr('y', labelBB.y) - .attr('height', labelBB.height) - .attr('width', labelBB.width); + let translate = [0, 0]; + if (this.savedTransform) { + const s = this.savedTransform; + const scaleStart = s.indexOf('scale('); + if (scaleStart !== -1) { + scale = parseFloat(s.substring(scaleStart + 6, s.length - 1)); + } + const translateStart = s.indexOf('translate('); + if (translateStart !== -1) { + const spec = s.substring( + translateStart + 10, + s.indexOf(')', translateStart) + ); + const tokens = spec.split(','); + translate = [parseFloat(tokens[0]), parseFloat(tokens[1])]; + } + gContent.attr('transform', this.savedTransform); } else { - Logger.warn(`Bad fragment: ${JSON.stringify(fragment)}`); + gContent.attr('transform', `scale(${scale})`); } - } - } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - _calcFragmentBounds(startMessage, fragment, positionsByMessageId) { - if (startMessage) { - const steps = this.application.getModel().unwrap().diagram.steps; - const bounds = { x0: 99999, x1: 0, y0: 99999, y1: 0 }; - let foundStart = false; - let foundStop = false; - for (const step of steps) { - const message = step.message; - if (message) { - if (message.id === startMessage.id) { - foundStart = true; - } - if (foundStart && !foundStop) { - const positions = positionsByMessageId[message.id]; - if (positions) { - bounds.x0 = Math.min(bounds.x0, Math.min(positions.x0, positions.x1)); - bounds.y0 = Math.min(bounds.y0, positions.y); - bounds.x1 = Math.max(bounds.x1, Math.max(positions.x0, positions.x1)); - bounds.y1 = Math.max(bounds.y1, positions.y); - } else { - // This probably means it hasn't been recorded yet, which is fine, because - // we draw fragments from where they END. - foundStop = true; - } - } - if (message.id === fragment.stop) { - foundStop = true; - } - } - } - return bounds; - } - return undefined; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Draw all lifelines. - * @param gLifelines lifelines container. - * @param lifelines lifelines definitions. - * @param y height. - * @private - */ - _drawLifelines(gLifelines, lifelines, y) { - - const maxLines = this.options.lifelines.header.maxLines; - const wrapWords = this.options.lifelines.header.wrapWords; - const wrapLines = this.options.lifelines.header.wrapLines; - - for (const lifeline of lifelines) { - const lines = Common.tokenize(lifeline.actor.name, wrapWords, wrapLines, maxLines); - const lifelineTxt = this.templates.lifeline({ - x: lifeline.x, - y0: 0, - y1: y, - lines, - rows: maxLines, - headerHeight: this.options.lifelines.header.height, - headerWidth: this.options.lifelines.header.width, - id: lifeline.actor.id, - }); - - const lifelineEl = Common.txt2dom(lifelineTxt); - Common.dom2svg(lifelineEl, gLifelines.append('g')); - } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Initialize all mouse events. - * @param gLifelines lifelines container. - * @param gCanvas top-level canvas container. - * @private - */ - _initMouseEvents(gLifelines, gCanvas) { - - const self = this; - const source = 'asdcs'; - const origin = `${window.location.protocol}//${window.location.host}`; - - let timer; - gLifelines.selectAll('.asdcs-diagram-lifeline-selectable') - .on('mouseenter', function f() { - timer = setTimeout(() => { - self.application.selectLifeline(d3.select(this.parentNode).attr('data-id')); - }, 150); - }) - .on('mouseleave', () => { - clearTimeout(timer); - self.application.selectLifeline(); - }) - .on('click', function f() { - const id = d3.select(this.parentNode).attr('data-id'); - window.postMessage({ source, id, type: 'lifeline' }, origin); - }); - - gLifelines.selectAll('.asdcs-diagram-lifeline-heading-box') - .on('mouseenter', function f() { - timer = setTimeout(() => { - self.application.selectLifeline(d3.select(this.parentNode).attr('data-id')); - }, 150); - }) - .on('mouseleave', () => { - clearTimeout(timer); - self.application.selectLifeline(); - }) - .on('click', function f() { - const id = d3.select(this.parentNode).attr('data-id'); - window.postMessage({ source, id, type: 'lifelineHeader' }, origin); - }); - - gCanvas.selectAll('.asdcs-diagram-message-selectable') - .on('mouseenter', function f() { - self.events.message = { x: d3.event.pageX, y: d3.event.pageY }; - timer = setTimeout(() => { - self.application.selectMessage(d3.select(this.parentNode).attr('data-id')); - }, 200); - }) - .on('mouseleave', () => { - delete self.events.message; - clearTimeout(timer); - self.application.selectMessage(); - }) - .on('click', function f() { - const id = d3.select(this.parentNode).attr('data-id'); - window.postMessage({ source, id, type: 'message' }, origin); - }); - - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get CSS classes to be applied to a message, according to whether request/response - * or synchronous/asynchronous. - * @param message message being rendered. - * @returns CSS class name(s). - * @private - */ - static _getMessageStyles(message) { - - let marker = 'asdcsDiagramArrowSolid'; - let dasharray = ''; - let css = 'asdcs-diagram-message'; - if (message.type === 'request') { - css = `${css} asdcs-diagram-message-request`; - } else { - css = `${css} asdcs-diagram-message-response`; - marker = 'asdcsDiagramArrowOpen'; - dasharray = '30, 10'; - } + const zoom = d3.zoom().on('zoom', zoomed); - if (message.asynchronous) { - css = `${css} asdcs-diagram-message-asynchronous`; - marker = 'asdcsDiagramArrowOpen'; - } else { - css = `${css} asdcs-diagram-message-synchronous`; - } + this.svg.call(zoom); + this.svg.call(zoom.scaleBy, scale); - return { css, marker, dasharray }; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Initialize or reinitialize zoom. This sets the initial zoom in the case of - * a re-rendering, and initializes the eventhandling in all cases. - * - * It does some fairly risky parsing of the 'transform' attribute, assuming that it - * can contain scale() and translate(). But only the zoom handler and us are writing - * the transform values, so that's probably OK. - * - * @param gContent container. - * @param width diagram width. - * @param height diagram height. - * @private - */ - _initZoom(gContent, width, height) { - - const zoomed = function zoomed() { - if (!this.initialTransformX && !this.initialTransformY) { - this.initialTransformX = d3.event.transform.x; - this.initialTransformY = d3.event.transform.y; - } - - gContent.attr('transform', - `translate(${d3.event.transform.x - this.initialTransformX}, ${d3.event.transform.y - - this.initialTransformY})scale(${d3.event.transform.k}, ${d3.event.transform.k})`); - }; - - const viewWidth = this.state.width || this.options.svg.width; - const viewHeight = this.state.height || this.options.svg.height; - const scaleMinimum = this.options.svg.scale.minimum; - const scaleWidth = viewWidth / width; - const scaleHeight = viewHeight / height; - - let scale = scaleMinimum; - if (this.options.svg.scale.width) { - scale = Math.max(scale, scaleWidth); - } - if (this.options.svg.scale.height) { - scale = Math.min(scale, scaleHeight); + gContent.attr( + 'transform', + `translate(${translate[0]}, ${translate[1]})` + ); + gContent.attr('transform', `scale(${scale})`); } - scale = Math.max(scale, scaleMinimum); - - let translate = [0, 0]; - if (this.savedTransform) { - const s = this.savedTransform; - const scaleStart = s.indexOf('scale('); - if (scaleStart !== -1) { - scale = parseFloat(s.substring(scaleStart + 6, s.length - 1)); - } - const translateStart = s.indexOf('translate('); - if (translateStart !== -1) { - const spec = s.substring(translateStart + 10, s.indexOf(')', translateStart)); - const tokens = spec.split(','); - translate = [parseFloat(tokens[0]), parseFloat(tokens[1])]; - } - - gContent.attr('transform', this.savedTransform); - } else { - gContent.attr('transform', `scale(${scale})`); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Hide from the linter the fact that we're modifying the lifeline. + * @param lifeline to be updated with X position. + * @param x X position. + * @private + */ + static _processLifeline(lifeline, x) { + const actor = lifeline; + actor.id = actor.id || actor.name; + actor.x = x; } - const zoom = d3.zoom() - .on('zoom', zoomed); - - this.svg.call(zoom); - this.svg.call(zoom.scaleBy, scale); - - gContent.attr('transform', `translate(${translate[0]}, ${translate[1]})`); - gContent.attr('transform', `scale(${scale})`); - - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Hide from the linter the fact that we're modifying the lifeline. - * @param lifeline to be updated with X position. - * @param x X position. - * @private - */ - static _processLifeline(lifeline, x) { - const actor = lifeline; - actor.id = actor.id || actor.name; - actor.x = x; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Derive active occurrences for lifeline. - * @param oData occurrences data. - * @param lifelineId lifeline to be analyzed. - * @returns {number} - * @private - */ - static _calcActive(oData, lifelineId) { - const o = oData[lifelineId]; - let active = 0; - if (o && o.active) { - active = o.active.length; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Derive active occurrences for lifeline. + * @param oData occurrences data. + * @param lifelineId lifeline to be analyzed. + * @returns {number} + * @private + */ + static _calcActive(oData, lifelineId) { + const o = oData[lifelineId]; + let active = 0; + if (o && o.active) { + active = o.active.length; + } + return active; } - return active; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Derive the X position of an occurrence on a lifeline, taking into account how - * many occurrences are active. - * @param active active count. - * @param x lifeline X position; basis for offset. - * @param arrow whether this is the arrow (to) end. - * @param leftToRight whether this message goes left-to-right. - * @returns {*} calculated X position for occurrence left-hand side. - * @private - */ - _calcMessageX(active, x, arrow, leftToRight) { - const width = this.options.lifelines.occurrences.width; - const halfWidth = width / 2; - const active0 = Math.max(0, active - 1); - let calculated = x + (active0 * width); - if (arrow) { - // End (ARROW). - if (leftToRight) { - calculated -= halfWidth; - } else { - calculated += halfWidth; - } - } else { - // Start (NOT ARROW). - if (leftToRight) { - calculated += halfWidth; - } else { - calculated -= halfWidth; - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Derive the X position of an occurrence on a lifeline, taking into account how + * many occurrences are active. + * @param active active count. + * @param x lifeline X position; basis for offset. + * @param arrow whether this is the arrow (to) end. + * @param leftToRight whether this message goes left-to-right. + * @returns {*} calculated X position for occurrence left-hand side. + * @private + */ + _calcMessageX(active, x, arrow, leftToRight) { + const width = this.options.lifelines.occurrences.width; + const halfWidth = width / 2; + const active0 = Math.max(0, active - 1); + let calculated = x + active0 * width; + if (arrow) { + // End (ARROW). + if (leftToRight) { + calculated -= halfWidth; + } else { + calculated += halfWidth; + } + } else { + // Start (NOT ARROW). + if (leftToRight) { + calculated += halfWidth; + } else { + calculated -= halfWidth; + } + } + + return calculated; } - return calculated; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show popup upon hovering over a messages that has associated notes. - * @param id - * @private - */ - _showNotesPopup(id) { - if (this.popup) { - if (id) { - const message = this.application.getModel().getMessageById(id); - if (message && message.notes && message.notes.length > 0 && this.events.message) { - this.popup.setState({ - visible: true, - left: this.events.message.x - 50, - top: this.events.message.y + 20, - notes: message.notes[0], - }); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show popup upon hovering over a messages that has associated notes. + * @param id + * @private + */ + _showNotesPopup(id) { + if (this.popup) { + if (id) { + const message = this.application.getModel().getMessageById(id); + if ( + message && + message.notes && + message.notes.length > 0 && + this.events.message + ) { + this.popup.setState({ + visible: true, + left: this.events.message.x - 50, + top: this.events.message.y + 20, + notes: message.notes[0] + }); + } + } else { + this.popup.setState({ visible: false, notes: '' }); + } } - } else { - this.popup.setState({ visible: false, notes: '' }); - } } - } } - Diagram.propTypes = { - application: PropTypes.object.isRequired, + application: PropTypes.object.isRequired }; export default Diagram; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx index 8f8f859aad..a2a6582ab0 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/diagram/components/popup/Popup.jsx @@ -25,85 +25,81 @@ import iconEdit from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/i * @constructor */ class Popup extends React.Component { - - // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct react view. - * @param props element properties (of which there are none). - * @param context react context. - */ - constructor(props, context) { - super(props, context); - this.state = { - top: 0, - left: 0, - visible: false, - notes: '', - }; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render view. - * @returns {XML} - */ - render() { - - // Build CSS + styles to position and configure popup. - - let top = this.state.top; - let left = this.state.left; - - const popupHeight = 200; - const popupWidth = 320; - - let auxCssVertical = 'top'; - let auxCssHorizontal = 'left'; - - if (this.state.top > (window.innerHeight - popupHeight)) { - top -= (popupHeight + 50); - auxCssVertical = 'bottom'; - } - - if (this.state.left > (window.innerWidth - popupWidth)) { - left -= (popupWidth - 80); - auxCssHorizontal = 'right'; - } - - const auxCss = `asdcs-diagram-popup-${auxCssVertical}${auxCssHorizontal}`; - const styles = { - top, - left, - display: (this.state.visible ? 'block' : 'none'), - }; - - // Render element. - - let notes = this.state.notes || ''; - if (notes.length > 255) { - notes = notes.substring(0, 255); - notes = `${notes} ...`; + // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct react view. + * @param props element properties (of which there are none). + * @param context react context. + */ + constructor(props, context) { + super(props, context); + this.state = { + top: 0, + left: 0, + visible: false, + notes: '' + }; } - return ( - <div className={`asdcs-diagram-popup ${auxCss}`} style={styles}> - <div className="asdcs-diagram-popup-header">Notes</div> - <div className="asdcs-diagram-popup-body"> - <div className="asdcs-icon-popup"> - <Icon glyph={iconEdit} /> - </div> - <div className="asdcs-diagram-notes"> - <div className="asdcs-diagram-note"> - {notes} + // /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render view. + * @returns {XML} + */ + render() { + // Build CSS + styles to position and configure popup. + + let top = this.state.top; + let left = this.state.left; + + const popupHeight = 200; + const popupWidth = 320; + + let auxCssVertical = 'top'; + let auxCssHorizontal = 'left'; + + if (this.state.top > window.innerHeight - popupHeight) { + top -= popupHeight + 50; + auxCssVertical = 'bottom'; + } + + if (this.state.left > window.innerWidth - popupWidth) { + left -= popupWidth - 80; + auxCssHorizontal = 'right'; + } + + const auxCss = `asdcs-diagram-popup-${auxCssVertical}${auxCssHorizontal}`; + const styles = { + top, + left, + display: this.state.visible ? 'block' : 'none' + }; + + // Render element. + + let notes = this.state.notes || ''; + if (notes.length > 255) { + notes = notes.substring(0, 255); + notes = `${notes} ...`; + } + + return ( + <div className={`asdcs-diagram-popup ${auxCss}`} style={styles}> + <div className="asdcs-diagram-popup-header">Notes</div> + <div className="asdcs-diagram-popup-body"> + <div className="asdcs-icon-popup"> + <Icon glyph={iconEdit} /> + </div> + <div className="asdcs-diagram-notes"> + <div className="asdcs-diagram-note">{notes}</div> + </div> + </div> + <div className="asdcs-diagram-popup-footer" /> </div> - </div> - </div> - <div className="asdcs-diagram-popup-footer"></div> - </div> - ); - } + ); + } } export default Popup; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx index d48ef3bd88..96a709948c 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/dialog/Dialog.jsx @@ -28,211 +28,216 @@ import iconClose from '../../../../../../res/ecomp/asdc/sequencer/sprites/icons/ * configured, shown and hidden as required. */ class Dialog extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + */ + constructor(props, context) { + super(props, context); + + this.MODE = { + INFO: { + icon: 'asdcs-icon-info', + heading: 'Information' + }, + ERROR: { + icon: 'asdcs-icon-exclaim', + heading: 'Error' + }, + EDIT: { + icon: 'asdcs-icon-edit', + heading: 'Edit', + edit: true, + confirm: true + }, + CONFIRM: { + icon: 'asdcs-icon-question', + heading: 'Confirm', + confirm: true + } + }; + + this.state = { + mode: this.MODE.INFO, + message: '', + text: '', + visible: false + }; + + // Bindings. + + this.onClickOK = this.onClickOK.bind(this); + this.onClickCancel = this.onClickCancel.bind(this); + this.onChangeText = this.onChangeText.bind(this); + this.showConfirmDialog = this.showConfirmDialog.bind(this); + this.showInfoDialog = this.showInfoDialog.bind(this); + this.showEditDialog = this.showEditDialog.bind(this); + this.showErrorDialog = this.showErrorDialog.bind(this); + this.showDialog = this.showDialog.bind(this); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show info dialog. + * @param message info message. + */ + showInfoDialog(message) { + this.showDialog(this.MODE.INFO, { message }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show error dialog. + * @param message error message. + */ + showErrorDialog(message) { + this.showDialog(this.MODE.ERROR, { message }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show edit dialog. + * @param message dialog message. + * @param text current edit text. + * @param callback callback function to be invoked on OK. + */ + showEditDialog(message, text, callback) { + this.showDialog(this.MODE.EDIT, { message, text, callback }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show confirmation dialog. + * @param message dialog message. + * @param callback callback function to be invoked on OK. + */ + showConfirmDialog(message, callback) { + this.showDialog(this.MODE.CONFIRM, { message, callback }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle buttonclick. + */ + onClickOK() { + this.props.application.hideOverlay(); + this.setState({ visible: false }); + if (this.callback) { + // So far the only thing we can return is edit text, but send it back + // as properties to allow for future return values. + + this.callback({ text: this.state.text }); + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle buttonclick. + */ + onClickCancel() { + this.props.application.hideOverlay(); + this.setState({ visible: false }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle text changes. + * @param event update event. + */ + onChangeText(event) { + this.setState({ text: event.target.value }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show dialog in specified configuration. + * @param mode dialog mode. + * @param args dialog parameters, varying slightly by dialog type. + * @private + */ + showDialog(mode, args) { + this.props.application.showOverlay(); + this.callback = args.callback; + this.setState({ + mode, + visible: true, + message: args.message || '', + text: args.text || '' + }); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct view. - */ - constructor(props, context) { - - super(props, context); - - this.MODE = { - INFO: { - icon: 'asdcs-icon-info', - heading: 'Information', - }, - ERROR: { - icon: 'asdcs-icon-exclaim', - heading: 'Error', - }, - EDIT: { - icon: 'asdcs-icon-edit', - heading: 'Edit', - edit: true, - confirm: true, - }, - CONFIRM: { - icon: 'asdcs-icon-question', - heading: 'Confirm', - confirm: true, - }, - }; - - this.state = { - mode: this.MODE.INFO, - message: '', - text: '', - visible: false, - }; - - // Bindings. - - this.onClickOK = this.onClickOK.bind(this); - this.onClickCancel = this.onClickCancel.bind(this); - this.onChangeText = this.onChangeText.bind(this); - this.showConfirmDialog = this.showConfirmDialog.bind(this); - this.showInfoDialog = this.showInfoDialog.bind(this); - this.showEditDialog = this.showEditDialog.bind(this); - this.showErrorDialog = this.showErrorDialog.bind(this); - this.showDialog = this.showDialog.bind(this); - - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show info dialog. - * @param message info message. - */ - showInfoDialog(message) { - this.showDialog(this.MODE.INFO, { message }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show error dialog. - * @param message error message. - */ - showErrorDialog(message) { - this.showDialog(this.MODE.ERROR, { message }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show edit dialog. - * @param message dialog message. - * @param text current edit text. - * @param callback callback function to be invoked on OK. - */ - showEditDialog(message, text, callback) { - this.showDialog(this.MODE.EDIT, { message, text, callback }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show confirmation dialog. - * @param message dialog message. - * @param callback callback function to be invoked on OK. - */ - showConfirmDialog(message, callback) { - this.showDialog(this.MODE.CONFIRM, { message, callback }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle buttonclick. - */ - onClickOK() { - this.props.application.hideOverlay(); - this.setState({ visible: false }); - if (this.callback) { - - // So far the only thing we can return is edit text, but send it back - // as properties to allow for future return values. - - this.callback({ text: this.state.text }); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render dialog into the page, initially hidden. + */ + render() { + const dialogClass = this.state.visible ? '' : 'asdcs-hidden'; + const cancelClass = this.callback ? '' : 'asdcs-hidden'; + const textClass = + this.state.mode === this.MODE.EDIT ? '' : 'asdcs-hidden'; + + return ( + <div className={`asdcs-dialog ${dialogClass}`}> + <div className="asdcs-dialog-header"> + {this.state.mode.heading} + </div> + <div + className="asdcs-dialog-close" + onClick={this.onClickCancel}> + <Icon + glyph={iconClose} + className={this.MODE.CONFIRM.icon} + /> + </div> + <div className={`asdcs-dialog-icon ${this.state.mode.icon}`}> + <Icon + glyph={iconQuestion} + className={this.MODE.CONFIRM.icon} + /> + <Icon + glyph={iconExclaim} + className={this.MODE.ERROR.icon} + /> + <Icon glyph={iconInfo} className={this.MODE.INFO.icon} /> + <Icon glyph={iconEdit} className={this.MODE.EDIT.icon} /> + </div> + <div className="asdcs-dialog-message">{this.state.message}</div> + <div className={`asdcs-dialog-text ${textClass}`}> + <textarea + maxLength="255" + value={this.state.text} + onChange={this.onChangeText} + /> + </div> + <div className="asdcs-dialog-buttonbar"> + <button + className={`asdcs-dialog-button-cancel ${cancelClass}`} + onClick={this.onClickCancel}> + Cancel + </button> + <button + className="asdcs-dialog-button-ok" + onClick={this.onClickOK}> + OK + </button> + </div> + </div> + ); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle buttonclick. - */ - onClickCancel() { - this.props.application.hideOverlay(); - this.setState({ visible: false }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle text changes. - * @param event update event. - */ - onChangeText(event) { - this.setState({ text: event.target.value }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show dialog in specified configuration. - * @param mode dialog mode. - * @param args dialog parameters, varying slightly by dialog type. - * @private - */ - showDialog(mode, args) { - this.props.application.showOverlay(); - this.callback = args.callback; - this.setState({ - mode, - visible: true, - message: args.message || '', - text: args.text || '', - }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render dialog into the page, initially hidden. - */ - render() { - - const dialogClass = (this.state.visible) ? '' : 'asdcs-hidden'; - const cancelClass = (this.callback) ? '' : 'asdcs-hidden'; - const textClass = (this.state.mode === this.MODE.EDIT) ? '' : 'asdcs-hidden'; - - return ( - <div className={`asdcs-dialog ${dialogClass}`}> - <div className="asdcs-dialog-header">{this.state.mode.heading}</div> - <div className="asdcs-dialog-close" onClick={this.onClickCancel} > - <Icon glyph={iconClose} className={this.MODE.CONFIRM.icon} /> - </div> - <div className={`asdcs-dialog-icon ${this.state.mode.icon}`}> - <Icon glyph={iconQuestion} className={this.MODE.CONFIRM.icon} /> - <Icon glyph={iconExclaim} className={this.MODE.ERROR.icon} /> - <Icon glyph={iconInfo} className={this.MODE.INFO.icon} /> - <Icon glyph={iconEdit} className={this.MODE.EDIT.icon} /> - </div> - <div className="asdcs-dialog-message"> - {this.state.message} - </div> - <div className={`asdcs-dialog-text ${textClass}`}> - <textarea - maxLength="255" - value={this.state.text} - onChange={this.onChangeText} - /> - </div> - <div className="asdcs-dialog-buttonbar"> - <button - className={`asdcs-dialog-button-cancel ${cancelClass}`} - onClick={this.onClickCancel} - > - Cancel - </button> - <button - className="asdcs-dialog-button-ok" - onClick={this.onClickOK} - > - OK - </button> - </div> - </div> - ); - } } Dialog.propTypes = { - application: PropTypes.object.isRequired, + application: PropTypes.object.isRequired }; export default Dialog; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx index 00c8f7c47c..087bc8029f 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/Editor.jsx @@ -26,149 +26,147 @@ import Source from './components/source/Source'; * Editor view, aggregating the designer, the code editor, the toolbar. */ class Editor extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Construct React view. + * @param props properties. + * @param context context. + */ + constructor(props, context) { + super(props, context); - /** - * Construct React view. - * @param props properties. - * @param context context. - */ - constructor(props, context) { - super(props, context); + this.application = Common.assertNotNull(props.application); + this.demo = this.application.getOptions().demo; - this.application = Common.assertNotNull(props.application); - this.demo = this.application.getOptions().demo; + // Bindings. - // Bindings. + this.selectMessage = this.selectMessage.bind(this); + this.selectLifeline = this.selectLifeline.bind(this); - this.selectMessage = this.selectMessage.bind(this); - this.selectLifeline = this.selectLifeline.bind(this); - - this.onMouseDown = this.onMouseDown.bind(this); - this.onMouseUp = this.onMouseUp.bind(this); - this.onMouseMove = this.onMouseMove.bind(this); - } + this.onMouseDown = this.onMouseDown.bind(this); + this.onMouseUp = this.onMouseUp.bind(this); + this.onMouseMove = this.onMouseMove.bind(this); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Select message by ID. - * @param id message ID. - */ - selectMessage(id) { - if (this.designer) { - this.designer.selectMessage(id); + /** + * Select message by ID. + * @param id message ID. + */ + selectMessage(id) { + if (this.designer) { + this.designer.selectMessage(id); + } } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Select lifeline by ID. - * @param id lifeline ID. - */ - selectLifeline(id) { - if (this.designer) { - this.designer.selectLifeline(id); + /** + * Select lifeline by ID. + * @param id lifeline ID. + */ + selectLifeline(id) { + if (this.designer) { + this.designer.selectLifeline(id); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Record that we're dragging. - */ - onMouseDown() { - if (this.editor) { - this.resize = { - initialWidth: this.editor.offsetWidth, - initialPageX: undefined, - }; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Record that we're dragging. + */ + onMouseDown() { + if (this.editor) { + this.resize = { + initialWidth: this.editor.offsetWidth, + initialPageX: undefined + }; + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Record that we're not dragging. - */ - onMouseUp() { - this.resize = undefined; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Record mouse movement. - */ - onMouseMove(event) { - if (this.resize) { - if (this.editor) { - if (this.resize.initialPageX) { - const deltaX = event.pageX - this.resize.initialPageX; - const newWidth = this.resize.initialWidth + deltaX; - const newWidthBounded = Math.min(800, Math.max(400, newWidth)); - this.editor.style.width = `${newWidthBounded}px`; - } else { - this.resize.initialPageX = event.pageX; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Record that we're not dragging. + */ + onMouseUp() { + this.resize = undefined; + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Record mouse movement. + */ + onMouseMove(event) { + if (this.resize) { + if (this.editor) { + if (this.resize.initialPageX) { + const deltaX = event.pageX - this.resize.initialPageX; + const newWidth = this.resize.initialWidth + deltaX; + const newWidthBounded = Math.min( + 800, + Math.max(400, newWidth) + ); + this.editor.style.width = `${newWidthBounded}px`; + } else { + this.resize.initialPageX = event.pageX; + } + } } - } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render editor. - */ - render() { - - Logger.info('Editor.jsx - render()'); - - return ( - - <div - className="asdcs-editor" - ref={(r) => { this.editor = r; }} - > - - <Toolbar application={this.props.application} editor={this} /> - - <div className="asdcs-editor-content"> - <Source application={this.props.application} /> - <Designer - application={this.props.application} - ref={(r) => { - if (r) { - this.designer = r.getDecoratedComponentInstance(); - } else { - this.designer = null; - } - }} - /> - </div> - - <div className="asdcs-editor-statusbar"> - <div className="asdcs-editor-status"></div> - <div className="asdcs-editor-validation"></div> - </div> - - <div - className="asdcs-editor-resize-handle" - onMouseDown={this.onMouseDown} - onMouseUp={this.onMouseUp} - > - </div> - </div> - ); - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render editor. + */ + render() { + Logger.info('Editor.jsx - render()'); + + return ( + <div + className="asdcs-editor" + ref={r => { + this.editor = r; + }}> + <Toolbar application={this.props.application} editor={this} /> + + <div className="asdcs-editor-content"> + <Source application={this.props.application} /> + <Designer + application={this.props.application} + ref={r => { + if (r) { + this.designer = r.getDecoratedComponentInstance(); + } else { + this.designer = null; + } + }} + /> + </div> + + <div className="asdcs-editor-statusbar"> + <div className="asdcs-editor-status" /> + <div className="asdcs-editor-validation" /> + </div> + + <div + className="asdcs-editor-resize-handle" + onMouseDown={this.onMouseDown} + onMouseUp={this.onMouseUp} + /> + </div> + ); + } } /** Element properties. */ Editor.propTypes = { - application: PropTypes.object.isRequired, + application: PropTypes.object.isRequired }; export default Editor; - diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx index c67c68e4e2..09e321dd54 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/Designer.jsx @@ -35,369 +35,383 @@ import iconCollapsed from '../../../../../../../../res/ecomp/asdc/sequencer/spri * LHS design wid` view. */ class Designer extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + + Logger.noop(); + + this.application = Common.assertNotNull(props.application); + + this.state = { + lifelinesExpanded: false, + messagesExpanded: true, + activeLifelineId: undefined, + activeMessageId: undefined + }; + + // Bind this. + + this.onToggle = this.onToggle.bind(this); + this.onMouseEnterLifeline = this.onMouseEnterLifeline.bind(this); + this.onMouseLeaveLifeline = this.onMouseLeaveLifeline.bind(this); + this.onMouseEnterMessage = this.onMouseEnterMessage.bind(this); + this.onMouseLeaveMessage = this.onMouseLeaveMessage.bind(this); + + this.addMessage = this.addMessage.bind(this); + this.updateMessage = this.updateMessage.bind(this); + this.deleteMessage = this.deleteMessage.bind(this); + this.addLifeline = this.addLifeline.bind(this); + this.updateLifeline = this.updateLifeline.bind(this); + this.deleteLifeline = this.deleteLifeline.bind(this); + + this.selectMessage = this.selectMessage.bind(this); + this.selectLifeline = this.selectLifeline.bind(this); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select message by ID. + * @param id message ID. + */ + selectMessage(id) { + // TODO: scroll into view. + + this.setState({ activeMessageId: id }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Select lifeline by ID. + * @param id lifeline ID. + */ + selectLifeline(id) { + // TODO: scroll into view. + + this.setState({ activeLifelineId: id }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show/hide lifelines section. + */ + onToggle() { + const lifelinesExpanded = !this.state.lifelinesExpanded; + const messagesExpanded = !lifelinesExpanded; + this.setState({ lifelinesExpanded, messagesExpanded }); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle mouse event. + * @param id lifeline identifier. + */ + onMouseEnterLifeline(id) { + this.application.selectLifeline(id); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle mouse event. + */ + onMouseLeaveLifeline() { + this.application.selectLifeline(); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle mouse event. + * @param id message identifier. + */ + onMouseEnterMessage(id) { + this.application.selectMessage(id); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); + /** + * Handle mouse event. + */ + onMouseLeaveMessage() { + // Only on next selection. + // this.application.selectMessage(); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Add new message. + */ + addMessage() { + if (this.application.getModel().unwrap().diagram.lifelines.length < 2) { + this.application.showErrorDialog( + 'You need at least two lifelines.' + ); + return; + } - Logger.noop(); - - this.application = Common.assertNotNull(props.application); - - this.state = { - lifelinesExpanded: false, - messagesExpanded: true, - activeLifelineId: undefined, - activeMessageId: undefined, - }; - - // Bind this. - - this.onToggle = this.onToggle.bind(this); - this.onMouseEnterLifeline = this.onMouseEnterLifeline.bind(this); - this.onMouseLeaveLifeline = this.onMouseLeaveLifeline.bind(this); - this.onMouseEnterMessage = this.onMouseEnterMessage.bind(this); - this.onMouseLeaveMessage = this.onMouseLeaveMessage.bind(this); - - this.addMessage = this.addMessage.bind(this); - this.updateMessage = this.updateMessage.bind(this); - this.deleteMessage = this.deleteMessage.bind(this); - this.addLifeline = this.addLifeline.bind(this); - this.updateLifeline = this.updateLifeline.bind(this); - this.deleteLifeline = this.deleteLifeline.bind(this); - - this.selectMessage = this.selectMessage.bind(this); - this.selectLifeline = this.selectLifeline.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Select message by ID. - * @param id message ID. - */ - selectMessage(id) { - - // TODO: scroll into view. - - this.setState({ activeMessageId: id }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Select lifeline by ID. - * @param id lifeline ID. - */ - selectLifeline(id) { - - // TODO: scroll into view. - - this.setState({ activeLifelineId: id }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show/hide lifelines section. - */ - onToggle() { - const lifelinesExpanded = !this.state.lifelinesExpanded; - const messagesExpanded = !lifelinesExpanded; - this.setState({ lifelinesExpanded, messagesExpanded }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - * @param id lifeline identifier. - */ - onMouseEnterLifeline(id) { - this.application.selectLifeline(id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - */ - onMouseLeaveLifeline() { - this.application.selectLifeline(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - * @param id message identifier. - */ - onMouseEnterMessage(id) { - this.application.selectMessage(id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - */ - onMouseLeaveMessage() { - // Only on next selection. - // this.application.selectMessage(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add new message. - */ - addMessage() { - - if (this.application.getModel().unwrap().diagram.lifelines.length < 2) { - this.application.showErrorDialog('You need at least two lifelines.'); - return; + this.application.getModel().addMessage(); + this.forceUpdate(); + this.application.renderDiagram(); } - this.application.getModel().addMessage(); - this.forceUpdate(); - this.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Apply property changes to the message identified by props.id. - * @param props properties to be updated (excluding 'id'). - */ - updateMessage(props) { - Common.assertPlainObject(props); - const model = this.application.getModel(); - const message = model.getMessageById(props.id); - if (message) { - for (const k of Object.keys(props)) { - if (k !== 'id') { - message[k] = props[k]; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Apply property changes to the message identified by props.id. + * @param props properties to be updated (excluding 'id'). + */ + updateMessage(props) { + Common.assertPlainObject(props); + const model = this.application.getModel(); + const message = model.getMessageById(props.id); + if (message) { + for (const k of Object.keys(props)) { + if (k !== 'id') { + message[k] = props[k]; + } + } } - } + this.forceUpdate(); + this.application.renderDiagram(); } - this.forceUpdate(); - this.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Delete message after confirmation. - * @param id ID of message to be deleted. - */ - deleteMessage(id) { - - const self = this; - const model = this.application.getModel(); - - const confirmComplete = function f() { - model.deleteMessageById(id); - self.render(); - self.application.renderDiagram(); - }; - - this.application.showConfirmDialog('Delete this message?', - confirmComplete); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add new lifeline. - */ - addLifeline() { - this.application.getModel().addLifeline(); - this.forceUpdate(); - this.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Apply property changes to the lifeline identified by props.id. - * @param props properties to be updated (excluding 'id'). - */ - updateLifeline(props) { - Common.assertPlainObject(props); - const model = this.application.getModel(); - const lifeline = model.getLifelineById(props.id); - if (lifeline) { - for (const k of Object.keys(props)) { - if (k !== 'id') { - lifeline[k] = props[k]; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Delete message after confirmation. + * @param id ID of message to be deleted. + */ + deleteMessage(id) { + const self = this; + const model = this.application.getModel(); + + const confirmComplete = function f() { + model.deleteMessageById(id); + self.render(); + self.application.renderDiagram(); + }; + + this.application.showConfirmDialog( + 'Delete this message?', + confirmComplete + ); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Add new lifeline. + */ + addLifeline() { + this.application.getModel().addLifeline(); + this.forceUpdate(); + this.application.renderDiagram(); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Apply property changes to the lifeline identified by props.id. + * @param props properties to be updated (excluding 'id'). + */ + updateLifeline(props) { + Common.assertPlainObject(props); + const model = this.application.getModel(); + const lifeline = model.getLifelineById(props.id); + if (lifeline) { + for (const k of Object.keys(props)) { + if (k !== 'id') { + lifeline[k] = props[k]; + } + } } - } + this.forceUpdate(); + this.application.renderDiagram(); } - this.forceUpdate(); - this.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Delete lifeline after confirmation. - * @param id candidate for deletion. - */ - deleteLifeline(id) { - - const self = this; - const model = this.application.getModel(); - - const confirmComplete = function f() { - model.deleteLifelineById(id); - self.forceUpdate(); - self.application.renderDiagram(); - }; - this.application.showConfirmDialog('Delete this lifeline and all its steps?', - confirmComplete); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render designer. - */ - render() { - - const application = this.props.application; - const model = application.getModel(); - const diagram = model.unwrap().diagram; - const metadata = diagram.metadata; - - const lifelinesIcon = this.state.lifelinesExpanded ? iconExpanded : iconCollapsed; - const lifelinesClass = this.state.lifelinesExpanded ? '' : 'asdcs-hidden'; - const messagesIcon = this.state.messagesExpanded ? iconExpanded : iconCollapsed; - const messagesClass = this.state.messagesExpanded ? '' : 'asdcs-hidden'; - - return ( - - <div className="asdcs-editor-designer"> - <div className="asdcs-designer-accordion"> - - <div className="asdcs-designer-metadata-container"> - <Metadata metadata={metadata} /> - </div> - - <h3 onClick={this.onToggle}>Lifelines - <div className="asdcs-designer-icon" onClick={this.onToggle}> - <Icon glyph={lifelinesIcon} /> - </div> - </h3> - - <div className={`asdcs-designer-lifelines-container ${lifelinesClass}`}> - <Lifelines - application={this.application} - designer={this} - activeLifelineId={this.state.activeLifelineId} - /> - </div> - - <h3 onClick={this.onToggle}>Steps - <div className="asdcs-designer-icon" onClick={this.onToggle}> - <Icon glyph={messagesIcon} /> + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Delete lifeline after confirmation. + * @param id candidate for deletion. + */ + deleteLifeline(id) { + const self = this; + const model = this.application.getModel(); + + const confirmComplete = function f() { + model.deleteLifelineById(id); + self.forceUpdate(); + self.application.renderDiagram(); + }; + this.application.showConfirmDialog( + 'Delete this lifeline and all its steps?', + confirmComplete + ); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render designer. + */ + render() { + const application = this.props.application; + const model = application.getModel(); + const diagram = model.unwrap().diagram; + const metadata = diagram.metadata; + + const lifelinesIcon = this.state.lifelinesExpanded + ? iconExpanded + : iconCollapsed; + const lifelinesClass = this.state.lifelinesExpanded + ? '' + : 'asdcs-hidden'; + const messagesIcon = this.state.messagesExpanded + ? iconExpanded + : iconCollapsed; + const messagesClass = this.state.messagesExpanded ? '' : 'asdcs-hidden'; + + return ( + <div className="asdcs-editor-designer"> + <div className="asdcs-designer-accordion"> + <div className="asdcs-designer-metadata-container"> + <Metadata metadata={metadata} /> + </div> + + <h3 onClick={this.onToggle}> + Lifelines + <div + className="asdcs-designer-icon" + onClick={this.onToggle}> + <Icon glyph={lifelinesIcon} /> + </div> + </h3> + + <div + className={`asdcs-designer-lifelines-container ${lifelinesClass}`}> + <Lifelines + application={this.application} + designer={this} + activeLifelineId={this.state.activeLifelineId} + /> + </div> + + <h3 onClick={this.onToggle}> + Steps + <div + className="asdcs-designer-icon" + onClick={this.onToggle}> + <Icon glyph={messagesIcon} /> + </div> + </h3> + + <div + className={`asdcs-designer-steps-container ${messagesClass}`}> + <Messages + application={this.application} + designer={this} + activeMessageId={this.state.activeMessageId} + /> + </div> + </div> + + <Actions + application={this.props.application} + model={model} + ref={r => { + this.actions = r; + }} + /> </div> - </h3> - - <div className={`asdcs-designer-steps-container ${messagesClass}`} > - <Messages - application={this.application} - designer={this} - activeMessageId={this.state.activeMessageId} - /> - </div> - - </div> - - <Actions - application={this.props.application} - model={model} - ref={(r) => { this.actions = r; }} - /> - - </div> - ); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Scroll accordion pane to make - * @param $element focused element. - * @private - */ - static _scrollIntoView($element) { - const $pane = $element.closest('.ui-accordion-content'); - const paneScrollTop = $pane.scrollTop(); - const paneHeight = $pane.height(); - const paneBottom = paneScrollTop + paneHeight; - const elementTop = $element[0].offsetTop - $pane[0].offsetTop; - const elementHeight = $element.height(); - const elementBottom = elementTop + elementHeight; - if (elementBottom > paneBottom) { - $pane.scrollTop(elementTop); - } else if (elementTop < paneScrollTop) { - $pane.scrollTop(elementTop); + ); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Scroll accordion pane to make + * @param $element focused element. + * @private + */ + static _scrollIntoView($element) { + const $pane = $element.closest('.ui-accordion-content'); + const paneScrollTop = $pane.scrollTop(); + const paneHeight = $pane.height(); + const paneBottom = paneScrollTop + paneHeight; + const elementTop = $element[0].offsetTop - $pane[0].offsetTop; + const elementHeight = $element.height(); + const elementBottom = elementTop + elementHeight; + if (elementBottom > paneBottom) { + $pane.scrollTop(elementTop); + } else if (elementTop < paneScrollTop) { + $pane.scrollTop(elementTop); + } } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show actions menu. - * @param id selected message ID. - * @param position page coordinates. - */ - showActions(id, position) { - if (this.actions) { - this.actions.show(id, position); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show actions menu. + * @param id selected message ID. + * @param position page coordinates. + */ + showActions(id, position) { + if (this.actions) { + this.actions.show(id, position); + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show notes popup. + * @param id selected message identifier. + */ + showNotes(id) { + const model = this.application.getModel(); + const options = this.application.getOptions(); + const message = model.getMessageById(id); + const notes = + message.notes && message.notes.length > 0 ? message.notes[0] : ''; + const editComplete = function f(p) { + message.notes = []; + if (p && p.text) { + const sanitized = Common.sanitizeText(p.text, options, 'notes'); + message.notes.push(sanitized); + } + }; + this.application.showEditDialog('Notes:', notes, editComplete); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show notes popup. - * @param id selected message identifier. - */ - showNotes(id) { - const model = this.application.getModel(); - const options = this.application.getOptions(); - const message = model.getMessageById(id); - const notes = (message.notes && (message.notes.length > 0)) ? message.notes[0] : ''; - const editComplete = function f(p) { - message.notes = []; - if (p && p.text) { - const sanitized = Common.sanitizeText(p.text, options, 'notes'); - message.notes.push(sanitized); - } - }; - this.application.showEditDialog('Notes:', notes, editComplete); - } } /** Element properties. */ Designer.propTypes = { - application: PropTypes.object.isRequired, + application: PropTypes.object.isRequired }; +/* eslint-disable new-cap */ export default DragDropContext(HTML5Backend)(Designer); +/* eslint-enable new-cap */ diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx index 5a8343cccf..a558a14f1d 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/actions/Actions.jsx @@ -36,439 +36,499 @@ import iconFragmentStop from '../../../../../../../../../../res/ecomp/asdc/seque * Action menu view. */ class Actions extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); + Logger.noop(); - Logger.noop(); + this.state = { + id: undefined, + visible: false + }; - this.state = { - id: undefined, - visible: false, - }; + // Bindings. - // Bindings. + this.show = this.show.bind(this); - this.show = this.show.bind(this); + this.onClickOccurrenceToggle = this.onClickOccurrenceToggle.bind(this); + this.onClickOccurrenceFrom = this.onClickOccurrenceFrom.bind(this); + this.onClickOccurrenceTo = this.onClickOccurrenceTo.bind(this); - this.onClickOccurrenceToggle = this.onClickOccurrenceToggle.bind(this); - this.onClickOccurrenceFrom = this.onClickOccurrenceFrom.bind(this); - this.onClickOccurrenceTo = this.onClickOccurrenceTo.bind(this); + this.onClickFragmentToggle = this.onClickFragmentToggle.bind(this); + this.onChangeFragmentGuard = this.onChangeFragmentGuard.bind(this); + this.onChangeFragmentOperator = this.onChangeFragmentOperator.bind( + this + ); - this.onClickFragmentToggle = this.onClickFragmentToggle.bind(this); - this.onChangeFragmentGuard = this.onChangeFragmentGuard.bind(this); - this.onChangeFragmentOperator = this.onChangeFragmentOperator.bind(this); - - this.onMouseOut = this.onMouseOut.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Show for message. - * @param id message ID. - * @param position xy coordinates. - */ - show(id, position) { - const message = this.props.model.getMessageById(id); - - let occurrencesToggle = false; - let fragmentToggle = false; - if (message) { - - message.occurrences = message.occurrences || { start: [], stop: [] }; - message.occurrences.start = message.occurrences.start || []; - message.occurrences.stop = message.occurrences.stop || []; - message.fragment = message.fragment || {}; - message.fragment.start = message.fragment.start || false; - message.fragment.stop = message.fragment.stop || false; - message.fragment.guard = message.fragment.guard || ''; - message.fragment.operator = message.fragment.operator || ''; - - const mo = message.occurrences; - occurrencesToggle = (mo.start.length > 0 || mo.stop.length > 0); - - const mf = message.fragment; - fragmentToggle = (mf.start || mf.stop); + this.onMouseOut = this.onMouseOut.bind(this); } - this.setState({ - id, - message, - occurrencesToggle, - fragmentToggle, - visible: true, - x: position.x, - y: position.y, - }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Toggle occurrence state. - */ - onClickOccurrenceToggle() { - const message = this.state.message; - if (message) { - const oFromState = Actions.getOccurrenceState(message.occurrences, message.from); - const oToState = Actions.getOccurrenceState(message.occurrences, message.to); - const oExpanded = oFromState > 0 || oToState > 0; - if (oExpanded) { - this.setState({ occurrencesExpanded: true }); - } else { - const occurrencesExpanded = !this.state.occurrencesExpanded; - this.setState({ occurrencesExpanded }); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Show for message. + * @param id message ID. + * @param position xy coordinates. + */ + show(id, position) { + const message = this.props.model.getMessageById(id); + + let occurrencesToggle = false; + let fragmentToggle = false; + if (message) { + message.occurrences = message.occurrences || { + start: [], + stop: [] + }; + message.occurrences.start = message.occurrences.start || []; + message.occurrences.stop = message.occurrences.stop || []; + message.fragment = message.fragment || {}; + message.fragment.start = message.fragment.start || false; + message.fragment.stop = message.fragment.stop || false; + message.fragment.guard = message.fragment.guard || ''; + message.fragment.operator = message.fragment.operator || ''; + + const mo = message.occurrences; + occurrencesToggle = mo.start.length > 0 || mo.stop.length > 0; + + const mf = message.fragment; + fragmentToggle = mf.start || mf.stop; + } + + this.setState({ + id, + message, + occurrencesToggle, + fragmentToggle, + visible: true, + x: position.x, + y: position.y + }); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Handle menu click. - */ - onClickOccurrenceFrom() { - const message = this.state.message; - if (message) { - Actions._toggleOccurrence(message.occurrences, message.from); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Toggle occurrence state. + */ + onClickOccurrenceToggle() { + const message = this.state.message; + if (message) { + const oFromState = Actions.getOccurrenceState( + message.occurrences, + message.from + ); + const oToState = Actions.getOccurrenceState( + message.occurrences, + message.to + ); + const oExpanded = oFromState > 0 || oToState > 0; + if (oExpanded) { + this.setState({ occurrencesExpanded: true }); + } else { + const occurrencesExpanded = !this.state.occurrencesExpanded; + this.setState({ occurrencesExpanded }); + } + } } - this.setState({ message }); - this.props.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle menu click. - */ - onClickOccurrenceTo() { - const message = this.state.message; - if (message) { - Actions._toggleOccurrence(message.occurrences, message.to); - } - this.setState({ message }); - this.props.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Toggle fragment. - */ - onClickFragmentToggle() { - const message = this.state.message; - if (message) { - Actions._toggleFragment(message.fragment); - } - this.setState({ message }); - this.props.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle menu click. - * @param event update event. - */ - onChangeFragmentGuard(event) { - const message = this.state.message; - if (message) { - const options = this.props.application.getOptions(); - message.fragment.guard = Common.sanitizeText(event.target.value, options, 'guard'); - } - this.setState({ message }); - this.props.application.renderDiagram(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle menu click. - * @param value updated value. - */ - onChangeFragmentOperator(value) { - const message = this.state.message; - if (message) { - message.fragment.operator = value.value; - } - this.setState({ message }); - this.props.application.renderDiagram(); - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + */ + onClickOccurrenceFrom() { + const message = this.state.message; + if (message) { + Actions._toggleOccurrence(message.occurrences, message.from); + } + this.setState({ message }); + this.props.application.renderDiagram(); + } - /** - * Handle mouse movement. - */ - onMouseOut() { - this.setState({ id: -1, visible: false, x: 0, y: 0 }); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + */ + onClickOccurrenceTo() { + const message = this.state.message; + if (message) { + Actions._toggleOccurrence(message.occurrences, message.to); + } + this.setState({ message }); + this.props.application.renderDiagram(); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Toggle fragment. + */ + onClickFragmentToggle() { + const message = this.state.message; + if (message) { + Actions._toggleFragment(message.fragment); + } + this.setState({ message }); + this.props.application.renderDiagram(); + } - /** - * Render view. - * @returns {XML} - */ - render() { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + * @param event update event. + */ + onChangeFragmentGuard(event) { + const message = this.state.message; + if (message) { + const options = this.props.application.getOptions(); + message.fragment.guard = Common.sanitizeText( + event.target.value, + options, + 'guard' + ); + } + this.setState({ message }); + this.props.application.renderDiagram(); + } - const actionsStyles = { }; - const message = this.state.message; - if (!message || !this.state.visible) { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + * @param value updated value. + */ + onChangeFragmentOperator(value) { + const message = this.state.message; + if (message) { + message.fragment.operator = value.value; + } + this.setState({ message }); + this.props.application.renderDiagram(); + } - // Invisible. + // /////////////////////////////////////////////////////////////////////////////////////////////// - return (<div className="asdcs-actions" ></div>); + /** + * Handle mouse movement. + */ + onMouseOut() { + this.setState({ id: -1, visible: false, x: 0, y: 0 }); } - // Position and display. - - actionsStyles.display = 'block'; - actionsStyles.left = this.state.x - 10; - actionsStyles.top = this.state.y - 10; - - const oFromState = Actions.getOccurrenceState(message.occurrences, message.from); - const oToState = Actions.getOccurrenceState(message.occurrences, message.to); - const fState = Actions.getFragmentState(message.fragment); - - const oExpanded = this.state.occurrencesExpanded || (oFromState > 0) || (oToState > 0); - const oAuxClassName = oExpanded ? '' : 'asdcs-hidden'; - - const fExpanded = fState !== 0; - const fAuxClassName = fExpanded ? '' : 'asdcs-hidden'; - - const fragmentOperatorOptions = [{ - value: 'alt', - label: 'Alternate', - }, { - value: 'opt', - label: 'Optional', - }, { - value: 'loop', - label: 'Loop', - }]; - - const operator = message.fragment.operator || 'alt'; - - return ( - <div - className="asdcs-actions" - style={actionsStyles} - onMouseLeave={this.onMouseOut} - > - <div className="asdcs-actions-header"> - <div className="asdcs-actions-icon"> - <Icon glyph={iconSettings} /> - </div> - </div> - - <div className="asdcs-actions-options"> - - <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence"> - <div - className="asdcs-actions-option asdcs-actions-option-occurrence-toggle" - onClick={this.onClickOccurrenceToggle} - > - <span className="asdcs-label">Occurrence</span> - <div className="asdcs-actions-state"> - <Icon glyph={iconCollapsed} className={oExpanded ? 'asdcs-hidden' : ''} /> - <Icon glyph={iconExpanded} className={oExpanded ? '' : 'asdcs-hidden'} /> - </div> - </div> - </div> - - <div - className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`} - onClick={this.onClickOccurrenceFrom} - > - <span className="asdcs-label">From</span> - <div className="asdcs-actions-state"> - <span className="asdcs-annotation"></span> - <Icon glyph={iconOccurrenceDefault} className={oFromState === 0 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconOccurrenceStart} className={oFromState === 1 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconOccurrenceStop} className={oFromState === 2 ? '' : 'asdcs-hidden'} /> - </div> - </div> - - <div - className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`} - onClick={this.onClickOccurrenceTo} - > - <span className="asdcs-label">To</span> - <div className="asdcs-actions-state"> - <span className="asdcs-annotation"></span> - <Icon glyph={iconOccurrenceDefault} className={oToState === 0 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconOccurrenceStart} className={oToState === 1 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconOccurrenceStop} className={oToState === 2 ? '' : 'asdcs-hidden'} /> - </div> - </div> - - <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment"> + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render view. + * @returns {XML} + */ + render() { + const actionsStyles = {}; + const message = this.state.message; + if (!message || !this.state.visible) { + // Invisible. + + return <div className="asdcs-actions" />; + } + + // Position and display. + + actionsStyles.display = 'block'; + actionsStyles.left = this.state.x - 10; + actionsStyles.top = this.state.y - 10; + + const oFromState = Actions.getOccurrenceState( + message.occurrences, + message.from + ); + const oToState = Actions.getOccurrenceState( + message.occurrences, + message.to + ); + const fState = Actions.getFragmentState(message.fragment); + + const oExpanded = + this.state.occurrencesExpanded || oFromState > 0 || oToState > 0; + const oAuxClassName = oExpanded ? '' : 'asdcs-hidden'; + + const fExpanded = fState !== 0; + const fAuxClassName = fExpanded ? '' : 'asdcs-hidden'; + + const fragmentOperatorOptions = [ + { + value: 'alt', + label: 'Alternate' + }, + { + value: 'opt', + label: 'Optional' + }, + { + value: 'loop', + label: 'Loop' + } + ]; + + const operator = message.fragment.operator || 'alt'; + + return ( <div - className="asdcs-actions-option asdcs-actions-fragment-toggle" - onClick={this.onClickFragmentToggle} - > - <span className="asdcs-label">Fragment</span> - <div className="asdcs-actions-state"> - <span className="asdcs-annotation"></span> - <Icon glyph={iconFragmentDefault} className={fState === 0 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconFragmentStart} className={fState === 1 ? '' : 'asdcs-hidden'} /> - <Icon glyph={iconFragmentStop} className={fState === 2 ? '' : 'asdcs-hidden'} /> - </div> + className="asdcs-actions" + style={actionsStyles} + onMouseLeave={this.onMouseOut}> + <div className="asdcs-actions-header"> + <div className="asdcs-actions-icon"> + <Icon glyph={iconSettings} /> + </div> + </div> + + <div className="asdcs-actions-options"> + <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-occurrence"> + <div + className="asdcs-actions-option asdcs-actions-option-occurrence-toggle" + onClick={this.onClickOccurrenceToggle}> + <span className="asdcs-label">Occurrence</span> + <div className="asdcs-actions-state"> + <Icon + glyph={iconCollapsed} + className={oExpanded ? 'asdcs-hidden' : ''} + /> + <Icon + glyph={iconExpanded} + className={oExpanded ? '' : 'asdcs-hidden'} + /> + </div> + </div> + </div> + + <div + className={`asdcs-actions-option asdcs-actions-option-occurrence-from ${oAuxClassName}`} + onClick={this.onClickOccurrenceFrom}> + <span className="asdcs-label">From</span> + <div className="asdcs-actions-state"> + <span className="asdcs-annotation" /> + <Icon + glyph={iconOccurrenceDefault} + className={ + oFromState === 0 ? '' : 'asdcs-hidden' + } + /> + <Icon + glyph={iconOccurrenceStart} + className={ + oFromState === 1 ? '' : 'asdcs-hidden' + } + /> + <Icon + glyph={iconOccurrenceStop} + className={ + oFromState === 2 ? '' : 'asdcs-hidden' + } + /> + </div> + </div> + + <div + className={`asdcs-actions-option asdcs-actions-option-occurrence-to ${oAuxClassName}`} + onClick={this.onClickOccurrenceTo}> + <span className="asdcs-label">To</span> + <div className="asdcs-actions-state"> + <span className="asdcs-annotation" /> + <Icon + glyph={iconOccurrenceDefault} + className={oToState === 0 ? '' : 'asdcs-hidden'} + /> + <Icon + glyph={iconOccurrenceStart} + className={oToState === 1 ? '' : 'asdcs-hidden'} + /> + <Icon + glyph={iconOccurrenceStop} + className={oToState === 2 ? '' : 'asdcs-hidden'} + /> + </div> + </div> + + <div className="asdcs-actions-optiongroup asdcs-actions-optiongroup-fragment"> + <div + className="asdcs-actions-option asdcs-actions-fragment-toggle" + onClick={this.onClickFragmentToggle}> + <span className="asdcs-label">Fragment</span> + <div className="asdcs-actions-state"> + <span className="asdcs-annotation" /> + <Icon + glyph={iconFragmentDefault} + className={ + fState === 0 ? '' : 'asdcs-hidden' + } + /> + <Icon + glyph={iconFragmentStart} + className={ + fState === 1 ? '' : 'asdcs-hidden' + } + /> + <Icon + glyph={iconFragmentStop} + className={ + fState === 2 ? '' : 'asdcs-hidden' + } + /> + </div> + </div> + </div> + + <div + className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}> + <div className="asdcs-label">Operator</div> + <div className="asdcs-value"> + <Select + className="asdcs-editable-select" + openOnFocus + clearable={false} + searchable={false} + value={operator} + onChange={this.onChangeFragmentOperator} + options={fragmentOperatorOptions} + /> + </div> + </div> + + <div + className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}> + <div className="asdcs-label">Guard</div> + <div className="asdcs-value"> + <input + className="asdcs-editable" + type="text" + size="20" + maxLength="80" + value={message.fragment.guard} + placeholder="Condition" + onChange={this.onChangeFragmentGuard} + /> + </div> + </div> + </div> + + <div className="asdcs-actions-footer" /> </div> - </div> - - <div className={`asdcs-actions-option asdcs-actions-fragment-operator ${fAuxClassName}`}> - <div className="asdcs-label">Operator</div> - <div className="asdcs-value"> - <Select - className="asdcs-editable-select" - openOnFocus - clearable={false} - searchable={false} - value={operator} - onChange={this.onChangeFragmentOperator} - options={fragmentOperatorOptions} - /> - </div> - </div> - - <div className={`asdcs-actions-option asdcs-actions-fragment-guard ${fAuxClassName}`}> - <div className="asdcs-label">Guard</div> - <div className="asdcs-value"> - <input - className="asdcs-editable" - type="text" - size="20" - maxLength="80" - value={message.fragment.guard} - placeholder="Condition" - onChange={this.onChangeFragmentGuard} - /> - </div> - </div> - - </div> - - <div className="asdcs-actions-footer"></div> - - </div> - - ); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Toggle through three occurrence states on click. - * @param occurrence occurrences state, updated as side-effect. - * @param lifelineId message end that's being toggled. - * @private - */ - static _toggleOccurrence(occurrence, lifelineId) { - const o = occurrence; - - const rm = function rm(array, value) { - const index = array.indexOf(value); - if (index !== -1) { - array.splice(index, 1); - } - }; - - const add = function add(array, value) { - if (array.indexOf(value) === -1) { - array.push(value); - } - }; - - if (o.start && o.start.indexOf(lifelineId) !== -1) { - // Start -> stop. - rm(o.start, lifelineId); - add(o.stop, lifelineId); - } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) { - // Stop -> default. - rm(o.start, lifelineId); - rm(o.stop, lifelineId); - } else { - // Default -> start. - add(o.start, lifelineId); - rm(o.stop, lifelineId); + ); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Toggle fragment setting on click. - * @param fragment - * @private - **/ - static _toggleFragment(fragment) { - const f = fragment; - if (f.start === true) { - f.start = false; - f.stop = true; - } else if (f.stop === true) { - f.stop = false; - f.start = false; - } else { - f.start = true; - f.stop = false; - } - f.guard = ''; - f.operator = ''; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get ternary occurrences state. - * @param o occurrences. - * @param lifelineId from/to lifeline ID. - * @returns {number} - * @private - */ - static getOccurrenceState(o, lifelineId) { - if (o.start.indexOf(lifelineId) !== -1) { - return 1; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Toggle through three occurrence states on click. + * @param occurrence occurrences state, updated as side-effect. + * @param lifelineId message end that's being toggled. + * @private + */ + static _toggleOccurrence(occurrence, lifelineId) { + const o = occurrence; + + const rm = function rm(array, value) { + const index = array.indexOf(value); + if (index !== -1) { + array.splice(index, 1); + } + }; + + const add = function add(array, value) { + if (array.indexOf(value) === -1) { + array.push(value); + } + }; + + if (o.start && o.start.indexOf(lifelineId) !== -1) { + // Start -> stop. + rm(o.start, lifelineId); + add(o.stop, lifelineId); + } else if (o.stop && o.stop.indexOf(lifelineId) !== -1) { + // Stop -> default. + rm(o.start, lifelineId); + rm(o.stop, lifelineId); + } else { + // Default -> start. + add(o.start, lifelineId); + rm(o.stop, lifelineId); + } } - if (o.stop.indexOf(lifelineId) !== -1) { - return 2; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Toggle fragment setting on click. + * @param fragment + * @private + **/ + static _toggleFragment(fragment) { + const f = fragment; + if (f.start === true) { + f.start = false; + f.stop = true; + } else if (f.stop === true) { + f.stop = false; + f.start = false; + } else { + f.start = true; + f.stop = false; + } + f.guard = ''; + f.operator = ''; } - return 0; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get ternary fragment state. - * @param f fragment. - * @returns {number} - * @private - */ - static getFragmentState(f) { - if (f.start) { - return 1; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get ternary occurrences state. + * @param o occurrences. + * @param lifelineId from/to lifeline ID. + * @returns {number} + * @private + */ + static getOccurrenceState(o, lifelineId) { + if (o.start.indexOf(lifelineId) !== -1) { + return 1; + } + if (o.stop.indexOf(lifelineId) !== -1) { + return 2; + } + return 0; } - if (f.stop) { - return 2; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get ternary fragment state. + * @param f fragment. + * @returns {number} + * @private + */ + static getFragmentState(f) { + if (f.start) { + return 1; + } + if (f.stop) { + return 2; + } + return 0; } - return 0; - } } /** Element properties. */ Actions.propTypes = { - application: PropTypes.object.isRequired, - model: PropTypes.object.isRequired, + application: PropTypes.object.isRequired, + model: PropTypes.object.isRequired }; export default Actions; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx index 86ee80f72e..09c8d92c9b 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifeline.jsx @@ -28,238 +28,247 @@ import iconDelete from '../../../../../../../../../../res/ecomp/asdc/sequencer/s * LHS lifeline row view. */ class Lifeline extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct editor view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + + this.state = { + active: false, + name: props.lifeline.name + }; + + const metamodel = Common.assertNotNull(this.props.metamodel).unwrap(); + this.canReorder = metamodel.diagram.lifelines.constraints.reorder; + this.canDelete = metamodel.diagram.lifelines.constraints.delete; + + // Bindings. + + this.onChangeName = this.onChangeName.bind(this); + this.onBlurName = this.onBlurName.bind(this); + this.onClickDelete = this.onClickDelete.bind(this); + this.onMouseEnter = this.onMouseEnter.bind(this); + this.onMouseLeave = this.onMouseLeave.bind(this); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct editor view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - - this.state = { - active: false, - name: props.lifeline.name, - }; - - const metamodel = Common.assertNotNull(this.props.metamodel).unwrap(); - this.canReorder = metamodel.diagram.lifelines.constraints.reorder; - this.canDelete = metamodel.diagram.lifelines.constraints.delete; - - // Bindings. - - this.onChangeName = this.onChangeName.bind(this); - this.onBlurName = this.onBlurName.bind(this); - this.onClickDelete = this.onClickDelete.bind(this); - this.onMouseEnter = this.onMouseEnter.bind(this); - this.onMouseLeave = this.onMouseLeave.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle name change. - * @param event change event. - */ - onChangeName(event) { - this.setState({ name: event.target.value }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle name change. - * @param event change event. - */ - onBlurName(event) { - const options = this.props.application.getOptions(); - const sanitized = Common.sanitizeText(event.target.value, options, 'lifeline'); - const props = { - id: this.props.lifeline.id, - name: sanitized, - }; - this.props.designer.updateLifeline(props); - this.setState({ name: sanitized }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Handle lifeline delete. - */ - onClickDelete() { - this.props.designer.deleteLifeline(this.props.lifeline.id); - } + /** + * Handle name change. + * @param event change event. + */ + onChangeName(event) { + this.setState({ name: event.target.value }); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle name change. + * @param event change event. + */ + onBlurName(event) { + const options = this.props.application.getOptions(); + const sanitized = Common.sanitizeText( + event.target.value, + options, + 'lifeline' + ); + const props = { + id: this.props.lifeline.id, + name: sanitized + }; + this.props.designer.updateLifeline(props); + this.setState({ name: sanitized }); + } - /** - * Handle mouseover event. - */ - onMouseEnter() { - this.setState({ active: true }); - this.props.designer.onMouseEnterLifeline(this.props.lifeline.id); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Handle lifeline delete. + */ + onClickDelete() { + this.props.designer.deleteLifeline(this.props.lifeline.id); + } - /** - * Handle mouseleave event. - */ - onMouseLeave() { - this.setState({ active: false }); - this.props.designer.onMouseLeaveLifeline(this.props.lifeline.id); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Handle mouseover event. + */ + onMouseEnter() { + this.setState({ active: true }); + this.props.designer.onMouseEnterLifeline(this.props.lifeline.id); + } - /** - * Get whether metadata permits reorder. - * @returns true if reorderable. - */ - isCanReorder() { - return this.canReorder; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Handle mouseleave event. + */ + onMouseLeave() { + this.setState({ active: false }); + this.props.designer.onMouseLeaveLifeline(this.props.lifeline.id); + } - /** - * Get whether metadata permits delete. - * @returns true if lifeline can be deleted. - */ - isCanDelete() { - return this.canDelete; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Get whether metadata permits reorder. + * @returns true if reorderable. + */ + isCanReorder() { + return this.canReorder; + } - /** - * React render. - * @returns {*} - */ - render() { + // /////////////////////////////////////////////////////////////////////////////////////////////// - const id = this.props.lifeline.id; - const activeClass = (this.props.active === true) ? 'asdcs-active' : ''; - const { connectDragSource, connectDropTarget } = this.props; - return connectDragSource(connectDropTarget( + /** + * Get whether metadata permits delete. + * @returns true if lifeline can be deleted. + */ + isCanDelete() { + return this.canDelete; + } - <div - className={`asdcs-designer-lifeline ${activeClass}`} - data-id={id} - onMouseEnter={this.onMouseEnter} - onMouseLeave={this.onMouseLeave} - > - <table className="asdcs-designer-layout asdcs-designer-lifeline-row1"> - <tbody> - <tr> - <td> - <div className="asdcs-designer-sort asdcs-designer-icon"> - <Icon glyph={iconHandle} /> - </div> - </td> - <td> - <div className="asdcs-designer-lifeline-index">{this.props.lifeline.index}.</div> - </td> - <td> - <div className="asdcs-designer-lifeline-name"> - <input - type="text" - className="asdcs-editable" - placeholder="Unnamed" - value={this.state.name} - onChange={this.onChangeName} - onBlur={this.onBlurName} - /> + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * React render. + * @returns {*} + */ + render() { + const id = this.props.lifeline.id; + const activeClass = this.props.active === true ? 'asdcs-active' : ''; + const { connectDragSource, connectDropTarget } = this.props; + return connectDragSource( + connectDropTarget( + <div + className={`asdcs-designer-lifeline ${activeClass}`} + data-id={id} + onMouseEnter={this.onMouseEnter} + onMouseLeave={this.onMouseLeave}> + <table className="asdcs-designer-layout asdcs-designer-lifeline-row1"> + <tbody> + <tr> + <td> + <div className="asdcs-designer-sort asdcs-designer-icon"> + <Icon glyph={iconHandle} /> + </div> + </td> + <td> + <div className="asdcs-designer-lifeline-index"> + {this.props.lifeline.index}. + </div> + </td> + <td> + <div className="asdcs-designer-lifeline-name"> + <input + type="text" + className="asdcs-editable" + placeholder="Unnamed" + value={this.state.name} + onChange={this.onChangeName} + onBlur={this.onBlurName} + /> + </div> + </td> + <td> + <div + className="asdcs-designer-delete asdcs-designer-icon" + onClick={this.onClickDelete}> + <Icon glyph={iconDelete} /> + </div> + </td> + </tr> + </tbody> + </table> </div> - </td> - <td> - <div className="asdcs-designer-delete asdcs-designer-icon" onClick={this.onClickDelete}> - <Icon glyph={iconDelete} /> - </div> - </td> - </tr> - </tbody> - </table> - </div> - )); - } + ) + ); + } } /** * Declare properties. */ Lifeline.propTypes = { - application: PropTypes.object.isRequired, - designer: PropTypes.object.isRequired, - lifeline: PropTypes.object.isRequired, - active: PropTypes.bool.isRequired, - metamodel: PropTypes.object.isRequired, - id: PropTypes.any.isRequired, - index: PropTypes.number.isRequired, - lifelines: PropTypes.object.isRequired, - isDragging: PropTypes.bool.isRequired, - connectDragSource: PropTypes.func.isRequired, - connectDropTarget: PropTypes.func.isRequired, + application: PropTypes.object.isRequired, + designer: PropTypes.object.isRequired, + lifeline: PropTypes.object.isRequired, + active: PropTypes.bool.isRequired, + metamodel: PropTypes.object.isRequired, + id: PropTypes.any.isRequired, + index: PropTypes.number.isRequired, + lifelines: PropTypes.object.isRequired, + isDragging: PropTypes.bool.isRequired, + connectDragSource: PropTypes.func.isRequired, + connectDropTarget: PropTypes.func.isRequired }; /** DND. */ const source = { - beginDrag(props) { - return { - id: props.id, - index: props.index, - }; - }, + beginDrag(props) { + return { + id: props.id, + index: props.index + }; + } }; /** DND. */ const sourceCollect = function collection(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - }; + return { + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging() + }; }; /** DND. */ const target = { - drop(props, monitor, component) { - Common.assertNotNull(props); - Common.assertNotNull(monitor); - const decorated = component.getDecoratedComponentInstance(); - if (decorated) { - const lifelines = decorated.props.lifelines; - if (lifelines) { - const dragIndex = monitor.getItem().index; - const hoverIndex = lifelines.getHoverIndex(); - lifelines.onDrop(dragIndex, hoverIndex); - } - } - }, - hover(props, monitor, component) { - Common.assertNotNull(props); - Common.assertNotNull(monitor); - if (component) { - const decorated = component.getDecoratedComponentInstance(); - if (decorated) { - const lifelines = decorated.props.lifelines; - if (lifelines) { - lifelines.setHoverIndex(decorated.props.index); + drop(props, monitor, component) { + Common.assertNotNull(props); + Common.assertNotNull(monitor); + const decorated = component.getDecoratedComponentInstance(); + if (decorated) { + const lifelines = decorated.props.lifelines; + if (lifelines) { + const dragIndex = monitor.getItem().index; + const hoverIndex = lifelines.getHoverIndex(); + lifelines.onDrop(dragIndex, hoverIndex); + } + } + }, + hover(props, monitor, component) { + Common.assertNotNull(props); + Common.assertNotNull(monitor); + if (component) { + const decorated = component.getDecoratedComponentInstance(); + if (decorated) { + const lifelines = decorated.props.lifelines; + if (lifelines) { + lifelines.setHoverIndex(decorated.props.index); + } + } } - } } - }, }; /** DND. */ function targetCollect(connect, monitor) { - return { - connectDropTarget: connect.dropTarget(), - isOver: monitor.isOver(), - }; + return { + connectDropTarget: connect.dropTarget(), + isOver: monitor.isOver() + }; } - +/* eslint-disable new-cap */ const wrapper1 = DragSource('lifeline', source, sourceCollect)(Lifeline); -export default DropTarget(['lifeline', 'lifeline-new'], target, targetCollect)(wrapper1); +export default DropTarget(['lifeline', 'lifeline-new'], target, targetCollect)( + wrapper1 +); +/* eslint-enable new-cap */ diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx index a8147be370..beb6364670 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/LifelineNew.jsx @@ -26,88 +26,92 @@ import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/s * LHS lifeline row view. */ class LifelineNew extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); + // Bindings. - // Bindings. + this.onClickAdd = this.onClickAdd.bind(this); + } - this.onClickAdd = this.onClickAdd.bind(this); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Handle click event. + */ + onClickAdd() { + this.props.designer.addLifeline(); + } - /** - * Handle click event. - */ - onClickAdd() { - this.props.designer.addLifeline(); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render view. - * @returns {*} - */ - render() { - const { connectDragSource } = this.props; - return connectDragSource( - <div className="asdcs-designer-lifeline asdcs-designer-lifeline-new"> - <table className="asdcs-designer-layout asdcs-designer-lifeline-new"> - <tbody> - <tr> - <td> - <div className="asdcs-designer-sort asdcs-designer-icon"> - <Icon glyph={iconHandle} /> - </div> - </td> - <td> - <div className="asdcs-designer-label" onClick={this.onClickAdd}> - Add Lifeline - </div> - </td> - <td> - <div className="asdcs-designer-icon" onClick={this.onClickAdd}> - <Icon glyph={iconPlus} /> - </div> - </td> - <td> </td> - </tr> - </tbody> - </table> - </div> - ); - } + /** + * Render view. + * @returns {*} + */ + render() { + const { connectDragSource } = this.props; + return connectDragSource( + <div className="asdcs-designer-lifeline asdcs-designer-lifeline-new"> + <table className="asdcs-designer-layout asdcs-designer-lifeline-new"> + <tbody> + <tr> + <td> + <div className="asdcs-designer-sort asdcs-designer-icon"> + <Icon glyph={iconHandle} /> + </div> + </td> + <td> + <div + className="asdcs-designer-label" + onClick={this.onClickAdd}> + Add Lifeline + </div> + </td> + <td> + <div + className="asdcs-designer-icon" + onClick={this.onClickAdd}> + <Icon glyph={iconPlus} /> + </div> + </td> + <td> </td> + </tr> + </tbody> + </table> + </div> + ); + } } /** Element properties. */ LifelineNew.propTypes = { - designer: PropTypes.object.isRequired, - lifelines: PropTypes.object.isRequired, - connectDragSource: PropTypes.func.isRequired, + designer: PropTypes.object.isRequired, + lifelines: PropTypes.object.isRequired, + connectDragSource: PropTypes.func.isRequired }; /** DND. */ const source = { - beginDrag(props) { - return { id: props.id }; - }, + beginDrag(props) { + return { id: props.id }; + } }; /** DND. */ const collect = function collection(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - }; + return { + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging() + }; }; - +/* eslint-disable new-cap */ export default DragSource('lifeline-new', source, collect)(LifelineNew); +/* eslint-enable new-cap */ diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx index 2f82fec7a0..248264b6df 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/lifeline/Lifelines.jsx @@ -28,111 +28,110 @@ import LifelineNew from './LifelineNew'; * @constructor */ class Lifelines extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + this.setHoverIndex = this.setHoverIndex.bind(this); + this.getHoverIndex = this.getHoverIndex.bind(this); + this.onDrop = this.onDrop.bind(this); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - this.setHoverIndex = this.setHoverIndex.bind(this); - this.getHoverIndex = this.getHoverIndex.bind(this); - this.onDrop = this.onDrop.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Record last hover index as non-state. - * @param index index. - */ - setHoverIndex(index) { - this.hoverIndex = index; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get last recorded hover index. - * @returns {*} - */ - getHoverIndex() { - return this.hoverIndex; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle drop. - * @param dragIndex dragged item index; undefined if new. - * @param hoverIndex drop index. - */ - onDrop(dragIndex, hoverIndex) { - if (hoverIndex >= 0) { - const application = this.props.application; - const model = application.getModel(); - if (Common.isNumber(dragIndex)) { - if (dragIndex !== hoverIndex) { - model.reorderLifelines(dragIndex, hoverIndex); - } - } else { - model.addLifeline(hoverIndex); - } - this.forceUpdate(); - application.renderDiagram(); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Record last hover index as non-state. + * @param index index. + */ + setHoverIndex(index) { + this.hoverIndex = index; + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get last recorded hover index. + * @returns {*} + */ + getHoverIndex() { + return this.hoverIndex; } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render view. - * @returns {XML} - */ - render() { - const model = this.props.application.getModel(); - const metamodel = model.getMetamodel(); - const diagram = model.unwrap().diagram; - - const lifelines = []; - for (const lifeline of diagram.lifelines) { - lifelines.push(<Lifeline - key={`l${lifeline.id}`} - application={this.props.application} - designer={this.props.designer} - lifeline={lifeline} - active={this.props.activeLifelineId === lifeline.id} - id={lifeline.id} - metamodel={metamodel} - lifelines={this} - index={lifelines.length} - />); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle drop. + * @param dragIndex dragged item index; undefined if new. + * @param hoverIndex drop index. + */ + onDrop(dragIndex, hoverIndex) { + if (hoverIndex >= 0) { + const application = this.props.application; + const model = application.getModel(); + if (Common.isNumber(dragIndex)) { + if (dragIndex !== hoverIndex) { + model.reorderLifelines(dragIndex, hoverIndex); + } + } else { + model.addLifeline(hoverIndex); + } + this.forceUpdate(); + application.renderDiagram(); + } } - lifelines.push(<LifelineNew - key="_l" - designer={this.props.designer} - lifelines={this} - />); - - return ( - <div className="asdcs-designer-lifelines"> - {lifelines} - </div> - ); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render view. + * @returns {XML} + */ + render() { + const model = this.props.application.getModel(); + const metamodel = model.getMetamodel(); + const diagram = model.unwrap().diagram; + + const lifelines = []; + for (const lifeline of diagram.lifelines) { + lifelines.push( + <Lifeline + key={`l${lifeline.id}`} + application={this.props.application} + designer={this.props.designer} + lifeline={lifeline} + active={this.props.activeLifelineId === lifeline.id} + id={lifeline.id} + metamodel={metamodel} + lifelines={this} + index={lifelines.length} + /> + ); + } + + lifelines.push( + <LifelineNew + key="_l" + designer={this.props.designer} + lifelines={this} + /> + ); + + return <div className="asdcs-designer-lifelines">{lifelines}</div>; + } } /** * Declare properties. */ Lifelines.propTypes = { - application: PropTypes.object.isRequired, - designer: PropTypes.object.isRequired, - activeLifelineId: PropTypes.string, + application: PropTypes.object.isRequired, + designer: PropTypes.object.isRequired, + activeLifelineId: PropTypes.string }; export default Lifelines; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx index a2c7f5122a..ba77e8658f 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Message.jsx @@ -34,482 +34,480 @@ import iconResponse from '../../../../../../../../../../res/ecomp/asdc/sequencer * LHS message row view. */ class Message extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + + this.state = { + active: false, + name: props.message.name || '' + }; + + this.combinedOptions = [ + { + value: 'REQUEST_SYNC' + }, + { + value: 'REQUEST_ASYNC' + }, + { + value: 'RESPONSE' + } + ]; + + // Bindings. + + this.onChangeName = this.onChangeName.bind(this); + this.onBlurName = this.onBlurName.bind(this); + this.onChangeType = this.onChangeType.bind(this); + this.onChangeFrom = this.onChangeFrom.bind(this); + this.onChangeTo = this.onChangeTo.bind(this); + this.onClickDelete = this.onClickDelete.bind(this); + this.onClickActions = this.onClickActions.bind(this); + this.onClickNotes = this.onClickNotes.bind(this); + this.onMouseEnter = this.onMouseEnter.bind(this); + this.onMouseLeave = this.onMouseLeave.bind(this); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); + /** + * Handle name change. + * @param event change event. + */ + onChangeName(event) { + this.setState({ name: event.target.value }); + } - this.state = { - active: false, - name: props.message.name || '', - }; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle name change. + * @param event change event. + */ + onBlurName(event) { + const options = this.props.application.getOptions(); + const sanitized = Common.sanitizeText( + event.target.value, + options, + 'message' + ); + const props = { + id: this.props.message.id, + name: sanitized + }; + this.props.designer.updateMessage(props); + this.setState({ name: sanitized }); + } - this.combinedOptions = [{ - value: 'REQUEST_SYNC', - }, { - value: 'REQUEST_ASYNC', - }, { - value: 'RESPONSE', - }]; - - // Bindings. - - this.onChangeName = this.onChangeName.bind(this); - this.onBlurName = this.onBlurName.bind(this); - this.onChangeType = this.onChangeType.bind(this); - this.onChangeFrom = this.onChangeFrom.bind(this); - this.onChangeTo = this.onChangeTo.bind(this); - this.onClickDelete = this.onClickDelete.bind(this); - this.onClickActions = this.onClickActions.bind(this); - this.onClickNotes = this.onClickNotes.bind(this); - this.onMouseEnter = this.onMouseEnter.bind(this); - this.onMouseLeave = this.onMouseLeave.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle name change. - * @param event change event. - */ - onChangeName(event) { - this.setState({ name: event.target.value }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle name change. - * @param event change event. - */ - onBlurName(event) { - const options = this.props.application.getOptions(); - const sanitized = Common.sanitizeText(event.target.value, options, 'message'); - const props = { - id: this.props.message.id, - name: sanitized, - }; - this.props.designer.updateMessage(props); - this.setState({ name: sanitized }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle delete. - */ - onClickDelete() { - this.props.designer.deleteMessage(this.props.message.id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle menu click. - */ - onClickActions(event) { - this.props.designer.showActions(this.props.message.id, { x: event.pageX, y: event.pageY }); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle menu click. - */ - onClickNotes() { - this.props.designer.showNotes(this.props.message.id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle selection. - * @param value selection. - */ - onChangeFrom(value) { - if (value.target) { - this.updateMessage({ from: value.target.value }); - } else { - this.updateMessage({ from: value.value }); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle delete. + */ + onClickDelete() { + this.props.designer.deleteMessage(this.props.message.id); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle selection. - * @param value selection. - */ - onChangeTo(value) { - if (value.target) { - this.updateMessage({ to: value.target.value }); - } else { - this.updateMessage({ to: value.value }); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + */ + onClickActions(event) { + this.props.designer.showActions(this.props.message.id, { + x: event.pageX, + y: event.pageY + }); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle selection. - * @param selected selection. - */ - onChangeType(selected) { - - const value = selected.target ? selected.target.value : selected.value; - const props = {}; - if (value.indexOf('RESPONSE') !== -1) { - props.type = 'response'; - props.asynchronous = false; - } else { - props.type = 'request'; - props.asynchronous = (value.indexOf('ASYNC') !== -1); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle menu click. + */ + onClickNotes() { + this.props.designer.showNotes(this.props.message.id); } - this.updateMessage(props); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - */ - onMouseEnter() { - this.setState({ active: true }); - this.props.designer.onMouseEnterMessage(this.props.message.id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle mouse event. - */ - onMouseLeave() { - this.setState({ active: false }); - this.props.designer.onMouseLeaveMessage(this.props.message.id); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Update message properties. - * @param props properties updates. - */ - updateMessage(props) { - const update = { - id: this.props.message.id, - }; - for (const k of Object.keys(props)) { - update[k] = props[k]; + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle selection. + * @param value selection. + */ + onChangeFrom(value) { + if (value.target) { + this.updateMessage({ from: value.target.value }); + } else { + this.updateMessage({ from: value.value }); + } } - this.props.designer.updateMessage(update); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render icon. - * @param option selection. - * @returns {XML} - */ - renderOption(option) { - if (option.value === 'RESPONSE') { - return <Icon glyph={iconResponse} />; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle selection. + * @param value selection. + */ + onChangeTo(value) { + if (value.target) { + this.updateMessage({ to: value.target.value }); + } else { + this.updateMessage({ to: value.value }); + } } - if (option.value === 'REQUEST_ASYNC') { - return <Icon glyph={iconRequestAsync} />; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle selection. + * @param selected selection. + */ + onChangeType(selected) { + const value = selected.target ? selected.target.value : selected.value; + const props = {}; + if (value.indexOf('RESPONSE') !== -1) { + props.type = 'response'; + props.asynchronous = false; + } else { + props.type = 'request'; + props.asynchronous = value.indexOf('ASYNC') !== -1; + } + + this.updateMessage(props); } - return <Icon glyph={iconRequestSync} />; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get request/response and asynchronous combined constant. - * @param message message whose properties define spec. - * @returns {*} - */ - getMessageSpec(message) { - if (message.type === 'response') { - return 'RESPONSE'; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle mouse event. + */ + onMouseEnter() { + this.setState({ active: true }); + this.props.designer.onMouseEnterMessage(this.props.message.id); } - if (message.asynchronous) { - return 'REQUEST_ASYNC'; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle mouse event. + */ + onMouseLeave() { + this.setState({ active: false }); + this.props.designer.onMouseLeaveMessage(this.props.message.id); } - return 'REQUEST_SYNC'; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * @returns {*} - * @private - */ - renderHTMLSelect() { - - const message = this.props.message; - const from = this.props.from; - const to = Common.assertNotNull(this.props.to); - const messageNotesActiveClass = message.notes && message.notes.length > 0 ? 'asdcs-active' : ''; - const combinedValue = this.getMessageSpec(message); - - const lifelineOptions = []; - for (const lifeline of this.props.model.unwrap().diagram.lifelines) { - lifelineOptions.push(<option - key={lifeline.id} - value={lifeline.id} - > - {lifeline.name} - </option>); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Update message properties. + * @param props properties updates. + */ + updateMessage(props) { + const update = { + id: this.props.message.id + }; + for (const k of Object.keys(props)) { + update[k] = props[k]; + } + this.props.designer.updateMessage(update); } - const activeClass = (this.state.active || this.props.active) ? 'asdcs-active' : ''; - const { connectDragSource, connectDropTarget } = this.props; - return connectDragSource(connectDropTarget( - <div - className={`asdcs-designer-message ${activeClass}`} - data-id={message.id} - onMouseEnter={this.onMouseEnter} - onMouseLeave={this.onMouseLeave} - > - - <table className="asdcs-designer-layout asdcs-designer-message-row1"> - <tbody> - <tr> - <td> - <div className="asdcs-designer-sort asdcs-designer-icon"> - <Icon glyph={iconHandle} /> - </div> - </td> - <td> - <div className="asdcs-designer-message-index">{message.index}.</div> - </td> - <td> - <div className="asdcs-designer-message-name"> - <input - type="text" - className="asdcs-editable" - value={this.state.name} - placeholder="Unnamed" - onBlur={this.onBlurName} - onChange={this.onChangeName} - /> - </div> - </td> - <td> - <div className="asdcs-designer-actions"> - <div - className="asdcs-designer-settings asdcs-designer-icon" - onClick={this.onClickActions} - > - <Icon glyph={iconSettings} /> - </div> - <div - className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`} - onClick={this.onClickNotes} - > - <Icon glyph={iconNotes} /> - </div> - <div - className="asdcs-designer-delete asdcs-designer-icon" - onClick={this.onClickDelete} - > - <Icon glyph={iconDelete} /> - </div> - </div> - </td> - </tr> - </tbody> - </table> - - <table className="asdcs-designer-layout asdcs-designer-message-row2"> - <tbody> - <tr> - <td> - <select - onChange={this.onChangeFrom} - className="asdcs-designer-select-message-from" - value={from.id} - onChange={this.onChangeFrom} - > - options={lifelineOptions} - </select> - </td> - <td> - <select - onChange={this.onChangeFrom} - className="asdcs-designer-select-message-type" - value={combinedValue} - onChange={this.onChangeType} - > - <option value="REQUEST_SYNC">⇾</option> - <option value="REQUEST_ASYNC">→</option> - <option value="RESPONSE">⇠</option> - </select> - </td> - <td> - <select - onChange={this.onChangeFrom} - className="asdcs-designer-select-message-to" - value={to.id} - onChange={this.onChangeTo} - > - options={lifelineOptions} - </select> - </td> - </tr> - </tbody> - </table> - - </div> - )); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render view. - * @returns {*} - * @private - */ - renderReactSelect() { - - const message = this.props.message; - const from = this.props.from; - const to = Common.assertNotNull(this.props.to); - const messageNotesActiveClass = message.notes && message.notes.length > 0 ? 'asdcs-active' : ''; - const combinedValue = this.getMessageSpec(message); - - const lifelineOptions = []; - for (const lifeline of this.props.model.unwrap().diagram.lifelines) { - lifelineOptions.push({ - value: lifeline.id, - label: lifeline.name, - }); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render icon. + * @param option selection. + * @returns {XML} + */ + renderOption(option) { + if (option.value === 'RESPONSE') { + return <Icon glyph={iconResponse} />; + } + if (option.value === 'REQUEST_ASYNC') { + return <Icon glyph={iconRequestAsync} />; + } + return <Icon glyph={iconRequestSync} />; } - const activeClass = (this.state.active || this.props.active) ? 'asdcs-active' : ''; - const { connectDragSource, connectDropTarget } = this.props; - return connectDragSource(connectDropTarget( - - <div - className={`asdcs-designer-message ${activeClass}`} - data-id={message.id} - onMouseEnter={this.onMouseEnter} - onMouseLeave={this.onMouseLeave} - > - - <table className="asdcs-designer-layout asdcs-designer-message-row1"> - <tbody> - <tr> - <td> - <div className="asdcs-designer-sort asdcs-designer-icon"> - <Icon glyph={iconHandle} /> - </div> - </td> - <td> - <div className="asdcs-designer-message-index">{message.index}.</div> - </td> - <td> - <div className="asdcs-designer-message-name"> - <input - type="text" - className="asdcs-editable" - value={this.state.name} - placeholder="Unnamed" - onBlur={this.onBlurName} - onChange={this.onChangeName} - /> + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get request/response and asynchronous combined constant. + * @param message message whose properties define spec. + * @returns {*} + */ + getMessageSpec(message) { + if (message.type === 'response') { + return 'RESPONSE'; + } + if (message.asynchronous) { + return 'REQUEST_ASYNC'; + } + return 'REQUEST_SYNC'; + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * @returns {*} + * @private + */ + renderHTMLSelect() { + const message = this.props.message; + const from = this.props.from; + const to = Common.assertNotNull(this.props.to); + const messageNotesActiveClass = + message.notes && message.notes.length > 0 ? 'asdcs-active' : ''; + const combinedValue = this.getMessageSpec(message); + + const lifelineOptions = []; + for (const lifeline of this.props.model.unwrap().diagram.lifelines) { + lifelineOptions.push( + <option key={lifeline.id} value={lifeline.id}> + {lifeline.name} + </option> + ); + } + + const activeClass = + this.state.active || this.props.active ? 'asdcs-active' : ''; + const { connectDragSource, connectDropTarget } = this.props; + return connectDragSource( + connectDropTarget( + <div + className={`asdcs-designer-message ${activeClass}`} + data-id={message.id} + onMouseEnter={this.onMouseEnter} + onMouseLeave={this.onMouseLeave}> + <table className="asdcs-designer-layout asdcs-designer-message-row1"> + <tbody> + <tr> + <td> + <div className="asdcs-designer-sort asdcs-designer-icon"> + <Icon glyph={iconHandle} /> + </div> + </td> + <td> + <div className="asdcs-designer-message-index"> + {message.index}. + </div> + </td> + <td> + <div className="asdcs-designer-message-name"> + <input + type="text" + className="asdcs-editable" + value={this.state.name} + placeholder="Unnamed" + onBlur={this.onBlurName} + onChange={this.onChangeName} + /> + </div> + </td> + <td> + <div className="asdcs-designer-actions"> + <div + className="asdcs-designer-settings asdcs-designer-icon" + onClick={this.onClickActions}> + <Icon glyph={iconSettings} /> + </div> + <div + className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`} + onClick={this.onClickNotes}> + <Icon glyph={iconNotes} /> + </div> + <div + className="asdcs-designer-delete asdcs-designer-icon" + onClick={this.onClickDelete}> + <Icon glyph={iconDelete} /> + </div> + </div> + </td> + </tr> + </tbody> + </table> + + <table className="asdcs-designer-layout asdcs-designer-message-row2"> + <tbody> + <tr> + <td> + <select + className="asdcs-designer-select-message-from" + value={from.id} + onChange={this.onChangeFrom}> + options={lifelineOptions} + </select> + </td> + <td> + <select + className="asdcs-designer-select-message-type" + value={combinedValue} + onChange={this.onChangeType}> + <option value="REQUEST_SYNC">⇾</option> + <option value="REQUEST_ASYNC">→</option> + <option value="RESPONSE">⇠</option> + </select> + </td> + <td> + <select + className="asdcs-designer-select-message-to" + value={to.id} + onChange={this.onChangeTo}> + options={lifelineOptions} + </select> + </td> + </tr> + </tbody> + </table> </div> - </td> - <td> - <div className="asdcs-designer-actions"> - <div - className="asdcs-designer-settings asdcs-designer-icon" - onClick={this.onClickActions} - > - <Icon glyph={iconSettings} /> - </div> - <div - className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`} - onClick={this.onClickNotes} - > - <Icon glyph={iconNotes} /> - </div> - <div - className="asdcs-designer-delete asdcs-designer-icon" - onClick={this.onClickDelete} - > - <Icon glyph={iconDelete} /> - </div> + ) + ); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render view. + * @returns {*} + * @private + */ + renderReactSelect() { + const message = this.props.message; + const from = this.props.from; + const to = Common.assertNotNull(this.props.to); + const messageNotesActiveClass = + message.notes && message.notes.length > 0 ? 'asdcs-active' : ''; + const combinedValue = this.getMessageSpec(message); + + const lifelineOptions = []; + for (const lifeline of this.props.model.unwrap().diagram.lifelines) { + lifelineOptions.push({ + value: lifeline.id, + label: lifeline.name + }); + } + + const activeClass = + this.state.active || this.props.active ? 'asdcs-active' : ''; + const { connectDragSource, connectDropTarget } = this.props; + return connectDragSource( + connectDropTarget( + <div + className={`asdcs-designer-message ${activeClass}`} + data-id={message.id} + onMouseEnter={this.onMouseEnter} + onMouseLeave={this.onMouseLeave}> + <table className="asdcs-designer-layout asdcs-designer-message-row1"> + <tbody> + <tr> + <td> + <div className="asdcs-designer-sort asdcs-designer-icon"> + <Icon glyph={iconHandle} /> + </div> + </td> + <td> + <div className="asdcs-designer-message-index"> + {message.index}. + </div> + </td> + <td> + <div className="asdcs-designer-message-name"> + <input + type="text" + className="asdcs-editable" + value={this.state.name} + placeholder="Unnamed" + onBlur={this.onBlurName} + onChange={this.onChangeName} + /> + </div> + </td> + <td> + <div className="asdcs-designer-actions"> + <div + className="asdcs-designer-settings asdcs-designer-icon" + onClick={this.onClickActions}> + <Icon glyph={iconSettings} /> + </div> + <div + className={`asdcs-designer-notes asdcs-designer-icon ${messageNotesActiveClass}`} + onClick={this.onClickNotes}> + <Icon glyph={iconNotes} /> + </div> + <div + className="asdcs-designer-delete asdcs-designer-icon" + onClick={this.onClickDelete}> + <Icon glyph={iconDelete} /> + </div> + </div> + </td> + </tr> + </tbody> + </table> + + <table className="asdcs-designer-layout asdcs-designer-message-row2"> + <tbody> + <tr> + <td> + <Select + className="asdcs-editable-select asdcs-designer-editable-message-from" + openOnFocus + clearable={false} + searchable={false} + value={from.id} + onChange={this.onChangeFrom} + options={lifelineOptions} + /> + </td> + <td> + <Select + className="asdcs-editable-select asdcs-designer-editable-message-type" + openOnFocus + clearable={false} + searchable={false} + value={combinedValue} + onChange={this.onChangeType} + options={this.combinedOptions} + optionRenderer={this.renderOption} + valueRenderer={this.renderOption} + /> + </td> + <td> + <Select + className="asdcs-editable-select asdcs-designer-editable-message-to" + openOnFocus + clearable={false} + searchable={false} + value={to.id} + onChange={this.onChangeTo} + options={lifelineOptions} + /> + </td> + </tr> + </tbody> + </table> </div> - </td> - </tr> - </tbody> - </table> - - <table className="asdcs-designer-layout asdcs-designer-message-row2"> - <tbody> - <tr> - <td> - <Select - className="asdcs-editable-select asdcs-designer-editable-message-from" - openOnFocus - clearable={false} - searchable={false} - value={from.id} - onChange={this.onChangeFrom} - options={lifelineOptions} - /> - </td> - <td> - <Select - className="asdcs-editable-select asdcs-designer-editable-message-type" - openOnFocus - clearable={false} - searchable={false} - value={combinedValue} - onChange={this.onChangeType} - options={this.combinedOptions} - optionRenderer={this.renderOption} - valueRenderer={this.renderOption} - /> - </td> - <td> - <Select - className="asdcs-editable-select asdcs-designer-editable-message-to" - openOnFocus - clearable={false} - searchable={false} - value={to.id} - onChange={this.onChangeTo} - options={lifelineOptions} - /> - </td> - - </tr> - </tbody> - </table> - - </div> - )); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - render() { - const options = this.props.application.getOptions(); - if (options.useHtmlSelect) { - return this.renderHTMLSelect(); + ) + ); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + render() { + const options = this.props.application.getOptions(); + if (options.useHtmlSelect) { + return this.renderHTMLSelect(); + } + return this.renderReactSelect(); } - return this.renderReactSelect(); - } } /** @@ -517,72 +515,74 @@ class Message extends React.Component { * @type {{designer: *, message: *, from: *, to: *, model: *, connectDragSource: *}} */ Message.propTypes = { - application: PropTypes.object.isRequired, - designer: PropTypes.object.isRequired, - message: PropTypes.object.isRequired, - active: PropTypes.bool.isRequired, - from: PropTypes.object.isRequired, - to: PropTypes.object.isRequired, - model: PropTypes.object.isRequired, - index: PropTypes.number.isRequired, - messages: PropTypes.object.isRequired, - connectDragSource: PropTypes.func.isRequired, - connectDropTarget: PropTypes.func.isRequired, + application: PropTypes.object.isRequired, + designer: PropTypes.object.isRequired, + message: PropTypes.object.isRequired, + active: PropTypes.bool.isRequired, + from: PropTypes.object.isRequired, + to: PropTypes.object.isRequired, + model: PropTypes.object.isRequired, + index: PropTypes.number.isRequired, + messages: PropTypes.object.isRequired, + connectDragSource: PropTypes.func.isRequired, + connectDropTarget: PropTypes.func.isRequired }; /** DND. */ const source = { - beginDrag(props) { - return { - id: props.id, - index: props.index, - }; - }, + beginDrag(props) { + return { + id: props.id, + index: props.index + }; + } }; /** DND. */ const sourceCollect = function collection(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - }; + return { + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging() + }; }; - /** DND. */ const target = { - drop(props, monitor, component) { - Common.assertNotNull(props); - Common.assertNotNull(monitor); - const decorated = component.getDecoratedComponentInstance(); - if (decorated) { - const messages = decorated.props.messages; - if (messages) { - const dragIndex = monitor.getItem().index; - const hoverIndex = messages.getHoverIndex(); - messages.onDrop(dragIndex, hoverIndex); - } + drop(props, monitor, component) { + Common.assertNotNull(props); + Common.assertNotNull(monitor); + const decorated = component.getDecoratedComponentInstance(); + if (decorated) { + const messages = decorated.props.messages; + if (messages) { + const dragIndex = monitor.getItem().index; + const hoverIndex = messages.getHoverIndex(); + messages.onDrop(dragIndex, hoverIndex); + } + } + }, + hover(props, monitor, component) { + Common.assertNotNull(props); + Common.assertNotNull(monitor); + if (component) { + const decorated = component.getDecoratedComponentInstance(); + if (decorated) { + decorated.props.messages.setHoverIndex(decorated.props.index); + } + } } - }, - hover(props, monitor, component) { - Common.assertNotNull(props); - Common.assertNotNull(monitor); - if (component) { - const decorated = component.getDecoratedComponentInstance(); - if (decorated) { - decorated.props.messages.setHoverIndex(decorated.props.index); - } - } - }, }; /** DND. */ function targetCollect(connect, monitor) { - return { - connectDropTarget: connect.dropTarget(), - isOver: monitor.isOver(), - }; + return { + connectDropTarget: connect.dropTarget(), + isOver: monitor.isOver() + }; } - +/* eslint-disable new-cap */ const wrapper = DragSource('message', source, sourceCollect)(Message); -export default DropTarget(['message', 'message-new'], target, targetCollect)(wrapper); +export default DropTarget(['message', 'message-new'], target, targetCollect)( + wrapper +); +/* eslint-enable new-cap */ diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx index c47cf28a64..78e892baf8 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/MessageNew.jsx @@ -26,82 +26,84 @@ import iconHandle from '../../../../../../../../../../res/ecomp/asdc/sequencer/s * LHS lifeline row view. */ class MessageNew extends React.Component { + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + this.onClickAdd = this.onClickAdd.bind(this); + } - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - this.onClickAdd = this.onClickAdd.bind(this); - } + /** + * Handle add. + */ + onClickAdd() { + this.props.designer.addMessage(); + } - /** - * Handle add. - */ - onClickAdd() { - this.props.designer.addMessage(); - } - - /** - * Render view. - * @returns {*} - */ - render() { - const { connectDragSource } = this.props; - return connectDragSource( - <div className="asdcs-designer-message asdcs-designer-message-new"> - <table className="asdcs-designer-layout asdcs-designer-message-new"> - <tbody> - <tr> - <td> - <div className="asdcs-designer-sort asdcs-designer-icon"> - <Icon glyph={iconHandle} /> - </div> - </td> - <td> - <div className="asdcs-designer-label" onClick={this.onClickAdd}> - Add Message - </div> - </td> - <td> - <div className="asdcs-designer-icon" onClick={this.onClickAdd}> - <Icon glyph={iconPlus} /> - </div> - </td> - <td> - - </td> - </tr> - </tbody> - </table> - </div> - ); - } + /** + * Render view. + * @returns {*} + */ + render() { + const { connectDragSource } = this.props; + return connectDragSource( + <div className="asdcs-designer-message asdcs-designer-message-new"> + <table className="asdcs-designer-layout asdcs-designer-message-new"> + <tbody> + <tr> + <td> + <div className="asdcs-designer-sort asdcs-designer-icon"> + <Icon glyph={iconHandle} /> + </div> + </td> + <td> + <div + className="asdcs-designer-label" + onClick={this.onClickAdd}> + Add Message + </div> + </td> + <td> + <div + className="asdcs-designer-icon" + onClick={this.onClickAdd}> + <Icon glyph={iconPlus} /> + </div> + </td> + <td> </td> + </tr> + </tbody> + </table> + </div> + ); + } } /** Element properties. */ MessageNew.propTypes = { - designer: PropTypes.object.isRequired, - messages: PropTypes.object.isRequired, - connectDragSource: PropTypes.func.isRequired, + designer: PropTypes.object.isRequired, + messages: PropTypes.object.isRequired, + connectDragSource: PropTypes.func.isRequired }; /** DND. */ const source = { - beginDrag(props) { - return { id: props.id }; - }, + beginDrag(props) { + return { id: props.id }; + } }; /** DND. */ const collect = function collection(connect, monitor) { - return { - connectDragSource: connect.dragSource(), - isDragging: monitor.isDragging(), - }; + return { + connectDragSource: connect.dragSource(), + isDragging: monitor.isDragging() + }; }; +/* eslint-disable new-cap */ export default DragSource('message-new', source, collect)(MessageNew); - +/* eslint-enable new-cap */ diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx index 417155498e..6d2b35e41d 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/message/Messages.jsx @@ -28,116 +28,113 @@ import MessageNew from './MessageNew'; * @constructor */ export default class Messages extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + this.state = {}; + this.setHoverIndex = this.setHoverIndex.bind(this); + this.getHoverIndex = this.getHoverIndex.bind(this); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - this.state = { - }; - this.setHoverIndex = this.setHoverIndex.bind(this); - this.getHoverIndex = this.getHoverIndex.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Record last hover index as non-state. - * @param index index. - */ - setHoverIndex(index) { - this.hoverIndex = index; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get last recorded hover index. - * @returns {*} - */ - getHoverIndex() { - return this.hoverIndex; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Handle drop. - * @param dragIndex dragged item index; undefined if new. - * @param hoverIndex drop index. - */ - onDrop(dragIndex, hoverIndex) { - if (hoverIndex >= 0) { - const application = this.props.application; - const model = application.getModel(); - if (Common.isNumber(dragIndex)) { - if (dragIndex !== hoverIndex) { - model.reorderMessages(dragIndex, hoverIndex); - } - } else { - model.addMessage(hoverIndex); - } - this.forceUpdate(); - application.renderDiagram(); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Record last hover index as non-state. + * @param index index. + */ + setHoverIndex(index) { + this.hoverIndex = index; } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render view. - * @returns {*} - */ - render() { - - const model = this.props.application.getModel(); - const diagram = model.unwrap().diagram; - - // Render existing messages. - - const messages = []; - for (const step of diagram.steps) { - const message = step.message; - const from = model.getLifelineById(message.from); - const to = model.getLifelineById(message.to); - messages.push(<Message - key={`m${message.id}`} - application={this.props.application} - designer={this.props.designer} - message={message} - active={this.props.activeMessageId === message.id} - from={from} - to={to} - model={model} - index={messages.length} - messages={this} - />); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get last recorded hover index. + * @returns {*} + */ + getHoverIndex() { + return this.hoverIndex; } - // Render add. + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Handle drop. + * @param dragIndex dragged item index; undefined if new. + * @param hoverIndex drop index. + */ + onDrop(dragIndex, hoverIndex) { + if (hoverIndex >= 0) { + const application = this.props.application; + const model = application.getModel(); + if (Common.isNumber(dragIndex)) { + if (dragIndex !== hoverIndex) { + model.reorderMessages(dragIndex, hoverIndex); + } + } else { + model.addMessage(hoverIndex); + } + this.forceUpdate(); + application.renderDiagram(); + } + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render view. + * @returns {*} + */ + render() { + const model = this.props.application.getModel(); + const diagram = model.unwrap().diagram; + + // Render existing messages. + + const messages = []; + for (const step of diagram.steps) { + const message = step.message; + const from = model.getLifelineById(message.from); + const to = model.getLifelineById(message.to); + messages.push( + <Message + key={`m${message.id}`} + application={this.props.application} + designer={this.props.designer} + message={message} + active={this.props.activeMessageId === message.id} + from={from} + to={to} + model={model} + index={messages.length} + messages={this} + /> + ); + } - messages.push(<MessageNew - key="_m" - designer={this.props.designer} - messages={this} - />); + // Render add. - return ( - <div className="asdcs-designer-steps"> - {messages} - </div> - ); - } + messages.push( + <MessageNew + key="_m" + designer={this.props.designer} + messages={this} + /> + ); + + return <div className="asdcs-designer-steps">{messages}</div>; + } } /** Element properties. */ Messages.propTypes = { - application: PropTypes.object.isRequired, - designer: PropTypes.object.isRequired, - activeMessageId: PropTypes.string, + application: PropTypes.object.isRequired, + designer: PropTypes.object.isRequired, + activeMessageId: PropTypes.string }; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx index cc1faddcba..419c728671 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/designer/components/metadata/Metadata.jsx @@ -20,15 +20,11 @@ import PropTypes from 'prop-types'; * Metadata view. */ const Metadata = function Metadata(props) { - return ( - <div className="asdcs-designer-metadata"> - {props.metadata.name} - </div> - ); + return <div className="asdcs-designer-metadata">{props.metadata.name}</div>; }; Metadata.propTypes = { - metadata: PropTypes.object.isRequired, + metadata: PropTypes.object.isRequired }; export default Metadata; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx index 04ea5280ba..1ba7e9f324 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/source/Source.jsx @@ -20,67 +20,69 @@ import PropTypes from 'prop-types'; * Editor view, aggregating the designer, the code editor, the toolbar. */ export default class Source extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct view. - */ - constructor(props, context) { - super(props, context); - this.demo = this.props.application.getOptions().demo; - } + /** + * Construct view. + */ + constructor(props, context) { + super(props, context); + this.demo = this.props.application.getOptions().demo; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Set JSON mode. - * @param json JSON (stringified) code. - */ - setJSON(json = '') { - if (this.textarea) { - this.textarea.value = json; + /** + * Set JSON mode. + * @param json JSON (stringified) code. + */ + setJSON(json = '') { + if (this.textarea) { + this.textarea.value = json; + } } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Set YAML mode. - * @param yaml YAML code. - */ - setYAML(yaml = '') { - if (this.textarea) { - this.textarea.value = yaml; + /** + * Set YAML mode. + * @param yaml YAML code. + */ + setYAML(yaml = '') { + if (this.textarea) { + this.textarea.value = yaml; + } } - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - componentDidMount() { - /* + componentDidMount() { + /* this.cm = CodeMirror.fromTextArea(this.textarea, { lineNumbers: true, readOnly: true, }); */ - } + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Render to DOM. - */ - render() { - return ( - <div className="asdcs-editor-code"> - <textarea ref={(r) => { this.textarea = r; }}></textarea> - </div> - ); - } + /** + * Render to DOM. + */ + render() { + return ( + <div className="asdcs-editor-code"> + <textarea + ref={r => { + this.textarea = r; + }} + /> + </div> + ); + } } Source.propTypes = { - application: PropTypes.object.isRequired, + application: PropTypes.object.isRequired }; - diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx index 4ac9c3dfad..c32172571d 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/editor/components/toolbar/Toolbar.jsx @@ -26,100 +26,120 @@ import iconOpen from '../../../../../../../../res/ecomp/asdc/sequencer/sprites/i * all you get are the buttons for toggling between JSON/YAML/Designer. */ export default class Toolbar extends React.Component { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct view. + */ + constructor(props, context) { + super(props, context); + this.application = Common.assertType(this.props.application, 'Object'); + this.editor = Common.assertType(this.props.editor, 'Object'); + this.mode = 'design'; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct view. - */ - constructor(props, context) { - super(props, context); - this.application = Common.assertType(this.props.application, 'Object'); - this.editor = Common.assertType(this.props.editor, 'Object'); - this.mode = 'design'; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Set editor mode, one of {design, json, yaml}. - * @param mode - */ - setMode(mode = 'design') { - this.mode = mode; - } + /** + * Set editor mode, one of {design, json, yaml}. + * @param mode + */ + setMode(mode = 'design') { + this.mode = mode; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Render into the DOM. - */ - render() { - - const demo = this.application.getOptions().demo; - const demoCss = demo ? '' : 'asdc-hide'; - - return ( - <div className={`asdcs-editor-toolbar ${demoCss}`}> - <div className="asdcs-editor-toolbar-demo"> - <button className="asdcs-button-new" data-title="New sequence"> - <svg> - <use xlinkHref={iconPlus} className="asdcs-icon" /> - </svg> - </button> - <button className="asdcs-button-open" data-title="Open sequence"> - <svg> - <use xlinkHref={iconOpen} className="asdcs-icon" /> - </svg> - </button> - <button className="asdcs-button-save" data-title="Save checkpoint"> - <svg> - <use xlinkHref="#icon--save" className="asdcs-icon" /> - </svg> - </button> - <button className="asdcs-button-validate" data-title="Validate"> - <svg> - <use xlinkHref="#icon--validate" className="asdcs-icon" /> - </svg> - </button> - <button className="asdcs-button-download" data-title="Download"> - <svg> - <use xlinkHref="#icon--download" className="asdcs-icon" /> - </svg> - </button> - <button className="asdcs-button-upload" data-title="Upload"> - <svg> - <use xlinkHref="#icon--upload" className="asdcs-icon" /> - </svg> - </button> - </div> - <div className="asdcs-editor-toolbar-toggle"> - <button className="asdcs-button-design asdcs-button-mode asdcs-button-toggle-left"> - Design - </button> - <button className="asdcs-button-json asdcs-button-mode asdcs-button-toggle-center"> - JSON - </button> - <button className="asdcs-button-yaml asdcs-button-mode asdcs-button-toggle-right"> - YAML - </button> - </div> - </div> - ); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Render into the DOM. + */ + render() { + const demo = this.application.getOptions().demo; + const demoCss = demo ? '' : 'asdc-hide'; + + return ( + <div className={`asdcs-editor-toolbar ${demoCss}`}> + <div className="asdcs-editor-toolbar-demo"> + <button + className="asdcs-button-new" + data-title="New sequence"> + <svg> + <use xlinkHref={iconPlus} className="asdcs-icon" /> + </svg> + </button> + <button + className="asdcs-button-open" + data-title="Open sequence"> + <svg> + <use xlinkHref={iconOpen} className="asdcs-icon" /> + </svg> + </button> + <button + className="asdcs-button-save" + data-title="Save checkpoint"> + <svg> + <use + xlinkHref="#icon--save" + className="asdcs-icon" + /> + </svg> + </button> + <button + className="asdcs-button-validate" + data-title="Validate"> + <svg> + <use + xlinkHref="#icon--validate" + className="asdcs-icon" + /> + </svg> + </button> + <button + className="asdcs-button-download" + data-title="Download"> + <svg> + <use + xlinkHref="#icon--download" + className="asdcs-icon" + /> + </svg> + </button> + <button className="asdcs-button-upload" data-title="Upload"> + <svg> + <use + xlinkHref="#icon--upload" + className="asdcs-icon" + /> + </svg> + </button> + </div> + <div className="asdcs-editor-toolbar-toggle"> + <button className="asdcs-button-design asdcs-button-mode asdcs-button-toggle-left"> + Design + </button> + <button className="asdcs-button-json asdcs-button-mode asdcs-button-toggle-center"> + JSON + </button> + <button className="asdcs-button-yaml asdcs-button-mode asdcs-button-toggle-right"> + YAML + </button> + </div> + </div> + ); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** * Initialize eventhandlers. * @private * @@ -172,9 +192,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoOpen() { @@ -189,9 +209,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoNew() { @@ -204,9 +224,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoSave() { @@ -217,9 +237,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoUpload() { @@ -241,9 +261,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoDownload() { @@ -256,9 +276,9 @@ export default class Toolbar extends React.Component { } */ - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** + /** * Demo action. * _doDemoValidate() { @@ -270,6 +290,6 @@ export default class Toolbar extends React.Component { } Toolbar.propTypes = { - application: PropTypes.object.isRequired, - editor: PropTypes.object.isRequired, + application: PropTypes.object.isRequired, + editor: PropTypes.object.isRequired }; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx index 529ae92ded..a6cb4abb49 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/export/Export.jsx @@ -17,15 +17,18 @@ import React from 'react'; const Export = function Export() { - return ( - <form className="asdcs-export" action="/ossui-svg/services/ossui/svg/export" method="post"> - <input name="svg" type="hidden" value="" /> - <input name="css" type="hidden" value="sdc/sequencer/default" /> - <input name="type" type="hidden" value="PDF" /> - <input name="height" type="hidden" value="1920" /> - <input name="width" type="hidden" value="1080" /> - </form> - ); + return ( + <form + className="asdcs-export" + action="/ossui-svg/services/ossui/svg/export" + method="post"> + <input name="svg" type="hidden" value="" /> + <input name="css" type="hidden" value="sdc/sequencer/default" /> + <input name="type" type="hidden" value="PDF" /> + <input name="height" type="hidden" value="1920" /> + <input name="width" type="hidden" value="1080" /> + </form> + ); }; export default Export; diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx index 6ed2d451d9..51849676e4 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/icons/Icon.jsx @@ -24,18 +24,17 @@ import PropTypes from 'prop-types'; * @constructor */ const Icon = function Icon({ glyph, className }) { - return ( - <svg viewBox="0 0 1000 1000" className={className} > - <use xlinkHref={glyph} className="asdcs-icon" /> - </svg> - ); + return ( + <svg viewBox="0 0 1000 1000" className={className}> + <use xlinkHref={glyph} className="asdcs-icon" /> + </svg> + ); }; /** Declare properties. */ Icon.propTypes = { - className: PropTypes.string, - glyph: PropTypes.string.isRequired, + className: PropTypes.string, + glyph: PropTypes.string.isRequired }; export default Icon; - diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx index 817f4f1697..7d03b468aa 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/components/overlay/Overlay.jsx @@ -20,42 +20,35 @@ import React from 'react'; * Overlay view. */ export default class Overlay extends React.Component { + /** + * Construct view. + * @param props element properties. + * @param context react context. + */ + constructor(props, context) { + super(props, context); + this.state = { + visible: false + }; + this.setVisible = this.setVisible.bind(this); + } - /** - * Construct view. - * @param props element properties. - * @param context react context. - */ - constructor(props, context) { - super(props, context); - this.state = { - visible: false, - }; - this.setVisible = this.setVisible.bind(this); - } + /** + * Set visibility. + * @param visible true if visible. + */ + setVisible(visible) { + this.setState({ + visible + }); + } - /** - * Set visibility. - * @param visible true if visible. - */ - setVisible(visible) { - this.setState({ - visible, - }); - } - - /** - * Render view. - * @returns {XML} - */ - render() { - const display = this.state.visible ? 'block' : 'none'; - return ( - <div - className="asdcs-overlay" - style={{ display }} - > - </div> - ); - } + /** + * Render view. + * @returns {XML} + */ + render() { + const display = this.state.visible ? 'block' : 'none'; + return <div className="asdcs-overlay" style={{ display }} />; + } } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js index 82e8ada588..140b7ef547 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodel.js @@ -22,73 +22,71 @@ import Common from '../common/Common'; * Rules governing what a definition can contain. */ export default class Metamodel { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct from JSON definition. + * @param json schema definition. + */ + constructor(json) { + Common.assertType(json, 'Object'); + const dfault = require('./templates/default.metamodel.json'); + this.json = _merge({}, dfault, json); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct from JSON definition. - * @param json schema definition. - */ - constructor(json) { - Common.assertType(json, 'Object'); - const dfault = require('./templates/default.metamodel.json'); - this.json = _merge({}, dfault, json); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get schema identifier. - * @returns ID. - */ - getId() { - return this.json.diagram.metadata.id; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Get lifeline constraints. - * @returns {*} - */ - getConstraints() { - return this.json.diagram.lifelines.constraints; - } + /** + * Get schema identifier. + * @returns ID. + */ + getId() { + return this.json.diagram.metadata.id; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Get lifeline metadata by lifeline ID. - * @param id sought lifeline. - * @returns lifeline if found. - */ - getLifelineById(id) { - for (const lifeline of this.json.diagram.lifelines.lifelines) { - if (lifeline.id === id) { - return lifeline; - } + /** + * Get lifeline constraints. + * @returns {*} + */ + getConstraints() { + return this.json.diagram.lifelines.constraints; } - return undefined; - } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get lifeline metadata by lifeline ID. + * @param id sought lifeline. + * @returns lifeline if found. + */ + getLifelineById(id) { + for (const lifeline of this.json.diagram.lifelines.lifelines) { + if (lifeline.id === id) { + return lifeline; + } + } + return undefined; + } - /** - * Get original JSON. - * @returns JSON. - */ - unwrap() { - return this.json; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Get original JSON. + * @returns JSON. + */ + unwrap() { + return this.json; + } - /** - * Get default schema. - * @returns Metamodel default (permissive) Metamodel. - */ - static getDefault() { - return new Metamodel({}); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Get default schema. + * @returns Metamodel default (permissive) Metamodel. + */ + static getDefault() { + return new Metamodel({}); + } } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js index 4ecfc0b5f7..40756a8e09 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Metamodels.js @@ -21,67 +21,64 @@ import Metamodel from './Metamodel'; * A simple lookup for schemas by ID. */ export default class Metamodels { + // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// + /** + * Construct metamodels from provided JSON definitions. + * @param metamodels JSON metamodel definitions. + */ + constructor(metamodels) { + Common.assertType(metamodels, 'Array'); - /** - * Construct metamodels from provided JSON definitions. - * @param metamodels JSON metamodel definitions. - */ - constructor(metamodels) { + this.lookup = {}; - Common.assertType(metamodels, 'Array'); + // Save each metamodel. It's up to the Metamodel class to make sense of + // potentially nonsense metamodel definitions. - this.lookup = {}; + for (const json of metamodels) { + const metamodel = new Metamodel(json); + this.lookup[metamodel.getId()] = metamodel; + } - // Save each metamodel. It's up to the Metamodel class to make sense of - // potentially nonsense metamodel definitions. + // Set (or override) the default metamodel with the inlined one. - for (const json of metamodels) { - const metamodel = new Metamodel(json); - this.lookup[metamodel.getId()] = metamodel; + this.lookup.$ = Metamodel.getDefault(); + Common.assertInstanceOf(this.lookup.$, Metamodel); } - // Set (or override) the default metamodel with the inlined one. + // /////////////////////////////////////////////////////////////////////////////////////////////// - this.lookup.$ = Metamodel.getDefault(); - Common.assertInstanceOf(this.lookup.$, Metamodel); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get Metamodel by its @id. - * @param id identifier. - * @returns Metamodel, or undefined if no matching metamodel found. - */ - getMetamodel(id) { - return this.lookup[id]; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get the default (permissive) metamodel. - * @returns default Metamodel. - */ - getDefault() { - return this.lookup.$; - } + /** + * Get Metamodel by its @id. + * @param id identifier. + * @returns Metamodel, or undefined if no matching metamodel found. + */ + getMetamodel(id) { + return this.lookup[id]; + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// - /** - * Get metamodel by its @id, falling back to the default. - * @param id identifier. - * @returns matching metamodel, or default. - */ - getMetamodelOrDefault(id) { - const metamodel = this.getMetamodel(id); - if (metamodel) { - return metamodel; + /** + * Get the default (permissive) metamodel. + * @returns default Metamodel. + */ + getDefault() { + return this.lookup.$; } - return this.getDefault(); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get metamodel by its @id, falling back to the default. + * @param id identifier. + * @returns matching metamodel, or default. + */ + getMetamodelOrDefault(id) { + const metamodel = this.getMetamodel(id); + if (metamodel) { + return metamodel; + } + return this.getDefault(); + } } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js index 1e68cd6034..3145506268 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/Model.js @@ -24,489 +24,481 @@ import Metamodel from './Metamodel'; * A wrapper for a model instance. */ export default class Model { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct model from model JSON. JSON is assumed to be in more or less + * the correct structure, but it's OK if it's missing IDs. + * + * @param json initial JSON; will be updated in situ. + * @param metamodel Metaobject definition. + */ + constructor(json, metamodel) { + if (metamodel) { + Common.assertInstanceOf(metamodel, Metamodel); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + this.metamodel = metamodel || Metamodel.getDefault(); + Common.assertInstanceOf(this.metamodel, Metamodel); - /** - * Construct model from model JSON. JSON is assumed to be in more or less - * the correct structure, but it's OK if it's missing IDs. - * - * @param json initial JSON; will be updated in situ. - * @param metamodel Metaobject definition. - */ - constructor(json, metamodel) { + this.jsonschema = require('./schema/asdc_sequencer_schema.json'); + this.templates = { + defaultModel: require('./templates/default.model.json'), + defaultMetamodel: require('./templates/default.metamodel.json') + }; - if (metamodel) { - Common.assertInstanceOf(metamodel, Metamodel); - } + this.model = this._preprocess(Common.assertType(json, 'Object')); + Common.assertPlainObject(this.model); - this.metamodel = metamodel || Metamodel.getDefault(); - Common.assertInstanceOf(this.metamodel, Metamodel); - - this.jsonschema = require('./schema/asdc_sequencer_schema.json'); - this.templates = { - defaultModel: require('./templates/default.model.json'), - defaultMetamodel: require('./templates/default.metamodel.json'), - }; - - this.model = this._preprocess(Common.assertType(json, 'Object')); - Common.assertPlainObject(this.model); - - this.renumber(); - - this.addLifeline = this.addLifeline.bind(this); - this.addMessage = this.addMessage.bind(this); - this.renumber = this.renumber.bind(this); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Unwrap to get model object. - * @returns {*} - */ - unwrap() { - return Common.assertPlainObject(this.model); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get the metamodel which defines valid states for this model. - * @returns Metamodel definition. - */ - getMetamodel() { - return Common.assertInstanceOf(this.metamodel, Metamodel); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Find lifeline by its ID. - * @param id lifeline ID. - * @returns lifeline object, if found. - */ - getLifelineById(id) { - for (const lifeline of this.model.diagram.lifelines) { - if (lifeline.id === id) { - return lifeline; - } - } - return undefined; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get message by ID. - * @param id message ID. - * @returns message if matched. - */ - getMessageById(id) { - Common.assertNotNull(id); - const step = this.getStepByMessageId(id); - if (step) { - return step.message; + this.renumber(); + + this.addLifeline = this.addLifeline.bind(this); + this.addMessage = this.addMessage.bind(this); + this.renumber = this.renumber.bind(this); } - return undefined; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get step by message ID. - * @param id step ID. - * @returns step if matched. - */ - getStepByMessageId(id) { - Common.assertNotNull(id); - for (const step of this.model.diagram.steps) { - if (step.message && step.message.id === id) { - return step; - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Unwrap to get model object. + * @returns {*} + */ + unwrap() { + return Common.assertPlainObject(this.model); } - return undefined; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add message to steps. - * @returns {{}} - */ - addMessage(index) { - const d = this.model.diagram; - const step = {}; - step.message = {}; - step.message.id = Model._guid(); - step.message.name = '[Unnamed Message]'; - step.message.type = 'request'; - step.message.from = d.lifelines.length > 0 ? d.lifelines[0].id : -1; - step.message.to = d.lifelines.length > 1 ? d.lifelines[1].id : -1; - if (index >= 0) { - d.steps.splice(index, 0, step); - } else { - d.steps.push(step); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get the metamodel which defines valid states for this model. + * @returns Metamodel definition. + */ + getMetamodel() { + return Common.assertInstanceOf(this.metamodel, Metamodel); } - this.renumber(); - return step; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Delete message with ID. - * @param id to be deleted. - */ - deleteMessageById(id) { - Common.assertNotNull(id); - const step = this.getStepByMessageId(id); - if (step) { - const index = this.model.diagram.steps.indexOf(step); - if (index !== -1) { - this.model.diagram.steps.splice(index, 1); - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Find lifeline by its ID. + * @param id lifeline ID. + * @returns lifeline object, if found. + */ + getLifelineById(id) { + for (const lifeline of this.model.diagram.lifelines) { + if (lifeline.id === id) { + return lifeline; + } + } + return undefined; } - this.renumber(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Add lifeline to lifelines. - * @param index optional index. - * @returns {{}} - */ - addLifeline(index) { - const lifeline = {}; - lifeline.id = Model._guid(); - lifeline.name = '[Unnamed Lifeline]'; - if (index >= 0) { - this.model.diagram.lifelines.splice(index, 0, lifeline); - } else { - this.model.diagram.lifelines.push(lifeline); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get message by ID. + * @param id message ID. + * @returns message if matched. + */ + getMessageById(id) { + Common.assertNotNull(id); + const step = this.getStepByMessageId(id); + if (step) { + return step.message; + } + return undefined; } - this.renumber(); - return lifeline; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Delete lifeline with ID. - * @param id to be deleted. - */ - deleteLifelineById(id) { - Common.assertNotNull(id); - this.deleteStepsByLifelineId(id); - const lifeline = this.getLifelineById(id); - if (lifeline) { - const index = this.model.diagram.lifelines.indexOf(lifeline); - if (index !== -1) { - this.model.diagram.lifelines.splice(index, 1); - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get step by message ID. + * @param id step ID. + * @returns step if matched. + */ + getStepByMessageId(id) { + Common.assertNotNull(id); + for (const step of this.model.diagram.steps) { + if (step.message && step.message.id === id) { + return step; + } + } + return undefined; } - this.renumber(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Delete all steps corresponding to lifeline. - * @param id lifeline ID. - */ - deleteStepsByLifelineId(id) { - Common.assertNotNull(id); - const steps = this.getStepsByLifelineId(id); - for (const step of steps) { - this.deleteMessageById(step.message.id); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Add message to steps. + * @returns {{}} + */ + addMessage(index) { + const d = this.model.diagram; + const step = {}; + step.message = {}; + step.message.id = Model._guid(); + step.message.name = '[Unnamed Message]'; + step.message.type = 'request'; + step.message.from = d.lifelines.length > 0 ? d.lifelines[0].id : -1; + step.message.to = d.lifelines.length > 1 ? d.lifelines[1].id : -1; + if (index >= 0) { + d.steps.splice(index, 0, step); + } else { + d.steps.push(step); + } + this.renumber(); + return step; } - this.renumber(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get all steps corresponding to lifeline. - * @param id lifeline ID. - * @return steps from/to lifeline. - */ - getStepsByLifelineId(id) { - Common.assertNotNull(id); - const steps = []; - for (const step of this.model.diagram.steps) { - if (step.message) { - if (step.message.from === id || step.message.to === id) { - steps.push(step); + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Delete message with ID. + * @param id to be deleted. + */ + deleteMessageById(id) { + Common.assertNotNull(id); + const step = this.getStepByMessageId(id); + if (step) { + const index = this.model.diagram.steps.indexOf(step); + if (index !== -1) { + this.model.diagram.steps.splice(index, 1); + } } - } + this.renumber(); } - return steps; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Validate model. Disabled, because we removed the jsonschema dependency. - * @returns {Array} of validation errors, if any. - */ - validate() { - const errors = []; - return errors; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Reorder messages. - * @param index message index. - * @param afterIndex new (after) index. - */ - reorderMessages(index, afterIndex) { - Common.assertType(index, 'Number'); - Common.assertType(afterIndex, 'Number'); - const steps = this.model.diagram.steps; - const element = steps[index]; - steps.splice(index, 1); - steps.splice(afterIndex, 0, element); - this.renumber(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Reorder lifelines. - * @param index lifeline index. - * @param afterIndex new (after) index. - */ - reorderLifelines(index, afterIndex) { - Common.assertType(index, 'Number'); - Common.assertType(afterIndex, 'Number'); - const lifelines = this.model.diagram.lifelines; - const element = lifelines[index]; - lifelines.splice(index, 1); - lifelines.splice(afterIndex, 0, element); - this.renumber(); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Renumber lifelines and messages. - */ - renumber() { - const modelJSON = this.unwrap(); - let stepIndex = 1; - let lifelineIndex = 1; - for (const step of modelJSON.diagram.steps) { - if (step.message) { - step.message.index = stepIndex++; - } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Add lifeline to lifelines. + * @param index optional index. + * @returns {{}} + */ + addLifeline(index) { + const lifeline = {}; + lifeline.id = Model._guid(); + lifeline.name = '[Unnamed Lifeline]'; + if (index >= 0) { + this.model.diagram.lifelines.splice(index, 0, lifeline); + } else { + this.model.diagram.lifelines.push(lifeline); + } + this.renumber(); + return lifeline; } - for (const lifeline of modelJSON.diagram.lifelines) { - lifeline.index = lifelineIndex++; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Delete lifeline with ID. + * @param id to be deleted. + */ + deleteLifelineById(id) { + Common.assertNotNull(id); + this.deleteStepsByLifelineId(id); + const lifeline = this.getLifelineById(id); + if (lifeline) { + const index = this.model.diagram.lifelines.indexOf(lifeline); + if (index !== -1) { + this.model.diagram.lifelines.splice(index, 1); + } + } + this.renumber(); } - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Build a simple, navigable dataset describing fragments. - * @returns {{}}, indexed by (stop) message ID, describing fragments. - */ - analyzeFragments() { - - const fData = {}; - - let depth = 0; - const modelJSON = this.unwrap(); - const open = []; - - const getData = function g(stop, fragment) { - let data = fData[stop]; - if (!data) { - data = { stop, start: [], fragment }; - fData[stop] = data; - } - return data; - }; - - const fragmentsByStart = {}; - for (const step of modelJSON.diagram.steps) { - if (step.message && step.message.fragment) { - const message = step.message; - const fragment = message.fragment; - if (fragment.start) { - fragmentsByStart[fragment.start] = fragment; - open.push(message.id); - depth++; + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Delete all steps corresponding to lifeline. + * @param id lifeline ID. + */ + deleteStepsByLifelineId(id) { + Common.assertNotNull(id); + const steps = this.getStepsByLifelineId(id); + for (const step of steps) { + this.deleteMessageById(step.message.id); } - if (fragment.stop) { - if (open.length > 0) { - getData(message.id).start.push(open.pop()); - } - depth = Math.max(depth - 1, 0); + this.renumber(); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get all steps corresponding to lifeline. + * @param id lifeline ID. + * @return steps from/to lifeline. + */ + getStepsByLifelineId(id) { + Common.assertNotNull(id); + const steps = []; + for (const step of this.model.diagram.steps) { + if (step.message) { + if (step.message.from === id || step.message.to === id) { + steps.push(step); + } + } } - } + return steps; } - if (open.length > 0) { - for (const o of open) { - getData(o, fragmentsByStart[o]).start.push(o); - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Validate model. Disabled, because we removed the jsonschema dependency. + * @returns {Array} of validation errors, if any. + */ + validate() { + const errors = []; + return errors; } - return fData; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Reorder messages. + * @param index message index. + * @param afterIndex new (after) index. + */ + reorderMessages(index, afterIndex) { + Common.assertType(index, 'Number'); + Common.assertType(afterIndex, 'Number'); + const steps = this.model.diagram.steps; + const element = steps[index]; + steps.splice(index, 1); + steps.splice(afterIndex, 0, element); + this.renumber(); + } - // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Reorder lifelines. + * @param index lifeline index. + * @param afterIndex new (after) index. + */ + reorderLifelines(index, afterIndex) { + Common.assertType(index, 'Number'); + Common.assertType(afterIndex, 'Number'); + const lifelines = this.model.diagram.lifelines; + const element = lifelines[index]; + lifelines.splice(index, 1); + lifelines.splice(afterIndex, 0, element); + this.renumber(); + } - /** - * Build a simple, navigable dataset describing occurrences. - * @returns a map, indexed by lifeline ID, of objects containing {start:[],stop:[],active[]}. - * @private - */ - analyzeOccurrences() { + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Renumber lifelines and messages. + */ + renumber() { + const modelJSON = this.unwrap(); + let stepIndex = 1; + let lifelineIndex = 1; + for (const step of modelJSON.diagram.steps) { + if (step.message) { + step.message.index = stepIndex++; + } + } + for (const lifeline of modelJSON.diagram.lifelines) { + lifeline.index = lifelineIndex++; + } + } - const oData = {}; + // /////////////////////////////////////////////////////////////////////////////////////////////// - // A few inline functions. They make this method kinda lengthy, but they - // reduce clutter in the class and keep it coherent, so it's OK. + /** + * Build a simple, navigable dataset describing fragments. + * @returns {{}}, indexed by (stop) message ID, describing fragments. + */ + analyzeFragments() { + const fData = {}; - const getDataByLifelineId = function get(lifelineId) { - if (!oData[lifelineId]) { - oData[lifelineId] = { active: [], start: {}, stop: {} }; - } - return oData[lifelineId]; - }; + let depth = 0; + const modelJSON = this.unwrap(); + const open = []; - const contains = function contains(array, value) { - return (array && (array.indexOf(value) !== -1)); - }; + const getData = function g(stop, fragment) { + let data = fData[stop]; + if (!data) { + data = { stop, start: [], fragment }; + fData[stop] = data; + } + return data; + }; + + const fragmentsByStart = {}; + for (const step of modelJSON.diagram.steps) { + if (step.message && step.message.fragment) { + const message = step.message; + const fragment = message.fragment; + if (fragment.start) { + fragmentsByStart[fragment.start] = fragment; + open.push(message.id); + depth++; + } + if (fragment.stop) { + if (open.length > 0) { + getData(message.id).start.push(open.pop()); + } + depth = Math.max(depth - 1, 0); + } + } + } - const process = function process(message, lifelineId) { - const oRule = message.occurrences; - if (oRule) { + if (open.length > 0) { + for (const o of open) { + getData(o, fragmentsByStart[o]).start.push(o); + } + } - const oDataLifeline = getDataByLifelineId(lifelineId); - if (oDataLifeline) { + return fData; + } - // Record all starts. + // /////////////////////////////////////////////////////////////////////////////////////////////// - if (contains(oRule.start, lifelineId)) { - oDataLifeline.active.push(message.id); - oDataLifeline.start[message.id] = undefined; - } + /** + * Build a simple, navigable dataset describing occurrences. + * @returns a map, indexed by lifeline ID, of objects containing {start:[],stop:[],active[]}. + * @private + */ + analyzeOccurrences() { + const oData = {}; - // Reconcile with stops. + // A few inline functions. They make this method kinda lengthy, but they + // reduce clutter in the class and keep it coherent, so it's OK. - if (contains(oRule.stop, lifelineId)) { - const startMessageId = oDataLifeline.active.pop(); - oDataLifeline.stop[message.id] = startMessageId; - if (startMessageId) { - oDataLifeline.start[startMessageId] = message.id; + const getDataByLifelineId = function get(lifelineId) { + if (!oData[lifelineId]) { + oData[lifelineId] = { active: [], start: {}, stop: {} }; + } + return oData[lifelineId]; + }; + + const contains = function contains(array, value) { + return array && array.indexOf(value) !== -1; + }; + + const process = function process(message, lifelineId) { + const oRule = message.occurrences; + if (oRule) { + const oDataLifeline = getDataByLifelineId(lifelineId); + if (oDataLifeline) { + // Record all starts. + + if (contains(oRule.start, lifelineId)) { + oDataLifeline.active.push(message.id); + oDataLifeline.start[message.id] = undefined; + } + + // Reconcile with stops. + + if (contains(oRule.stop, lifelineId)) { + const startMessageId = oDataLifeline.active.pop(); + oDataLifeline.stop[message.id] = startMessageId; + if (startMessageId) { + oDataLifeline.start[startMessageId] = message.id; + } + } + } + } + }; + + // Analyze start and end. + + const modelJSON = this.unwrap(); + for (const step of modelJSON.diagram.steps) { + if (step.message) { + const message = step.message; + if (message.occurrences) { + process(message, message.from); + process(message, message.to); + } } - } } - } - }; - - // Analyze start and end. - - const modelJSON = this.unwrap(); - for (const step of modelJSON.diagram.steps) { - if (step.message) { - const message = step.message; - if (message.occurrences) { - process(message, message.from); - process(message, message.to); + + // Reset active. (We used it, but it's not actually for us; it's for keeping + // track of active occurrences when rendering the diagram.) + + for (const lifelineId of Object.keys(oData)) { + oData[lifelineId].active = []; } - } - } - // Reset active. (We used it, but it's not actually for us; it's for keeping - // track of active occurrences when rendering the diagram.) + // Reconcile the start and end (message ID) maps for each lifeline, + // finding a "stop" for every start. Default to starting and stopping + // on the same message, which is the same as no occurrence. + + for (const lifelineId of Object.keys(oData)) { + const lifelineData = oData[lifelineId]; + for (const startId of Object.keys(lifelineData.start)) { + const stopId = lifelineData.start[startId]; + if (!stopId) { + lifelineData.start[startId] = startId; + lifelineData.stop[startId] = startId; + } + } + } - for (const lifelineId of Object.keys(oData)) { - oData[lifelineId].active = []; + return oData; } - // Reconcile the start and end (message ID) maps for each lifeline, - // finding a "stop" for every start. Default to starting and stopping - // on the same message, which is the same as no occurrence. - - for (const lifelineId of Object.keys(oData)) { - const lifelineData = oData[lifelineId]; - for (const startId of Object.keys(lifelineData.start)) { - const stopId = lifelineData.start[startId]; - if (!stopId) { - lifelineData.start[startId] = startId; - lifelineData.stop[startId] = startId; + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Preprocess model, adding IDs and whatnot. + * @param original to be preprocessed. + * @returns preprocessed JSON. + * @private + */ + _preprocess(original) { + const json = _merge({}, this.templates.defaultModel, original); + const metamodel = this.metamodel.unwrap(); + if (!json.diagram.metadata.ref) { + if (metamodel.diagram.metadata.id) { + json.diagram.metadata.ref = metamodel.diagram.metadata.id; + } else { + json.diagram.metadata.ref = '$'; + } } - } - } - return oData; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Preprocess model, adding IDs and whatnot. - * @param original to be preprocessed. - * @returns preprocessed JSON. - * @private - */ - _preprocess(original) { - - const json = _merge({}, this.templates.defaultModel, original); - const metamodel = this.metamodel.unwrap(); - if (!json.diagram.metadata.ref) { - if (metamodel.diagram.metadata.id) { - json.diagram.metadata.ref = metamodel.diagram.metadata.id; - } else { - json.diagram.metadata.ref = '$'; - } - } + for (const lifeline of json.diagram.lifelines) { + lifeline.id = lifeline.id || lifeline.name; + } - for (const lifeline of json.diagram.lifelines) { - lifeline.id = lifeline.id || lifeline.name; - } + for (const step of json.diagram.steps) { + if (step.message) { + step.message.id = step.message.id || Model._guid(); + const occurrences = step.message.occurrences; + if (occurrences) { + occurrences.start = occurrences.start || []; + occurrences.stop = occurrences.stop || []; + } + } + } - for (const step of json.diagram.steps) { - if (step.message) { - step.message.id = step.message.id || Model._guid(); - const occurrences = step.message.occurrences; - if (occurrences) { - occurrences.start = occurrences.start || []; - occurrences.stop = occurrences.stop || []; + if (!json.diagram.metadata.id || json.diagram.metadata.id === '$') { + json.diagram.metadata.id = Model._guid(); } - } - } - if (!json.diagram.metadata.id || json.diagram.metadata.id === '$') { - json.diagram.metadata.id = Model._guid(); + return json; } - return json; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Create pseudo-UUID. - * @returns {string} - * @private - */ - static _guid() { - function s4() { - return Math.floor((1 + Math.random()) * 0x10000) - .toString(16) - .substring(1); + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Create pseudo-UUID. + * @returns {string} + * @private + */ + static _guid() { + function s4() { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + } + return `${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}`; } - return `${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}-${s4()}`; - } - } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js index 4130ec7ec3..74707d472c 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/ecomp/asdc/sequencer/model/demo/scenarios/Scenarios.js @@ -18,93 +18,96 @@ * Example scenarios, for development, testing and demos. */ export default class Scenarios { - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Construct scenarios; read model and metamodel templates. - */ - constructor() { - this.templates = { - model: { - ecomp: require('./model/ECOMP.json'), - blank: require('./model/BLANK.json'), - dimensions: require('./model/DIMENSIONS.json'), - }, - metamodel: { - ecomp: require('./metamodel/ECOMP.json'), - blank: require('./metamodel/BLANK.json'), - }, - }; - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get ECOMP scenario. - * @return ECOMP scenario JSON. - */ - getECOMP() { - return JSON.parse(JSON.stringify(this.templates.model.ecomp)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get ECOMP scenario metamodel. - * @return scenario metamodel JSON. - */ - getECOMPMetamodel() { - return JSON.parse(JSON.stringify(this.templates.metamodel.ecomp)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get blank scenario. - * @return blank scenario JSON. - */ - getBlank() { - return JSON.parse(JSON.stringify(this.templates.model.blank)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get empty scenario metamodel. - * @return empty metamodel JSON. - */ - getBlankMetamodel() { - return JSON.parse(JSON.stringify(this.templates.metamodel.blank)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get scenario. - * @return scenario JSON. - */ - getDimensions() { - return JSON.parse(JSON.stringify(this.templates.model.dimensions)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get scenario metamodel. - * @return metamodel JSON. - */ - getDimensionsMetamodel() { - return JSON.parse(JSON.stringify(this.templates.metamodel.blank)); - } - - // /////////////////////////////////////////////////////////////////////////////////////////////// - - /** - * Get demo metamodels. - * @returns {*[]} - */ - getMetamodels() { - return [this.getBlankMetamodel(), this.getDimensionsMetamodel(), this.getECOMPMetamodel()]; - } + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Construct scenarios; read model and metamodel templates. + */ + constructor() { + this.templates = { + model: { + ecomp: require('./model/ECOMP.json'), + blank: require('./model/BLANK.json'), + dimensions: require('./model/DIMENSIONS.json') + }, + metamodel: { + ecomp: require('./metamodel/ECOMP.json'), + blank: require('./metamodel/BLANK.json') + } + }; + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get ECOMP scenario. + * @return ECOMP scenario JSON. + */ + getECOMP() { + return JSON.parse(JSON.stringify(this.templates.model.ecomp)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get ECOMP scenario metamodel. + * @return scenario metamodel JSON. + */ + getECOMPMetamodel() { + return JSON.parse(JSON.stringify(this.templates.metamodel.ecomp)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get blank scenario. + * @return blank scenario JSON. + */ + getBlank() { + return JSON.parse(JSON.stringify(this.templates.model.blank)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get empty scenario metamodel. + * @return empty metamodel JSON. + */ + getBlankMetamodel() { + return JSON.parse(JSON.stringify(this.templates.metamodel.blank)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get scenario. + * @return scenario JSON. + */ + getDimensions() { + return JSON.parse(JSON.stringify(this.templates.model.dimensions)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get scenario metamodel. + * @return metamodel JSON. + */ + getDimensionsMetamodel() { + return JSON.parse(JSON.stringify(this.templates.metamodel.blank)); + } + + // /////////////////////////////////////////////////////////////////////////////////////////////// + + /** + * Get demo metamodels. + * @returns {*[]} + */ + getMetamodels() { + return [ + this.getBlankMetamodel(), + this.getDimensionsMetamodel(), + this.getECOMPMetamodel() + ]; + } } diff --git a/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx b/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx index 4b0f7d2388..1c783cb890 100644 --- a/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx +++ b/dox-sequence-diagram-ui/src/main/webapp/lib/main.jsx @@ -21,15 +21,15 @@ import '../res/ecomp/asdc/sequencer/sequencer-development.scss'; import '../res/thirdparty/react-select/react-select.min.css'; function renderApplication() { - const shell = document.createElement('div'); - shell.setAttribute('style', 'height:100%;width:100%;margin:0;padding:0'); - document.body.appendChild(shell); - const options = { demo: true }; - render(<Sequencer options={options} />, shell); + const shell = document.createElement('div'); + shell.setAttribute('style', 'height:100%;width:100%;margin:0;padding:0'); + document.body.appendChild(shell); + const options = { demo: true }; + render(<Sequencer options={options} />, shell); } if (window.addEventListener) { - window.addEventListener('DOMContentLoaded', renderApplication); + window.addEventListener('DOMContentLoaded', renderApplication); } else { - window.attachEvent('onload', renderApplication); + window.attachEvent('onload', renderApplication); } diff --git a/dox-sequence-diagram-ui/yarn.lock b/dox-sequence-diagram-ui/yarn.lock index 4f3cc76a00..043f65b66b 100644 --- a/dox-sequence-diagram-ui/yarn.lock +++ b/dox-sequence-diagram-ui/yarn.lock @@ -85,14 +85,22 @@ acorn@^4.0.3: version "4.0.13" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" -acorn@^5.0.0, acorn@^5.2.1: +acorn@^5.0.0: version "5.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" -ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: +acorn@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.0.tgz#1abb587fbf051f94e3de20e6b26ef910b1828298" + +ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" +ajv-keywords@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -100,7 +108,7 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.1.0: +ajv@^5.0.0, ajv@^5.1.0, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -109,6 +117,14 @@ ajv@^5.0.0, ajv@^5.1.0: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.2.0.tgz#afac295bbaa0152449e522742e4547c1ae9328d2" + dependencies: + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -125,9 +141,9 @@ amdefine@>=0.0.4: version "1.0.1" resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" +ansi-escapes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" ansi-green@^0.1.1: version "0.1.1" @@ -151,7 +167,7 @@ ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -ansi-styles@^3.1.0: +ansi-styles@^3.1.0, ansi-styles@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.0.tgz#c159b8d5be0f9e5a6f346dab94f16ce022161b88" dependencies: @@ -338,7 +354,7 @@ aws4@^1.2.1, aws4@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" -babel-code-frame@^6.26.0: +babel-code-frame@^6.22.0, babel-code-frame@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.26.0.tgz#63fd43f7dc1e3bb7ce35947db8fe369a3f58c74b" dependencies: @@ -1220,7 +1236,7 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: +chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" dependencies: @@ -1238,6 +1254,18 @@ chalk@^2.0.0, chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chalk@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" + dependencies: + ansi-styles "^3.2.0" + escape-string-regexp "^1.0.5" + supports-color "^5.2.0" + +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + cheerio@^0.19.0: version "0.19.0" resolved "https://registry.yarnpkg.com/cheerio/-/cheerio-0.19.0.tgz#772e7015f2ee29965096d71ea4175b75ab354925" @@ -1310,11 +1338,11 @@ classnames@^2.2.4: version "2.2.5" resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.5.tgz#fb3801d453467649ef3603c7d61a02bd129bde6d" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: - restore-cursor "^1.0.1" + restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" @@ -1450,7 +1478,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6: +concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -1576,6 +1604,14 @@ cross-spawn@^3.0.0: lru-cache "^4.0.1" which "^1.2.9" +cross-spawn@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" + dependencies: + lru-cache "^4.0.1" + shebang-command "^1.2.0" + which "^1.2.9" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -1916,16 +1952,6 @@ d3@^4.10.0: d3-voronoi "1.1.2" d3-zoom "1.7.1" -d@1: - version "1.0.0" - resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" - dependencies: - es5-ext "^0.10.9" - -damerau-levenshtein@^1.0.0: - version "1.0.4" - resolved "https://registry.yarnpkg.com/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz#03191c432cb6eea168bb77f3a55ffdccb8978514" - dashdash@^1.12.0: version "1.14.1" resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" @@ -1936,7 +1962,7 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: @@ -2093,19 +2119,18 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@1.3.x: - version "1.3.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.3.0.tgz#13e75682b55518424276f7c173783456ef913d26" +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^1.2.2: - version "1.5.0" - resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" +doctrine@^2.0.2, doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: esutils "^2.0.2" - isarray "^1.0.0" dom-serializer@0, dom-serializer@~0.1.0: version "0.1.0" @@ -2232,58 +2257,6 @@ es-to-primitive@^1.1.1: is-date-object "^1.0.1" is-symbol "^1.0.1" -es5-ext@^0.10.14, es5-ext@^0.10.35, es5-ext@^0.10.9, es5-ext@~0.10.14: - version "0.10.38" - resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.38.tgz#fa7d40d65bbc9bb8a67e1d3f9cc656a00530eed3" - dependencies: - es6-iterator "~2.0.3" - es6-symbol "~3.1.1" - -es6-iterator@^2.0.1, es6-iterator@~2.0.1, es6-iterator@~2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.3.tgz#a7de889141a05a94b0854403b2d0a0fbfa98f3b7" - dependencies: - d "1" - es5-ext "^0.10.35" - es6-symbol "^3.1.1" - -es6-map@^0.1.3: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-set "~0.1.5" - es6-symbol "~3.1.1" - event-emitter "~0.3.5" - -es6-set@^0.1.4, es6-set@~0.1.5: - version "0.1.5" - resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" - dependencies: - d "1" - es5-ext "~0.10.14" - es6-iterator "~2.0.1" - es6-symbol "3.1.1" - event-emitter "~0.3.5" - -es6-symbol@3.1.1, es6-symbol@^3.1.1, es6-symbol@~3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" - dependencies: - d "1" - es5-ext "~0.10.14" - -es6-weak-map@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" - dependencies: - d "1" - es5-ext "^0.10.14" - es6-iterator "^2.0.1" - es6-symbol "^3.1.1" - escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -2292,34 +2265,20 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escope@^3.6.0: - version "3.6.0" - resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" - dependencies: - es6-map "^0.1.3" - es6-weak-map "^2.0.1" - esrecurse "^4.1.0" - estraverse "^4.1.1" - -eslint-config-airbnb-base@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-3.0.1.tgz#b777e01f65e946933442b499fc8518aa251a6530" - -eslint-config-airbnb@^9.0.1: - version "9.0.1" - resolved "https://registry.yarnpkg.com/eslint-config-airbnb/-/eslint-config-airbnb-9.0.1.tgz#6708170d5034b579d52913fe49dee2f7fec7d894" +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" dependencies: - eslint-config-airbnb-base "^3.0.0" + get-stdin "^5.0.1" -eslint-import-resolver-node@^0.2.0: - version "0.2.3" - resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" dependencies: - debug "^2.2.0" - object-assign "^4.0.1" - resolve "^1.1.6" + debug "^2.6.9" + resolve "^1.5.0" -eslint-loader@^1.3.0: +eslint-loader@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.9.0.tgz#7e1be9feddca328d3dcfaef1ad49d5beffe83a13" dependencies: @@ -2329,43 +2288,45 @@ eslint-loader@^1.3.0: object-hash "^1.1.4" rimraf "^2.6.1" -eslint-plugin-import@^1.8.0: - version "1.16.0" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-1.16.0.tgz#b2fa07ebcc53504d0f2a4477582ec8bff1871b9f" +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" + dependencies: + debug "^2.6.8" + pkg-dir "^1.0.0" + +eslint-plugin-import@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" dependencies: builtin-modules "^1.1.1" contains-path "^0.1.0" - debug "^2.2.0" - doctrine "1.3.x" - es6-map "^0.1.3" - es6-set "^0.1.4" - eslint-import-resolver-node "^0.2.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" has "^1.0.1" - lodash.cond "^4.3.0" - lodash.endswith "^4.0.1" - lodash.find "^4.3.0" - lodash.findindex "^4.3.0" + lodash "^4.17.4" minimatch "^3.0.3" - object-assign "^4.0.1" - pkg-dir "^1.0.0" - pkg-up "^1.0.0" + read-pkg-up "^2.0.0" -eslint-plugin-jsx-a11y@^1.2.2: - version "1.5.5" - resolved "https://registry.yarnpkg.com/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-1.5.5.tgz#da284a016c1889e73698180217e2eb988a98bab5" +eslint-plugin-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: - damerau-levenshtein "^1.0.0" - jsx-ast-utils "^1.0.0" - object-assign "^4.0.1" + fast-diff "^1.1.1" + jest-docblock "^21.0.0" -eslint-plugin-react@^5.1.1: - version "5.2.2" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-5.2.2.tgz#7db068e1f5487f6871e4deef36a381c303eac161" +eslint-plugin-react@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" dependencies: - doctrine "^1.2.2" - jsx-ast-utils "^1.2.1" + doctrine "^2.0.2" + has "^1.0.1" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.0" -eslint-scope@~3.7.1: +eslint-scope@^3.7.1, eslint-scope@~3.7.1: version "3.7.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" dependencies: @@ -2376,49 +2337,53 @@ eslint-visitor-keys@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" -eslint@^2.10.2: - version "2.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" +eslint@^4.18.1: + version "4.18.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.1.tgz#b9138440cb1e98b2f44a0d578c6ecf8eae6150b0" dependencies: - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - es6-map "^0.1.3" - escope "^3.6.0" - espree "^3.1.6" - estraverse "^4.2.0" + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.2" + esquery "^1.0.0" esutils "^2.0.2" - file-entry-cache "^1.1.1" - glob "^7.0.3" - globals "^9.2.0" - ignore "^3.1.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - optionator "^0.8.1" - path-is-absolute "^1.0.0" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.6.0" - strip-json-comments "~1.0.1" - table "^3.7.8" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "^4.0.1" text-table "~0.2.0" - user-home "^2.0.0" -espree@^3.1.6: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" +espree@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.3.tgz#931e0af64e7fbbed26b050a29daad1fc64799fa6" dependencies: - acorn "^5.2.1" + acorn "^5.4.0" acorn-jsx "^3.0.0" esprima@^2.6.0: @@ -2429,6 +2394,12 @@ esprima@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + esrecurse@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" @@ -2436,7 +2407,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -2448,13 +2419,6 @@ etag@~1.8.1: version "1.8.1" resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" -event-emitter@~0.3.5: - version "0.3.5" - resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" - dependencies: - d "1" - es5-ext "~0.10.14" - eventemitter3@1.x.x: version "1.2.0" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" @@ -2476,10 +2440,6 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: md5.js "^1.3.4" safe-buffer "^5.1.1" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -2562,6 +2522,14 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +external-editor@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -2593,6 +2561,10 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-diff@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -2629,12 +2601,11 @@ fbjs@^0.8.16, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" - object-assign "^4.1.0" file-contents@^0.2.4: version "0.2.4" @@ -2665,9 +2636,9 @@ file-contents@^0.3.1: through2 "^2.0.1" vinyl "^1.1.1" -file-entry-cache@^1.1.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -2754,7 +2725,7 @@ find-up@^1.0.0: path-exists "^2.0.0" pinkie-promise "^2.0.0" -find-up@^2.1.0: +find-up@^2.0.0, find-up@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" dependencies: @@ -2867,6 +2838,10 @@ function-bind@^1.0.2, function-bind@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + gauge@~2.7.3: version "2.7.4" resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" @@ -2904,6 +2879,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" @@ -2944,7 +2923,7 @@ glob@^6.0.4: once "^1.3.0" path-is-absolute "^1.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.1, glob@^7.1.2, glob@~7.1.1: version "7.1.2" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" dependencies: @@ -2971,11 +2950,15 @@ global-prefix@^0.1.4: is-windows "^0.2.0" which "^1.2.12" +globals@^11.0.1: + version "11.3.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0" + globals@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globals/-/globals-11.1.0.tgz#632644457f5f0e3ae711807183700ebf2e4633e4" -globals@^9.18.0, globals@^9.2.0: +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -3061,6 +3044,10 @@ has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + has-glob@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-0.1.1.tgz#a261c4c2a6c667e0c77b700a7f297c39ef3aa589" @@ -3259,7 +3246,7 @@ https-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" -iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@~0.4.13: +iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -3277,7 +3264,7 @@ ieee754@^1.1.4: version "1.1.8" resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" -ignore@^3.1.2: +ignore@^3.3.3: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -3333,22 +3320,23 @@ ini@^1.3.4, ini@~1.3.0: version "1.3.5" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" internal-ip@1.2.0: @@ -3513,7 +3501,7 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: +is-my-json-valid@^2.12.4: version "2.17.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" dependencies: @@ -3574,6 +3562,10 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -3655,6 +3647,10 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +jest-docblock@^21.0.0: + version "21.2.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" + js-base64@^2.1.8, js-base64@^2.1.9: version "2.4.2" resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.4.2.tgz#1896da010ef8862f385d8887648e9b6dc4a7a2e9" @@ -3663,7 +3659,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.5.1: +js-yaml@^3.9.1: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: @@ -3701,7 +3697,11 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: @@ -3736,9 +3736,11 @@ jsprim@^1.2.2: json-schema "0.2.3" verror "1.10.0" -jsx-ast-utils@^1.0.0, jsx-ast-utils@^1.2.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.4.1.tgz#3867213e8dd79bf1e8f2300c0cfc1efb182c0df1" +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" killable@^1.0.0: version "1.0.0" @@ -3807,6 +3809,15 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + loader-fs-cache@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" @@ -3862,22 +3873,6 @@ lodash.clonedeep@^4.3.2: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" -lodash.cond@^4.3.0: - version "4.5.2" - resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" - -lodash.endswith@^4.0.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/lodash.endswith/-/lodash.endswith-4.2.1.tgz#fed59ac1738ed3e236edd7064ec456448b37bc09" - -lodash.find@^4.3.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.find/-/lodash.find-4.6.0.tgz#cb0704d47ab71789ffa0de8b97dd926fb88b13b1" - -lodash.findindex@^4.3.0: - version "4.6.0" - resolved "https://registry.yarnpkg.com/lodash.findindex/-/lodash.findindex-4.6.0.tgz#a3245dee61fb9b6e0624b535125624bb69c11106" - lodash.memoize@^4.1.2: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -4085,6 +4080,10 @@ mime@^1.4.1, mime@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" +mimic-fn@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" + minimalistic-assert@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" @@ -4142,9 +4141,9 @@ multicast-dns@^6.0.1: dns-packet "^1.0.1" thunky "^0.1.0" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" +mute-stream@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" nan@^2.3.0, nan@^2.3.2: version "2.8.0" @@ -4166,6 +4165,10 @@ nanomatch@^1.2.5: snapdragon "^0.8.1" to-regex "^3.0.1" +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + negotiator@0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" @@ -4394,9 +4397,11 @@ once@^1.3.0, once@^1.3.3: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" opn@^5.1.0: version "5.2.0" @@ -4404,7 +4409,7 @@ opn@^5.1.0: dependencies: is-wsl "^1.1.0" -optionator@^0.8.1: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -4435,7 +4440,7 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -4529,7 +4534,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -4549,6 +4554,12 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + path@^0.12.7: version "0.12.7" resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" @@ -4604,15 +4615,9 @@ pkg-dir@^2.0.0: dependencies: find-up "^2.1.0" -pkg-up@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" - dependencies: - find-up "^1.0.0" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" portfinder@^1.0.9: version "1.0.13" @@ -4884,6 +4889,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@^1.10.2: + version "1.11.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.11.0.tgz#c024f70cab158c993f50fc0c25ffe738cb8b0f85" + private@^0.1.6, private@^0.1.7: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -4896,9 +4905,9 @@ process@^0.11.1, process@^0.11.10: version "0.11.10" resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise@^7.1.1: version "7.3.1" @@ -5100,6 +5109,13 @@ read-pkg-up@^1.0.1: find-up "^1.0.0" read-pkg "^1.0.0" +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + read-pkg@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" @@ -5108,6 +5124,14 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + readable-stream@1.1: version "1.1.13" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e" @@ -5138,14 +5162,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - redent@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" @@ -5358,7 +5374,7 @@ require-package-name@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9" -require-uncached@^1.0.2: +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: @@ -5394,18 +5410,18 @@ resolve-url@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" -resolve@^1.1.6: +resolve@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" + onetime "^2.0.0" + signal-exit "^3.0.2" right-align@^0.1.1: version "0.1.3" @@ -5426,19 +5442,25 @@ ripemd160@^2.0.0, ripemd160@^2.0.1: hash-base "^2.0.0" inherits "^2.0.1" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: - once "^1.3.0" + is-promise "^2.1.0" rw@1: version "1.3.3" resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" safe-buffer@5.1.1, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" @@ -5597,11 +5619,17 @@ shallow-clone@^0.1.2: lazy-cache "^0.2.3" mixin-object "^2.0.1" -shelljs@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" +shebang-command@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + dependencies: + shebang-regex "^1.0.0" + +shebang-regex@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" -signal-exit@^3.0.0: +signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -5609,9 +5637,11 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" snapdragon-node@^2.0.1: version "2.1.1" @@ -5829,7 +5859,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -5879,16 +5909,16 @@ strip-bom@^2.0.0: dependencies: is-utf8 "^0.2.0" +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + strip-indent@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" dependencies: get-stdin "^4.0.1" -strip-json-comments@~1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" - strip-json-comments@~2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" @@ -5926,6 +5956,12 @@ supports-color@^5.1.0: dependencies: has-flag "^2.0.0" +supports-color@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a" + dependencies: + has-flag "^3.0.0" + svg-sprite-loader@0.0.19: version "0.0.19" resolved "https://registry.yarnpkg.com/svg-sprite-loader/-/svg-sprite-loader-0.0.19.tgz#769a83009e34a1111b08efc84ae6df3038564542" @@ -5952,16 +5988,16 @@ symbol-observable@^1.0.2, symbol-observable@^1.0.3: version "1.1.0" resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.1.0.tgz#5c68fd8d54115d9dfb72a84720549222e8db9b32" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" +table@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + ajv "^6.0.1" + ajv-keywords "^3.0.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" tapable@^0.2.7, tapable@~0.2.5: version "0.2.8" @@ -6017,6 +6053,12 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" @@ -6214,12 +6256,6 @@ use@^2.0.0: isobject "^3.0.0" lazy-cache "^2.0.2" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" diff --git a/openecomp-ui/.eslintrc b/openecomp-ui/.eslintrc index 2ebd851b87..5bc1423a4a 100644 --- a/openecomp-ui/.eslintrc +++ b/openecomp-ui/.eslintrc @@ -1,5 +1,15 @@ { "parser": "babel-eslint", + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module", + "ecmaFeatures": { + "jsx": true, + "classes": true, + "modules": true, + "experimentalDecorators": true + } + }, "env": { "es6": true, "jquery": true, @@ -8,14 +18,12 @@ }, "plugins": [ "react", - "import" + "import", + "prettier" + ], + "extends": [ + "prettier" ], - "ecmaFeatures": { - "jsx": true, - "classes": true, - "modules": true, - "experimentalDecorators": true - }, "globals": { "Event": true, "window": true, @@ -40,23 +48,17 @@ "describe": true }, "rules": { + "prettier/prettier": ["error", { + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 + }], "linebreak-style": 0, "no-unused-vars": 2, "no-bitwise": 0, "no-eq-null": 2, "eqeqeq": 2, - "wrap-iife": [ - 2, - "any" - ], "no-unused-expressions": 2, - "indent": [ - 1, - "tab", - { - "SwitchCase": 1 - } - ], "no-use-before-define": 2, "new-cap": [ 2, @@ -75,25 +77,13 @@ "single", "avoid-escape" ], - "jsx-quotes": [ - 2, - "prefer-single" - ], "no-plusplus": 0, "no-cond-assign": [ 2, "except-parens" ], - "comma-style": [ - 2, - "last" - ], "no-invalid-this": 0, "dot-notation": 0, - "max-len": [ - 1, - 200 - ], "camelcase": [ 2, { @@ -101,16 +91,10 @@ } ], "curly": 2, - "brace-style": 0, "semi": [ 2, "always" ], - "space-in-brackets": [ - 0, - "never" - ], - "space-infix-ops": 2, "import/default": 0, "import/no-unresolved": 0, "import/no-named-as-default": 2, @@ -120,19 +104,6 @@ "react/display-name": 0, "react/forbid-prop-types": 0, "react/jsx-boolean-value": 0, - "react/jsx-closing-bracket-location": [ - 1, - { - "nonEmpty": "after-props", - "selfClosing": "after-props" - } - ], - "react/jsx-curly-spacing": 0, - "react/jsx-indent-props": [ - 1, - "tab" - ], - "react/jsx-max-props-per-line": 0, "react/jsx-no-duplicate-props": 1, "react/jsx-no-literals": 0, "react/jsx-no-undef": 1, @@ -149,9 +120,7 @@ "react/no-unknown-property": 1, "react/prop-types": 0, "react/react-in-jsx-scope": 1, - "react/require-extension": 1, "react/self-closing-comp": 1, "react/sort-comp": 0, - "react/wrap-multilines": 1 } } diff --git a/openecomp-ui/.prettierrc b/openecomp-ui/.prettierrc new file mode 100644 index 0000000000..0a7b3ae85f --- /dev/null +++ b/openecomp-ui/.prettierrc @@ -0,0 +1,5 @@ +{ + "singleQuote": true, + "jsxBracketSameLine": true, + "tabWidth": 4 +} diff --git a/openecomp-ui/package.json b/openecomp-ui/package.json index ecc28f7552..70c86cc50a 100644 --- a/openecomp-ui/package.json +++ b/openecomp-ui/package.json @@ -1,154 +1,158 @@ { - "name": "dox-ui", - "version": "1.0.0", - "description": "", - "author": "ONAP", - "license": "SEE LICENSE IN LICENSE", - "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", - "test-coverage": "jest --coverage && start ./coverage/lcov-report/index.html", - "test-build": "jest --coverage", - "storybook": "start-storybook -p 9090 -c .storybook -s .storybook/fonts", - "storyshots": "jest storyshots.test.js", - "build-storybook": "build-storybook -c .storybook -o .storybook-dist && gulp copy-storybook-fonts" - }, - "dependencies": { - "attr-accept": "^1.1.0", - "axios": "^0.16.2", - "classnames": "^2.2.5", - "core-js": "^2.4.0", - "d3": "^4.10.0", - "dox-sequence-diagram-ui": "file:../dox-sequence-diagram-ui", - "intl": "^1.0.1", - "intl-format-cache": "^2.0.5", - "intl-messageformat": "^1.2.0", - "intl-relativeformat": "^1.2.0", - "lodash": "^4.13.1", - "md5": "^2.1.0", - "prop-types": "^15.6.0", - "randomstring": "^1.1.5", - "react": "^15.6.2", - "react-dnd": "^2.5.4", - "react-dnd-html5-backend": "^2.5.4", - "react-dom": "^15.6.2", - "react-redux": "^5.0.6", - "react-select": "1.2.1", - "redux": "^3.7.2", - "react-bootstrap": "^0.32.1", - "react-click-outside": "^2.3.1", - "react-datepicker": "^0.48.0", - "react-dropzone": "4.2.3", - "react-input-autosize": "^2.2.0", - "react-show-more": "^1.1.1", - "react-sortable": "^1.2.0", - "sdc-ui": "1.6.24", - "uuid-js": "^0.7.5", - "validator": "^4.3.0" - }, - "devDependencies": { - "@kadira/storybook": "^2.35.3", - "@kadira/storybook-addon-knobs": "^1.7.1", - "@kadira/storybook-addon-options": "^1.0.2", - "babel-core": "^6.24.0", - "babel-eslint": "^7.2.1", - "babel-jest": "^22.1.0", - "babel-loader": "^7.0.0-beta.1", - "babel-plugin-transform-class-properties": "^6.10.2", - "babel-plugin-transform-decorators-legacy": "^1.3.4", - "babel-plugin-transform-object-rest-spread": "^6.8.0", - "babel-plugin-transform-runtime": "^6.22.0", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.23.0", - "css-loader": "^0.23.1", - "deep-freeze": "0.0.1", - "del": "^3.0.0", - "enzyme": "^2.7.1", - "eslint": "^2.13.1", - "eslint-loader": "^1.3.0", - "eslint-plugin-import": "^0.8.1", - "eslint-plugin-react": "^3.14.0", - "express": "^4.13.3", - "file-loader": "^0.8.5", - "gulp": "^3.9.1", - "gulp-clean": "^0.3.1", - "gulp-css-usage": "^2.0.0", - "gulp-rename": "^1.2.2", - "gulp-replace": "^0.5.4", - "gulp-sass": "^3.1.0", - "gulp-tap": "^1.0.1", - "gulp-zip": "^4.1.0", - "html-loader": "^0.4.3", - "http-proxy-middleware": "^0.17.4", - "ignore-loader": "^0.1.1", - "jasmine-core": "^2.5.2", - "jest": "^21.2.1", - "jshint": "^2.9.4", - "json-loader": "^0.5.4", - "jsx-loader": "^0.13.2", - "mkdirp": "^0.5.1", - "moment": "^2.18.1", - "node-sass": "^4.7.2", - "node-watch": "^0.3.5", - "prompt": "^0.2.14", - "react-addons-test-utils": "~15.3.2", - "react-hot-loader": "^3.1.3", - "rosie": "^1.6.0", - "run-sequence": "^2.2.1", - "sass-loader": "^6.0.6", - "source-map-loader": "^0.1.5", - "storyshots": "^3.2.2", - "style-loader": "^0.13.0", - "svg-sprite-loader": "^0.1.1", - "url-loader": "^0.5.7", - "webpack": "^2.2.1", - "webpack-dev-server": "^2.4.2" - }, - "engines": { - "node": ">=8.0.0", - "npm": ">=5.0.0", - "yarn": "^1.3.2" - }, - "jest": { - "moduleNameMapper": { - "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test-utils/fileMock.js", - "\\.(css|scss)$": "<rootDir>/test-utils/styleMock.js", - "^nfvo-utils/RestAPIUtil.js$": "<rootDir>/test-utils/MockRest.js", - "^sdc-ui/lib/react/SVGIcon.js$": "<rootDir>/test-utils/MockSVGIcon.js", - "^react-show-more$": "<rootDir>/test-utils/ShowMore.js", - "^nfvo-utils(.*)$": "<rootDir>/src/nfvo-utils$1", - "^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/en.json", - "^src(.*)$": "<rootDir>/src$1" + "name": "dox-ui", + "version": "1.0.0", + "description": "", + "author": "ONAP", + "license": "SEE LICENSE IN LICENSE", + "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", + "test-coverage": "jest --coverage && start ./coverage/lcov-report/index.html", + "test-build": "jest --coverage", + "storybook": "start-storybook -p 9090 -c .storybook -s .storybook/fonts", + "storyshots": "jest storyshots.test.js", + "build-storybook": "build-storybook -c .storybook -o .storybook-dist && gulp copy-storybook-fonts", + "lint-fix": "eslint --fix --ext .js --ext .jsx src" }, - "globals": { - "DEBUG": false + "dependencies": { + "attr-accept": "^1.1.0", + "axios": "^0.16.2", + "classnames": "^2.2.5", + "core-js": "^2.4.0", + "d3": "^4.10.0", + "dox-sequence-diagram-ui": "file:../dox-sequence-diagram-ui", + "intl": "^1.0.1", + "intl-format-cache": "^2.0.5", + "intl-messageformat": "^1.2.0", + "intl-relativeformat": "^1.2.0", + "lodash": "^4.13.1", + "md5": "^2.1.0", + "prop-types": "^15.6.0", + "randomstring": "^1.1.5", + "react": "^15.6.2", + "react-bootstrap": "^0.32.1", + "react-click-outside": "^2.3.1", + "react-datepicker": "^0.48.0", + "react-dnd": "^2.5.4", + "react-dnd-html5-backend": "^2.5.4", + "react-dom": "^15.6.2", + "react-dropzone": "4.2.3", + "react-input-autosize": "^2.2.0", + "react-redux": "^5.0.6", + "react-select": "1.2.1", + "react-show-more": "^1.1.1", + "react-sortable": "^1.2.0", + "redux": "^3.7.2", + "sdc-ui": "1.6.24", + "uuid-js": "^0.7.5", + "validator": "^4.3.0" }, - "setupFiles": [ - "<rootDir>/test-utils/test-env-setup.js" - ], - "setupTestFrameworkScriptFile": "<rootDir>/test-utils/test-setup.js", - "testPathIgnorePatterns": [ - "<rootDir>/node_modules/", - "<rootDir>/test/nfvo-components/storyshots.test.js" - ], - "collectCoverageFrom": [ - "src/**/*.{js,jsx}" - ], - "coveragePathIgnorePatterns": [ - "/node_modules/", - "(.)*.stories.js" - ], - "coverageReporters": [ - "lcov" - ] - } + "devDependencies": { + "@kadira/storybook": "^2.35.3", + "@kadira/storybook-addon-knobs": "^1.7.1", + "@kadira/storybook-addon-options": "^1.0.2", + "babel-core": "^6.24.0", + "babel-eslint": "^8.2.1", + "babel-jest": "^22.1.0", + "babel-loader": "^7.0.0-beta.1", + "babel-plugin-transform-class-properties": "^6.10.2", + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-plugin-transform-object-rest-spread": "^6.8.0", + "babel-plugin-transform-runtime": "^6.22.0", + "babel-preset-env": "^1.6.1", + "babel-preset-react": "^6.23.0", + "css-loader": "^0.23.1", + "deep-freeze": "0.0.1", + "del": "^3.0.0", + "enzyme": "^2.7.1", + "eslint": "^4.18.1", + "eslint-config-prettier": "^2.9.0", + "eslint-loader": "^2.0.0", + "eslint-plugin-import": "^2.9.0", + "eslint-plugin-prettier": "^2.6.0", + "eslint-plugin-react": "^7.7.0", + "express": "^4.13.3", + "file-loader": "^0.8.5", + "gulp": "^3.9.1", + "gulp-clean": "^0.3.1", + "gulp-css-usage": "^2.0.0", + "gulp-rename": "^1.2.2", + "gulp-replace": "^0.5.4", + "gulp-sass": "^3.1.0", + "gulp-tap": "^1.0.1", + "gulp-zip": "^4.1.0", + "html-loader": "^0.4.3", + "http-proxy-middleware": "^0.17.4", + "ignore-loader": "^0.1.1", + "jasmine-core": "^2.5.2", + "jest": "^21.2.1", + "jshint": "^2.9.4", + "json-loader": "^0.5.4", + "jsx-loader": "^0.13.2", + "mkdirp": "^0.5.1", + "moment": "^2.18.1", + "node-sass": "^4.7.2", + "node-watch": "^0.3.5", + "prettier": "^1.10.2", + "prompt": "^0.2.14", + "react-addons-test-utils": "~15.3.2", + "react-hot-loader": "^3.1.3", + "rosie": "^1.6.0", + "run-sequence": "^2.2.1", + "sass-loader": "^6.0.6", + "source-map-loader": "^0.1.5", + "storyshots": "^3.2.2", + "style-loader": "^0.13.0", + "svg-sprite-loader": "^0.1.1", + "url-loader": "^0.5.7", + "webpack": "^2.2.1", + "webpack-dev-server": "^2.4.2" + }, + "engines": { + "node": ">=8.0.0", + "npm": ">=5.0.0", + "yarn": "^1.3.2" + }, + "jest": { + "moduleNameMapper": { + "\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "<rootDir>/test-utils/fileMock.js", + "\\.(css|scss)$": "<rootDir>/test-utils/styleMock.js", + "^nfvo-utils/RestAPIUtil.js$": "<rootDir>/test-utils/MockRest.js", + "^sdc-ui/lib/react/SVGIcon.js$": "<rootDir>/test-utils/MockSVGIcon.js", + "^react-show-more$": "<rootDir>/test-utils/ShowMore.js", + "^nfvo-utils(.*)$": "<rootDir>/src/nfvo-utils$1", + "^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/en.json", + "^src(.*)$": "<rootDir>/src$1" + }, + "globals": { + "DEBUG": false + }, + "setupFiles": [ + "<rootDir>/test-utils/test-env-setup.js" + ], + "setupTestFrameworkScriptFile": "<rootDir>/test-utils/test-setup.js", + "testPathIgnorePatterns": [ + "<rootDir>/node_modules/", + "<rootDir>/test/nfvo-components/storyshots.test.js" + ], + "collectCoverageFrom": [ + "src/**/*.{js,jsx}" + ], + "coveragePathIgnorePatterns": [ + "/node_modules/", + "(.)*.stories.js" + ], + "coverageReporters": [ + "lcov" + ] + } } diff --git a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx index c15cd1d0e8..56382d6325 100644 --- a/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx +++ b/openecomp-ui/src/nfvo-components/SubmitErrorResponse.jsx @@ -13,11 +13,11 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import ListGroupItem from 'react-bootstrap/lib/ListGroupItem.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -import {Collapse} from 'react-bootstrap'; +import { Collapse } from 'react-bootstrap'; /** * parsing and showing the following Java Response object * @@ -42,121 +42,151 @@ import {Collapse} from 'react-bootstrap'; } */ class SubmitErrorResponse extends Component { + render() { + let { + validationResponse: { + vspErrors, + licensingDataErrors, + questionnaireValidationResult, + uploadDataErrors + } + } = this.props; + return ( + <div className="submit-error-response-view"> + {vspErrors && this.renderVspErrors(vspErrors)} + {licensingDataErrors && + this.renderVspErrors(licensingDataErrors)} + {questionnaireValidationResult && + this.renderComponentsErrors(questionnaireValidationResult)} + {uploadDataErrors && + this.renderUploadDataErrors(uploadDataErrors)} + </div> + ); + } + renderVspErrors(errors) { + return ( + <ErrorBlock errorType={i18n('VSP Errors')}> + <div> + {errors.length && + errors.map((error, i) => { + return ( + <ErrorMessage key={i} error={error.message} /> + ); + })} + </div> + </ErrorBlock> + ); + } - render() { - let {validationResponse : {vspErrors, licensingDataErrors, questionnaireValidationResult, uploadDataErrors}} = this.props; - return ( - <div className='submit-error-response-view'> - {vspErrors && this.renderVspErrors(vspErrors)} - {licensingDataErrors && this.renderVspErrors(licensingDataErrors)} - {questionnaireValidationResult && this.renderComponentsErrors(questionnaireValidationResult)} - {uploadDataErrors && this.renderUploadDataErrors(uploadDataErrors)} - </div> - ); - } - - renderVspErrors(errors) { - return ( - <ErrorBlock errorType={i18n('VSP Errors')}> - <div> - {errors.length && errors.map((error, i) => {return (<ErrorMessage key={i} error={error.message}/>);})} - </div> - </ErrorBlock> - ); - } - - - renderComponentsErrors(errors) { - return ( - <ErrorBlock errorType={i18n('Components Errors')}> - <div> - {errors.validationData.length && errors.validationData.map((item, i) =>{ return (<ComponentError key={i} item={item}/>);})} - </div> - </ErrorBlock> - ); - } + renderComponentsErrors(errors) { + return ( + <ErrorBlock errorType={i18n('Components Errors')}> + <div> + {errors.validationData.length && + errors.validationData.map((item, i) => { + return <ComponentError key={i} item={item} />; + })} + </div> + </ErrorBlock> + ); + } - renderUploadDataErrors(uploadDataErrors) { - return ( - <ErrorBlock errorType={i18n('Upload Data Errors')}> - <div> - <UploadErrorList items={uploadDataErrors}/> - </div> - </ErrorBlock> - ); - } + renderUploadDataErrors(uploadDataErrors) { + return ( + <ErrorBlock errorType={i18n('Upload Data Errors')}> + <div> + <UploadErrorList items={uploadDataErrors} /> + </div> + </ErrorBlock> + ); + } } - -const ComponentError = ({item}) => { - return ( - <div> - <div className='component-name-header'>{item.entityName}</div> - {item.errors.map((error, i) => {return(<ErrorMessage key={i} error={error}/>);})} - </div> - ); +const ComponentError = ({ item }) => { + return ( + <div> + <div className="component-name-header">{item.entityName}</div> + {item.errors.map((error, i) => { + return <ErrorMessage key={i} error={error} />; + })} + </div> + ); }; function* entries(obj) { - for (let key of Object.keys(obj)) { - yield {header: key, list: obj[key]}; - } + for (let key of Object.keys(obj)) { + yield { header: key, list: obj[key] }; + } } -const UploadErrorList = ({items}) => { - let generator = entries(items); - - let errors = []; - for (let item of generator) {errors.push( - <div key={item.header}> - <div className='component-name-header'>{item.header}</div> - {item.list.map((error, i) => <ErrorMessage key={i} warning={error.level === 'WARNING'} error={error.message}/> )} - </div> - );} +const UploadErrorList = ({ items }) => { + let generator = entries(items); + + let errors = []; + for (let item of generator) { + errors.push( + <div key={item.header}> + <div className="component-name-header">{item.header}</div> + {item.list.map((error, i) => ( + <ErrorMessage + key={i} + warning={error.level === 'WARNING'} + error={error.message} + /> + ))} + </div> + ); + } - return ( - <div> - {errors} - </div> - ); + return <div>{errors}</div>; }; class ErrorBlock extends React.Component { - state = { - collapsed: false - }; - - render() { - let {errorType, children} = this.props; - return ( - <div className='error-block'> - <ErrorHeader collapsed={this.state.collapsed} onClick={()=>{this.setState({collapsed: !this.state.collapsed});}} errorType={errorType}/> - <Collapse in={this.state.collapsed}> - {children} - </Collapse> - </div> - ); - } + state = { + collapsed: false + }; + + render() { + let { errorType, children } = this.props; + return ( + <div className="error-block"> + <ErrorHeader + collapsed={this.state.collapsed} + onClick={() => { + this.setState({ collapsed: !this.state.collapsed }); + }} + errorType={errorType} + /> + <Collapse in={this.state.collapsed}>{children}</Collapse> + </div> + ); + } } -const ErrorHeader = ({errorType, collapsed, onClick}) => { - return( - <div onClick={onClick} className='error-block-header'> - <SVGIcon iconClassName={collapsed ? '' : 'collapse-right' } name='chevronDown' label={errorType} labelPosition='right'/> - </div> - ); +const ErrorHeader = ({ errorType, collapsed, onClick }) => { + return ( + <div onClick={onClick} className="error-block-header"> + <SVGIcon + iconClassName={collapsed ? '' : 'collapse-right'} + name="chevronDown" + label={errorType} + labelPosition="right" + /> + </div> + ); }; -const ErrorMessage = ({error, warning}) => { - return ( - <ListGroupItem className='error-code-list-item'> - <SVGIcon - name={warning ? 'exclamationTriangleLine' : 'error'} - color={warning ? 'warning' : 'negative'} /> - <span className='icon-label'>{error}</span> - </ListGroupItem> - ); +const ErrorMessage = ({ error, warning }) => { + return ( + <ListGroupItem className="error-code-list-item"> + <SVGIcon + name={warning ? 'exclamationTriangleLine' : 'error'} + color={warning ? 'warning' : 'negative'} + /> + <span className="icon-label">{error}</span> + </ListGroupItem> + ); }; export default SubmitErrorResponse; diff --git a/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx b/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx index ac19072307..72f8de0d23 100644 --- a/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx +++ b/openecomp-ui/src/nfvo-components/accordion/Accordion.jsx @@ -4,9 +4,9 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. @@ -18,35 +18,38 @@ import React from 'react'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import PropTypes from 'prop-types'; - class Accordion extends React.Component { + static propTypes = { + title: PropTypes.string, + children: PropTypes.node + }; - static propTypes = { - title: PropTypes.string, - children: PropTypes.node - } - - constructor(props) { - super(props); - this.state = { - open: false - }; - } - render() { - const {children, title} = this.props; - const {open} = this.state; - return ( - <div className='accordion'> - <div onClick={()=>this.setState({open: !open})} className='accordion-header'> - <SVGIcon name='chevronUp' iconClassName={open ? 'down' : ''}/> - <div className='title'>{title}</div> - </div> - <div className={`accordion-body ${open ? 'open' : ''}`}> - {children} - </div> - </div> - ); - } + constructor(props) { + super(props); + this.state = { + open: false + }; + } + render() { + const { children, title } = this.props; + const { open } = this.state; + return ( + <div className="accordion"> + <div + onClick={() => this.setState({ open: !open })} + className="accordion-header"> + <SVGIcon + name="chevronUp" + iconClassName={open ? 'down' : ''} + /> + <div className="title">{title}</div> + </div> + <div className={`accordion-body ${open ? 'open' : ''}`}> + {children} + </div> + </div> + ); + } } -export default Accordion;
\ No newline at end of file +export default Accordion; diff --git a/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx index 25e7e7e02d..b4bc8be9ec 100644 --- a/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx +++ b/openecomp-ui/src/nfvo-components/datepicker/Datepicker.jsx @@ -5,72 +5,105 @@ import moment from 'moment'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; class CustomInput extends React.Component { + static propTypes = { + placeHolderText: PropTypes.string, + onChange: PropTypes.func, + onClick: PropTypes.func, + value: PropTypes.string + }; - static propTypes = { - placeHolderText: PropTypes.string, - onChange: PropTypes.func, - onClick: PropTypes.func, - value: PropTypes.string - }; - - render() { - const {placeholderText, onClick, onClear, inputRef, value: date} = this.props; - const text = date ? date : placeholderText; - const textStyle = date ? '' : 'placeholder'; - return ( - <div onClick={onClick} ref={inputRef} className='datepicker-custom-input'> - <div className={`datepicker-text ${textStyle}`}>{text}</div> - {date && <SVGIcon onClick={e => {e.stopPropagation(); onClear();}} name='close' className='clear-input'/>} - <SVGIcon name='calendar'/> - </div> - ); - } -}; + render() { + const { + placeholderText, + onClick, + onClear, + inputRef, + value: date + } = this.props; + const text = date ? date : placeholderText; + const textStyle = date ? '' : 'placeholder'; + return ( + <div + onClick={onClick} + ref={inputRef} + className="datepicker-custom-input"> + <div className={`datepicker-text ${textStyle}`}>{text}</div> + {date && ( + <SVGIcon + onClick={e => { + e.stopPropagation(); + onClear(); + }} + name="close" + className="clear-input" + /> + )} + <SVGIcon name="calendar" /> + </div> + ); + } +} const parseDate = (date, format) => { - return typeof date === 'number' ? moment.unix(date) : moment(date, format); + return typeof date === 'number' ? moment.unix(date) : moment(date, format); }; class Datepicker extends React.Component { - static propTypes = { - date: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - format: PropTypes.string, - onChange: PropTypes.func, - selectsStart: PropTypes.bool, - selectsEnd: PropTypes.bool, - startDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), - disabled: PropTypes.bool, - label: PropTypes.string, - isRequired: 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 - }; + static propTypes = { + date: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + format: PropTypes.string, + onChange: PropTypes.func, + selectsStart: PropTypes.bool, + selectsEnd: PropTypes.bool, + startDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + endDate: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), + disabled: PropTypes.bool, + label: PropTypes.string, + isRequired: 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> - ); - } + 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/editor/TabulatedEditor.jsx b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx index 3c9ceed0d8..9fcd7042bc 100644 --- a/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx +++ b/openecomp-ui/src/nfvo-components/editor/TabulatedEditor.jsx @@ -20,79 +20,106 @@ import VersionController from 'nfvo-components/panel/versionController/VersionCo import NavigationSideBar from 'nfvo-components/panel/NavigationSideBar.jsx'; export default class TabulatedEditor extends React.Component { + render() { + const { + navigationBarProps, + onToggle, + onVersionSwitching, + onMoreVersionsClick, + onCreate, + onSave, + onClose, + onVersionControllerAction, + onNavigate, + children, + meta, + onManagePermissions, + onOpenCommentCommitModal, + onOpenPermissions, + onOpenRevisionsModal + } = this.props; + let { versionControllerProps } = this.props; + const { className = '' } = React.Children.only(children).props; + const child = this.prepareChild(); - render() { - const {navigationBarProps, onToggle, onVersionSwitching, onMoreVersionsClick, onCreate, onSave, onClose, - onVersionControllerAction, onNavigate, children, meta, onManagePermissions, onOpenCommentCommitModal, onOpenPermissions, onOpenRevisionsModal} = this.props; - let {versionControllerProps} = this.props; - const {className = ''} = React.Children.only(children).props; - const child = this.prepareChild(); + if (onClose) { + versionControllerProps = { + ...versionControllerProps, + onClose: () => onClose(versionControllerProps) + }; + } + return ( + <div className="software-product-view"> + <div className="software-product-navigation-side-bar"> + <NavigationSideBar + {...navigationBarProps} + onSelect={onNavigate} + onToggle={onToggle} + /> + </div> + <div className="software-product-landing-view-right-side flex-column"> + <VersionController + {...versionControllerProps} + onVersionSwitching={version => + onVersionSwitching(version, meta) + } + onMoreVersionsClick={onMoreVersionsClick} + onManagePermissions={onManagePermissions} + onOpenCommentCommitModal={onOpenCommentCommitModal} + onOpenPermissions={onOpenPermissions} + onOpenRevisionsModal={onOpenRevisionsModal} + callVCAction={(action, version, comment) => + onVersionControllerAction( + action, + version, + comment, + meta + ) + } + onCreate={onCreate && this.handleCreate} + onSave={onSave && this.handleSave} + /> + <div className={classnames('content-area', `${className}`)}> + {child} + </div> + </div> + </div> + ); + } - if(onClose) { - versionControllerProps = { - ...versionControllerProps, - onClose: () => onClose(versionControllerProps) - }; - } - return ( - <div className='software-product-view'> - <div className='software-product-navigation-side-bar'> - <NavigationSideBar {...navigationBarProps} onSelect={onNavigate} onToggle={onToggle}/> - </div> - <div className='software-product-landing-view-right-side flex-column'> - <VersionController - {...versionControllerProps} - onVersionSwitching={version => onVersionSwitching(version, meta)} - onMoreVersionsClick={onMoreVersionsClick} - onManagePermissions={onManagePermissions} - onOpenCommentCommitModal={onOpenCommentCommitModal} - onOpenPermissions={onOpenPermissions} - onOpenRevisionsModal={onOpenRevisionsModal} - callVCAction={(action, version, comment) => onVersionControllerAction(action, version, comment, meta)} - onCreate={onCreate && this.handleCreate} - onSave={onSave && this.handleSave}/> - <div className={classnames('content-area', `${className}`)}> - { - child - } - </div> - </div> - </div> - ); - } + prepareChild() { + const { onSave, onCreate, children } = this.props; - prepareChild() { - const {onSave, onCreate, children} = this.props; + const additionalChildProps = { ref: 'editor' }; + if (onSave) { + additionalChildProps.onSave = onSave; + } + if (onCreate) { + additionalChildProps.onCreate = onCreate; + } - const additionalChildProps = {ref: 'editor'}; - if (onSave) { - additionalChildProps.onSave = onSave; - } - if (onCreate) { - additionalChildProps.onCreate = onCreate; - } + const child = React.cloneElement( + React.Children.only(children), + additionalChildProps + ); + return child; + } - const child = React.cloneElement(React.Children.only(children), additionalChildProps); - return child; - } + handleSave = () => { + const childInstance = this.refs.editor.getWrappedInstance(); + if (childInstance.save) { + return childInstance.save(); + } else { + return this.props.onSave(); + } + }; - - - handleSave = () => { - const childInstance = this.refs.editor.getWrappedInstance(); - if (childInstance.save) { - return childInstance.save(); - } else { - return this.props.onSave(); - } - }; - - handleCreate = () => { - const childInstance = this.refs.editor.getWrappedInstance(); - if (childInstance.create) { - childInstance.create(); - } else { - this.props.onCreate(); - } - } + handleCreate = () => { + const childInstance = this.refs.editor.getWrappedInstance(); + if (childInstance.create) { + childInstance.create(); + } else { + this.props.onCreate(); + } + }; } diff --git a/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx b/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx index 5b4e0a8bee..0d47d859d9 100644 --- a/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx +++ b/openecomp-ui/src/nfvo-components/fileupload/DraggableUploadFileBox.jsx @@ -26,20 +26,33 @@ * or * https://github.com/JedWatson/react-select */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Button from 'sdc-ui/lib/react/Button.js'; class DraggableUploadFileBox extends Component { - render() { - let {className, onClick, dataTestId, isReadOnlyMode} = this.props; - return ( - <div className={`file-upload-box ${className} ${isReadOnlyMode ? 'disabled' : ''}`}> - <div className={`drag-text ${isReadOnlyMode ? 'disabled' : ''}`}>{i18n('Drag & drop for upload')}</div> - <div className='or-text'>{i18n('or')}</div> - <Button type='button' data-test-id={dataTestId} btnType='outline' onClick={onClick} disabled={isReadOnlyMode}>{i18n('Select File')}</Button> - </div> - ); - } + render() { + let { className, onClick, dataTestId, isReadOnlyMode } = this.props; + return ( + <div + className={`file-upload-box ${className} ${ + isReadOnlyMode ? 'disabled' : '' + }`}> + <div + className={`drag-text ${isReadOnlyMode ? 'disabled' : ''}`}> + {i18n('Drag & drop for upload')} + </div> + <div className="or-text">{i18n('or')}</div> + <Button + type="button" + data-test-id={dataTestId} + btnType="outline" + onClick={onClick} + disabled={isReadOnlyMode}> + {i18n('Select File')} + </Button> + </div> + ); + } } export default DraggableUploadFileBox; diff --git a/openecomp-ui/src/nfvo-components/grid/GridItem.jsx b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx index c62e042bf4..9723cde2c0 100644 --- a/openecomp-ui/src/nfvo-components/grid/GridItem.jsx +++ b/openecomp-ui/src/nfvo-components/grid/GridItem.jsx @@ -15,12 +15,21 @@ */ import React from 'react'; -const GridItem = ({colSpan = 1, children, lastColInRow = false, stretch = false, className = ''}) => ( - <div className={`grid-col-${colSpan} ${lastColInRow ? 'last-col-in-row' : ''} ${className}`}> - <div className={`grid-item${stretch ? '-stretch' : ''}`}> - {children} - </div> - </div> +const GridItem = ({ + colSpan = 1, + children, + lastColInRow = false, + stretch = false, + className = '' +}) => ( + <div + className={`grid-col-${colSpan} ${ + lastColInRow ? 'last-col-in-row' : '' + } ${className}`}> + <div className={`grid-item${stretch ? '-stretch' : ''}`}> + {children} + </div> + </div> ); export default GridItem; diff --git a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx index 8f4a024fdb..f2e3588d9e 100644 --- a/openecomp-ui/src/nfvo-components/grid/GridSection.jsx +++ b/openecomp-ui/src/nfvo-components/grid/GridSection.jsx @@ -17,21 +17,32 @@ import React from 'react'; import PropTypes from 'prop-types'; import classnames from 'classnames'; -const GridSection = ({title, children, className = '', titleClassName, hasLastColSet = false}) => { - return ( - <div className={classnames('grid-section', className, {'has-last-col-set': hasLastColSet})}> - {title && <div className={`section-title ${titleClassName || ''}`}>{title}</div>} - <div className='grid-items'> - {children} - </div> - </div> - ); +const GridSection = ({ + title, + children, + className = '', + titleClassName, + hasLastColSet = false +}) => { + return ( + <div + className={classnames('grid-section', className, { + 'has-last-col-set': hasLastColSet + })}> + {title && ( + <div className={`section-title ${titleClassName || ''}`}> + {title} + </div> + )} + <div className="grid-items">{children}</div> + </div> + ); }; GridSection.propTypes = { - title: PropTypes.string, - titleClassName: PropTypes.string, - hasLastColSet: PropTypes.bool + title: PropTypes.string, + titleClassName: PropTypes.string, + hasLastColSet: PropTypes.bool }; export default GridSection; diff --git a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx index 82fbe1deed..3973ae8c5d 100644 --- a/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx +++ b/openecomp-ui/src/nfvo-components/input/ExpandableInput.jsx @@ -19,99 +19,118 @@ import ReactDOM from 'react-dom'; 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' data-test-id='expandable-input-closed' name={iconType} onClick={onClick} /> +const ExpandableInputClosed = ({ iconType, onClick }) => ( + <SVGIcon + className="expandable-input-wrapper closed" + data-test-id="expandable-input-closed" + name={iconType} + onClick={onClick} + /> ); class ExpandableInputOpened extends React.Component { - componentDidMount(){ - this.rawDomNode = ReactDOM.findDOMNode(this.searchInputNode.inputWrapper); - this.rawDomNode.focus(); - } + componentDidMount() { + this.rawDomNode = ReactDOM.findDOMNode( + this.searchInputNode.inputWrapper + ); + this.rawDomNode.focus(); + } - componentWillReceiveProps(newProps){ - if (!newProps.value){ - if (!(document.activeElement === this.rawDomNode)){ - this.props.handleBlur(); - } - } - } + componentWillReceiveProps(newProps) { + if (!newProps.value) { + if (!(document.activeElement === this.rawDomNode)) { + this.props.handleBlur(); + } + } + } - handleClose(){ - this.props.onChange(''); - this.rawDomNode.focus(); - } + handleClose() { + this.props.onChange(''); + this.rawDomNode.focus(); + } - handleKeyDown(e){ - if (e.key === 'Escape'){ - e.preventDefault(); - if (this.props.value) { - this.handleClose(); - } else { - this.rawDomNode.blur(); - } - }; - } + handleKeyDown(e) { + if (e.key === 'Escape') { + e.preventDefault(); + if (this.props.value) { + this.handleClose(); + } else { + this.rawDomNode.blur(); + } + } + } - render() { - let {iconType, value, onChange, handleBlur} = this.props; - return ( - <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' - groupClassName='expandable-input-control' - onChange={e => onChange(e)} - onKeyDown={e => this.handleKeyDown(e)} - onBlur={handleBlur}/> - {value && <SVGIcon data-test-id='expandable-input-close-btn' onClick={() => this.handleClose()} name='close' />} - {!value && <SVGIcon name={iconType} onClick={handleBlur}/>} - </div> - ); - } + render() { + let { iconType, value, onChange, handleBlur } = this.props; + return ( + <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" + groupClassName="expandable-input-control" + onChange={e => onChange(e)} + onKeyDown={e => this.handleKeyDown(e)} + onBlur={handleBlur} + /> + {value && ( + <SVGIcon + data-test-id="expandable-input-close-btn" + onClick={() => this.handleClose()} + name="close" + /> + )} + {!value && <SVGIcon name={iconType} onClick={handleBlur} />} + </div> + ); + } } class ExpandableInput extends React.Component { + static propTypes = { + iconType: PropTypes.string, + onChange: PropTypes.func, + value: PropTypes.string + }; - static propTypes = { - iconType: PropTypes.string, - onChange: PropTypes.func, - value: PropTypes.string - }; + state = { showInput: false }; - state = {showInput: false}; + closeInput() { + if (!this.props.value) { + this.setState({ showInput: false }); + } + } - closeInput(){ - if (!this.props.value) { - this.setState({showInput: false}); - } - } + getValue() { + return this.props.value; + } - getValue(){ - return this.props.value; - } - - render(){ - let {iconType, value, onChange = false} = this.props; - return ( - <div className='expandable-input-top'> - {this.state.showInput && - <ExpandableInputOpened - key='open' - iconType={iconType} - onChange={onChange} - value={value} - handleKeyDown={(e) => this.handleKeyDown(e)} - handleBlur={() => this.closeInput()}/> - } - {!this.state.showInput && <ExpandableInputClosed key='closed' iconType={iconType} onClick={() => this.setState({showInput: true})} />} - </div> - ); - } + render() { + let { iconType, value, onChange = false } = this.props; + return ( + <div className="expandable-input-top"> + {this.state.showInput && ( + <ExpandableInputOpened + key="open" + iconType={iconType} + onChange={onChange} + value={value} + handleKeyDown={e => this.handleKeyDown(e)} + handleBlur={() => this.closeInput()} + /> + )} + {!this.state.showInput && ( + <ExpandableInputClosed + key="closed" + iconType={iconType} + onClick={() => this.setState({ showInput: true })} + /> + )} + </div> + ); + } } - export default ExpandableInput; diff --git a/openecomp-ui/src/nfvo-components/input/SelectInput.jsx b/openecomp-ui/src/nfvo-components/input/SelectInput.jsx index 03c727379e..b0e0d87d7c 100644 --- a/openecomp-ui/src/nfvo-components/input/SelectInput.jsx +++ b/openecomp-ui/src/nfvo-components/input/SelectInput.jsx @@ -26,43 +26,51 @@ * or * https://github.com/JedWatson/react-select */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import Select from 'react-select'; class SelectInput extends Component { + inputValue = []; - inputValue = []; + render() { + let { label, value, ...other } = this.props; + const dataTestId = this.props['data-test-id'] + ? { 'data-test-id': this.props['data-test-id'] } + : {}; + return ( + <div + {...dataTestId} + className="validation-input-wrapper dropdown-multi-select"> + <div className="form-group"> + {label && <label className="control-label">{label}</label>} + <Select + ref="_myInput" + onChange={value => this.onSelectChanged(value)} + {...other} + value={value} + /> + </div> + </div> + ); + } - render() { - let {label, value, ...other} = this.props; - const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {}; - return ( - <div {...dataTestId} className='validation-input-wrapper dropdown-multi-select'> - <div className='form-group'> - {label && <label className='control-label'>{label}</label>} - <Select ref='_myInput' onChange={value => this.onSelectChanged(value)} {...other} value={value} /> - </div> - </div> - ); - } + getValue() { + return this.inputValue && this.inputValue.length ? this.inputValue : ''; + } - getValue() { - return this.inputValue && this.inputValue.length ? this.inputValue : ''; - } + onSelectChanged(value) { + this.props.onMultiSelectChanged(value); + } - onSelectChanged(value) { - this.props.onMultiSelectChanged(value); - } - - componentDidMount() { - let {value} = this.props; - this.inputValue = value ? value : []; - } - componentDidUpdate() { - if (this.inputValue !== this.props.value) { - this.inputValue = this.props.value; - } - } + componentDidMount() { + let { value } = this.props; + this.inputValue = value ? value : []; + } + componentDidUpdate() { + if (this.inputValue !== this.props.value) { + this.inputValue = this.props.value; + } + } } export default SelectInput; diff --git a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx index 31a8a66d86..947570fa29 100644 --- a/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx +++ b/openecomp-ui/src/nfvo-components/input/ToggleInput.jsx @@ -16,55 +16,60 @@ import React from 'react'; import PropTypes from 'prop-types'; -export default -class ToggleInput extends React.Component { +export default class ToggleInput extends React.Component { + static propTypes = { + label: PropTypes.node, + value: PropTypes.bool, + onChange: PropTypes.func, + disabled: PropTypes.bool + }; - static propTypes = { - label: PropTypes.node, - value: PropTypes.bool, - onChange: PropTypes.func, - disabled: PropTypes.bool - } + static defaultProps = { + value: false, + label: '' + }; - static defaultProps = { - value: false, - label: '' - } + state = { + value: this.props.value + }; - state = { - value: this.props.value - } + status() { + return this.state.value ? 'on' : 'off'; + } - status() { - return this.state.value ? 'on' : 'off'; - } + render() { + let { label, disabled } = this.props; + let checked = this.status() === 'on'; + //TODO check onclick + return ( + <div + className="toggle-input-wrapper form-group" + onClick={!disabled && this.click}> + <div className="toggle-input-label">{label}</div> + <div className="toggle-switch"> + <input + className="toggle toggle-round-flat" + type="checkbox" + checked={checked} + readOnly + /> + <label /> + </div> + </div> + ); + } - render() { - let {label, disabled} = this.props; - let checked = this.status() === 'on'; - //TODO check onclick - return ( - <div className='toggle-input-wrapper form-group' onClick={!disabled && this.click}> - <div className='toggle-input-label'>{label}</div> - <div className='toggle-switch'> - <input className='toggle toggle-round-flat' type='checkbox' checked={checked} readOnly/> - <label></label> - </div> - </div> - ); - } + click = () => { + let value = !this.state.value; + this.setState({ value }); - click = () => { - let value = !this.state.value; - this.setState({value}); + let onChange = this.props.onChange; + if (onChange) { + onChange(value); + } + }; - let onChange = this.props.onChange; - if (onChange) { - onChange(value); - } - } - - getValue() { - return this.state.value; - } + getValue() { + return this.state.value; + } } diff --git a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx index a689c50778..7ab4c8242c 100644 --- a/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx +++ b/openecomp-ui/src/nfvo-components/input/dualListbox/DualListboxView.jsx @@ -19,136 +19,224 @@ import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Input from 'nfvo-components/input/validation/InputWrapper.jsx'; class DualListboxView extends React.Component { - - static propTypes = { - - availableList: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired - })), - filterTitle: PropTypes.shape({ - left: PropTypes.string, - right: PropTypes.string - }), - selectedValuesList: PropTypes.arrayOf(PropTypes.string), - - onChange: PropTypes.func.isRequired - }; - - static defaultProps = { - selectedValuesList: [], - availableList: [], - filterTitle: { - left: '', - right: '' - } - }; - - state = { - availableListFilter: '', - selectedValuesListFilter: '', - selectedValues: [] - }; - - render() { - let {availableList, selectedValuesList, filterTitle, isReadOnlyMode} = this.props; - let {availableListFilter, selectedValuesListFilter} = this.state; - - let unselectedList = availableList.filter(availableItem => !selectedValuesList.find(value => value === availableItem.id)); - let selectedList = availableList.filter(availableItem => selectedValuesList.find(value => value === availableItem.id)); - selectedList = selectedList.sort((a, b) => selectedValuesList.indexOf(a.id) - selectedValuesList.indexOf(b.id)); - return ( - <div className='dual-list-box'> - {this.renderListbox(filterTitle.left, unselectedList, { - value: availableListFilter, - ref: 'availableListFilter', - disabled: isReadOnlyMode, - onChange: (value) => this.setState({availableListFilter: value}) - }, {ref: 'availableValues', disabled: isReadOnlyMode, testId: 'available',})} - {this.renderOperationsBar(isReadOnlyMode)} - {this.renderListbox(filterTitle.right, selectedList, { - value: selectedValuesListFilter, - ref: 'selectedValuesListFilter', - disabled: isReadOnlyMode, - onChange: (value) => this.setState({selectedValuesListFilter: value}) - }, {ref: 'selectedValues', disabled: isReadOnlyMode, testId: 'selected'})} - </div> - ); - } - - renderListbox(filterTitle, list, filterProps, props) { - let regExFilter = new RegExp(escape(filterProps.value), 'i'); - let matchedItems = list.filter(item => item.name.match(regExFilter)); - let unMatchedItems = list.filter(item => !item.name.match(regExFilter)); - return ( - <div className='dual-search-multi-select-section'> - <p>{filterTitle}</p> - <div className='dual-text-box-search search-wrapper'> - <Input data-test-id={`${props.testId}-search-input`} - name='search-input-control' type='text' - groupClassName='search-input-control' - {...filterProps}/> - <SVGIcon name='search' className='search-icon'/> - </div> - <Input - multiple - onChange={(event) => this.onSelectItems(event.target.selectedOptions)} - groupClassName='dual-list-box-multi-select' - type='select' - name='dual-list-box-multi-select' - data-test-id={`${props.testId}-select-input`} - disabled={props.disabled} - ref={props.ref}> - {matchedItems.map(item => this.renderOption(item.id, item.name))} - {matchedItems.length && unMatchedItems.length && <option style={{pointerEvents: 'none'}}>--------------------</option>} - {unMatchedItems.map(item => this.renderOption(item.id, item.name))} - </Input> - </div> - ); - } - - onSelectItems(selectedOptions) { - let selectedValues = Object.keys(selectedOptions).map((k) => selectedOptions[k].value); - this.setState({selectedValues}); - } - - renderOption(value, name) { - return (<option className='dual-list-box-multi-select-text' key={value} value={value}>{name}</option>); - } - - renderOperationsBar(isReadOnlyMode) { - return ( - <div className={`dual-list-options-bar${isReadOnlyMode ? ' disabled' : ''}`}> - {this.renderOperationBarButton(() => this.addToSelectedList(), 'angleRight')} - {this.renderOperationBarButton(() => this.removeFromSelectedList(), 'angleLeft')} - {this.renderOperationBarButton(() => this.addAllToSelectedList(), 'angleDoubleRight')} - {this.renderOperationBarButton(() => this.removeAllFromSelectedList(), 'angleDoubleLeft')} - </div> - ); - } - - renderOperationBarButton(onClick, iconName){ - return (<div className='dual-list-option' data-test-id={`operation-icon-${iconName}`} onClick={onClick}><SVGIcon name={iconName}/></div>); - } - - addToSelectedList() { - this.props.onChange(this.props.selectedValuesList.concat(this.state.selectedValues)); - this.setState({selectedValues: []}); - } - - removeFromSelectedList() { - const selectedValues = this.state.selectedValues; - this.props.onChange(this.props.selectedValuesList.filter(value => !selectedValues.find(selectedValue => selectedValue === value))); - this.setState({selectedValues: []}); - } - - addAllToSelectedList() { - this.props.onChange(this.props.availableList.map(item => item.id)); - } - - removeAllFromSelectedList() { - this.props.onChange([]); - } + static propTypes = { + availableList: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired + }) + ), + filterTitle: PropTypes.shape({ + left: PropTypes.string, + right: PropTypes.string + }), + selectedValuesList: PropTypes.arrayOf(PropTypes.string), + + onChange: PropTypes.func.isRequired + }; + + static defaultProps = { + selectedValuesList: [], + availableList: [], + filterTitle: { + left: '', + right: '' + } + }; + + state = { + availableListFilter: '', + selectedValuesListFilter: '', + selectedValues: [] + }; + + render() { + let { + availableList, + selectedValuesList, + filterTitle, + isReadOnlyMode + } = this.props; + let { availableListFilter, selectedValuesListFilter } = this.state; + + let unselectedList = availableList.filter( + availableItem => + !selectedValuesList.find(value => value === availableItem.id) + ); + let selectedList = availableList.filter(availableItem => + selectedValuesList.find(value => value === availableItem.id) + ); + selectedList = selectedList.sort( + (a, b) => + selectedValuesList.indexOf(a.id) - + selectedValuesList.indexOf(b.id) + ); + return ( + <div className="dual-list-box"> + {this.renderListbox( + filterTitle.left, + unselectedList, + { + value: availableListFilter, + ref: 'availableListFilter', + disabled: isReadOnlyMode, + onChange: value => + this.setState({ availableListFilter: value }) + }, + { + ref: 'availableValues', + disabled: isReadOnlyMode, + testId: 'available' + } + )} + {this.renderOperationsBar(isReadOnlyMode)} + {this.renderListbox( + filterTitle.right, + selectedList, + { + value: selectedValuesListFilter, + ref: 'selectedValuesListFilter', + disabled: isReadOnlyMode, + onChange: value => + this.setState({ selectedValuesListFilter: value }) + }, + { + ref: 'selectedValues', + disabled: isReadOnlyMode, + testId: 'selected' + } + )} + </div> + ); + } + + renderListbox(filterTitle, list, filterProps, props) { + let regExFilter = new RegExp(escape(filterProps.value), 'i'); + let matchedItems = list.filter(item => item.name.match(regExFilter)); + let unMatchedItems = list.filter(item => !item.name.match(regExFilter)); + return ( + <div className="dual-search-multi-select-section"> + <p>{filterTitle}</p> + <div className="dual-text-box-search search-wrapper"> + <Input + data-test-id={`${props.testId}-search-input`} + name="search-input-control" + type="text" + groupClassName="search-input-control" + {...filterProps} + /> + <SVGIcon name="search" className="search-icon" /> + </div> + <Input + multiple + onChange={event => + this.onSelectItems(event.target.selectedOptions) + } + groupClassName="dual-list-box-multi-select" + type="select" + name="dual-list-box-multi-select" + data-test-id={`${props.testId}-select-input`} + disabled={props.disabled} + ref={props.ref}> + {matchedItems.map(item => + this.renderOption(item.id, item.name) + )} + {matchedItems.length && + unMatchedItems.length && ( + <option style={{ pointerEvents: 'none' }}> + -------------------- + </option> + )} + {unMatchedItems.map(item => + this.renderOption(item.id, item.name) + )} + </Input> + </div> + ); + } + + onSelectItems(selectedOptions) { + let selectedValues = Object.keys(selectedOptions).map( + k => selectedOptions[k].value + ); + this.setState({ selectedValues }); + } + + renderOption(value, name) { + return ( + <option + className="dual-list-box-multi-select-text" + key={value} + value={value}> + {name} + </option> + ); + } + + renderOperationsBar(isReadOnlyMode) { + return ( + <div + className={`dual-list-options-bar${ + isReadOnlyMode ? ' disabled' : '' + }`}> + {this.renderOperationBarButton( + () => this.addToSelectedList(), + 'angleRight' + )} + {this.renderOperationBarButton( + () => this.removeFromSelectedList(), + 'angleLeft' + )} + {this.renderOperationBarButton( + () => this.addAllToSelectedList(), + 'angleDoubleRight' + )} + {this.renderOperationBarButton( + () => this.removeAllFromSelectedList(), + 'angleDoubleLeft' + )} + </div> + ); + } + + renderOperationBarButton(onClick, iconName) { + return ( + <div + className="dual-list-option" + data-test-id={`operation-icon-${iconName}`} + onClick={onClick}> + <SVGIcon name={iconName} /> + </div> + ); + } + + addToSelectedList() { + this.props.onChange( + this.props.selectedValuesList.concat(this.state.selectedValues) + ); + this.setState({ selectedValues: [] }); + } + + removeFromSelectedList() { + const selectedValues = this.state.selectedValues; + this.props.onChange( + this.props.selectedValuesList.filter( + value => + !selectedValues.find( + selectedValue => selectedValue === value + ) + ) + ); + this.setState({ selectedValues: [] }); + } + + addAllToSelectedList() { + this.props.onChange(this.props.availableList.map(item => item.id)); + } + + removeAllFromSelectedList() { + this.props.onChange([]); + } } export default DualListboxView; diff --git a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx index 6df0bf9009..62fc29a55c 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Form.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Form.jsx @@ -19,130 +19,160 @@ import PropTypes from 'prop-types'; import ValidationButtons from './ValidationButtons.jsx'; class Form extends React.Component { - - static defaultProps = { - hasButtons : true, - onSubmit : null, - onReset : null, - labledButtons: true, - onValidChange : null, - isValid: true, - submitButtonText: null, - cancelButtonText: null - }; - - static propTypes = { - isValid : PropTypes.bool, - formReady : PropTypes.bool, - isReadOnlyMode : PropTypes.bool, - hasButtons : PropTypes.bool, - onSubmit : PropTypes.func, - onReset : PropTypes.func, - labledButtons: PropTypes.bool, - submitButtonText: PropTypes.string, - cancelButtonText: PropTypes.string, - onValidChange : PropTypes.func, - onValidityChanged: PropTypes.func, - onValidateForm: PropTypes.func - }; - - constructor(props) { - super(props); - } - - - render() { - // eslint-disable-next-line no-unused-vars - 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'> - <fieldset disabled={isReadOnlyMode}> - {children} - </fieldset> - </div> - {hasButtons && - <ValidationButtons - labledButtons={labledButtons} - submitButtonText={submitButtonText} - cancelButtonText={cancelButtonText} - ref={(buttons) => this.buttons = buttons} - isReadOnlyMode={isReadOnlyMode}/>} - </form> - ); - } - - handleFormValidation(event) { - event.preventDefault(); - if (this.props.onValidateForm && !this.props.formReady){ - return this.props.onValidateForm(); - } else { - return this.handleFormSubmit(event); - } - } - handleFormSubmit(event) { - if (event) { - event.preventDefault(); - } - if(this.props.onSubmit) { - return this.props.onSubmit(event); - } - } - - componentDidMount() { - if (this.props.hasButtons) { - this.buttons.setState({isValid: this.props.isValid}); - } - } - - - - componentDidUpdate(prevProps) { - // only handling this programatically if the validation of the form is done outside of the view - // (example with a form that is dependent on the state of other forms) - if (prevProps.isValid !== this.props.isValid) { - if (this.props.hasButtons) { - this.buttons.setState({isValid: this.props.isValid}); - } - // callback in case form is part of bigger picture in view - if (this.props.onValidChange) { - this.props.onValidChange(this.props.isValid); - } - - // TODO - maybe this has to be part of componentWillUpdate - if(this.props.onValidityChanged) { - this.props.onValidityChanged(this.props.isValid); - } - } - if (this.props.formReady) { // if form validation succeeded -> continue with submit - this.handleFormSubmit(); - } - } - + static defaultProps = { + hasButtons: true, + onSubmit: null, + onReset: null, + labledButtons: true, + onValidChange: null, + isValid: true, + submitButtonText: null, + cancelButtonText: null + }; + + static propTypes = { + isValid: PropTypes.bool, + formReady: PropTypes.bool, + isReadOnlyMode: PropTypes.bool, + hasButtons: PropTypes.bool, + onSubmit: PropTypes.func, + onReset: PropTypes.func, + labledButtons: PropTypes.bool, + submitButtonText: PropTypes.string, + cancelButtonText: PropTypes.string, + onValidChange: PropTypes.func, + onValidityChanged: PropTypes.func, + onValidateForm: PropTypes.func + }; + + constructor(props) { + super(props); + } + render() { + /* eslint-disable no-unused-vars */ + let { + isValid, + onValidChange, + onValidityChanged, + onDataChanged, + formReady, + onValidateForm, + isReadOnlyMode, + hasButtons, + onSubmit, + labledButtons, + submitButtonText, + cancelButtonText, + children, + ...formProps + } = this.props; + /* eslint-enable no-unused-vars */ + return ( + <form + {...formProps} + ref={form => (this.form = form)} + onSubmit={event => this.handleFormValidation(event)}> + <div className="validation-form-content"> + <fieldset disabled={isReadOnlyMode}>{children}</fieldset> + </div> + {hasButtons && ( + <ValidationButtons + labledButtons={labledButtons} + submitButtonText={submitButtonText} + cancelButtonText={cancelButtonText} + ref={buttons => (this.buttons = buttons)} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </form> + ); + } + + handleFormValidation(event) { + event.preventDefault(); + if (this.props.onValidateForm && !this.props.formReady) { + return this.props.onValidateForm(); + } else { + return this.handleFormSubmit(event); + } + } + handleFormSubmit(event) { + if (event) { + event.preventDefault(); + } + if (this.props.onSubmit) { + return this.props.onSubmit(event); + } + } + + componentDidMount() { + if (this.props.hasButtons) { + this.buttons.setState({ isValid: this.props.isValid }); + } + } + + componentDidUpdate(prevProps) { + // only handling this programatically if the validation of the form is done outside of the view + // (example with a form that is dependent on the state of other forms) + if (prevProps.isValid !== this.props.isValid) { + if (this.props.hasButtons) { + this.buttons.setState({ isValid: this.props.isValid }); + } + // callback in case form is part of bigger picture in view + if (this.props.onValidChange) { + this.props.onValidChange(this.props.isValid); + } + + // TODO - maybe this has to be part of componentWillUpdate + if (this.props.onValidityChanged) { + this.props.onValidityChanged(this.props.isValid); + } + } + if (this.props.formReady) { + // if form validation succeeded -> continue with submit + this.handleFormSubmit(); + } + } } export class TabsForm extends Form { - render() { - // eslint-disable-next-line no-unused-vars - let {submitButtonText, cancelButtonText, isValid, formReady, onValidateForm, isReadOnlyMode, hasButtons, onSubmit, labledButtons, onValidChange, onValidityChanged, onDataChanged, children, - ...formProps} = this.props; - return ( - <form {...formProps} ref={(form) => this.form = form} onSubmit={event => this.handleFormValidation(event)}> - <div className='validation-form-content'> - {children} - </div> - {hasButtons && - <ValidationButtons - labledButtons={labledButtons} - submitButtonText={submitButtonText} - cancelButtonText={cancelButtonText} - ref={buttons => this.buttons = buttons} - isReadOnlyMode={isReadOnlyMode}/> - } - </form> - ); - } + render() { + /* eslint-disable no-unused-vars */ + let { + submitButtonText, + cancelButtonText, + isValid, + formReady, + onValidateForm, + isReadOnlyMode, + hasButtons, + onSubmit, + labledButtons, + onValidChange, + onValidityChanged, + onDataChanged, + children, + ...formProps + } = this.props; + /* eslint-enable no-unused-vars */ + return ( + <form + {...formProps} + ref={form => (this.form = form)} + onSubmit={event => this.handleFormValidation(event)}> + <div className="validation-form-content">{children}</div> + {hasButtons && ( + <ValidationButtons + labledButtons={labledButtons} + submitButtonText={submitButtonText} + cancelButtonText={cancelButtonText} + ref={buttons => (this.buttons = buttons)} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </form> + ); + } } export default Form; diff --git a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx index 33cea933b5..a5d6f4fd7a 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Input.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Input.jsx @@ -25,191 +25,249 @@ import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import Datepicker from 'nfvo-components/datepicker/Datepicker.jsx'; class Input extends React.Component { + state = { + value: this.props.value, + checked: this.props.checked, + selectedValues: [] + }; - state = { - value: this.props.value, - checked: this.props.checked, - selectedValues: [] - }; + render() { + /* eslint-disable no-unused-vars */ + const { + label, + isReadOnlyMode, + value, + onBlur, + onKeyDown, + type, + disabled, + checked, + name + } = this.props; + const { + groupClassName, + isValid = true, + errorText, + isRequired, + overlayPos, + ...inputProps + } = this.props; + const { + dateFormat, + startDate, + endDate, + selectsStart, + selectsEnd + } = this.props; // Date Props + /* eslint-enable no-unused-vars */ + let wrapperClassName = + type !== 'radio' + ? 'validation-input-wrapper' + : 'validation-radio-wrapper'; + if (disabled) { + wrapperClassName += ' disabled'; + } + return ( + <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' && ( + <FormControl + bsClass={'form-control input-options-other'} + onChange={e => this.onChange(e)} + disabled={isReadOnlyMode || Boolean(disabled)} + onBlur={onBlur} + onKeyDown={onKeyDown} + value={value || ''} + 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']} + /> + )} - 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, 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'; - } - return( - <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' && - <FormControl - bsClass={'form-control input-options-other'} - onChange={(e) => this.onChange(e)} - disabled={isReadOnlyMode || Boolean(disabled)} - onBlur={onBlur} - onKeyDown={onKeyDown} - value={value || ''} - 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 + className="form-control input-options-other" + disabled={isReadOnlyMode || Boolean(disabled)} + value={value || ''} + onBlur={onBlur} + onKeyDown={onKeyDown} + componentClass={type} + onChange={e => this.onChange(e)} + inputRef={input => (this.input = input)} + data-test-id={this.props['data-test-id']} + /> + )} - {type === 'textarea' && - <FormControl - className='form-control input-options-other' - disabled={isReadOnlyMode || Boolean(disabled)} - value={value || ''} - onBlur={onBlur} - onKeyDown={onKeyDown} - componentClass={type} - onChange={(e) => this.onChange(e)} - inputRef={(input) => this.input = input} - data-test-id={this.props['data-test-id']}/>} + {type === 'checkbox' && ( + <Checkbox + className={classNames({ + required: isRequired, + 'has-error': !isValid + })} + onChange={e => this.onChangeCheckBox(e)} + disabled={isReadOnlyMode || Boolean(disabled)} + checked={checked} + data-test-id={this.props['data-test-id']}> + {label} + </Checkbox> + )} - {type === 'checkbox' && - <Checkbox - className={classNames({'required' : isRequired , 'has-error' : !isValid})} - onChange={(e)=>this.onChangeCheckBox(e)} - disabled={isReadOnlyMode || Boolean(disabled)} - checked={checked} - data-test-id={this.props['data-test-id']}>{label}</Checkbox>} + {type === 'radio' && ( + <Radio + name={name} + checked={checked} + disabled={isReadOnlyMode || Boolean(disabled)} + value={value} + onChange={isChecked => + this.onChangeRadio(isChecked) + } + inputRef={input => (this.input = input)} + label={label} + data-test-id={this.props['data-test-id']} + /> + )} + {type === 'select' && ( + <FormControl + onClick={e => this.optionSelect(e)} + className="custom-select" + componentClass={type} + 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> + ); + } - {type === 'radio' && - <Radio name={name} - checked={checked} - disabled={isReadOnlyMode || Boolean(disabled)} - value={value} - onChange={(isChecked)=>this.onChangeRadio(isChecked)} - inputRef={(input) => this.input = input} - label={label} - data-test-id={this.props['data-test-id']} />} - {type === 'select' && - <FormControl onClick={ (e) => this.optionSelect(e) } - className='custom-select' - componentClass={type} - 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> - ); - } + getValue() { + return this.props.type !== 'select' + ? this.state.value + : this.state.selectedValues; + } - getValue() { - return this.props.type !== 'select' ? this.state.value : this.state.selectedValues; - } + getChecked() { + return this.state.checked; + } - getChecked() { - return this.state.checked; - } + optionSelect(e) { + let selectedValues = []; + if (e.target.value) { + selectedValues.push(e.target.value); + } + this.setState({ + selectedValues + }); + } - optionSelect(e) { - let selectedValues = []; - if (e.target.value) { - selectedValues.push(e.target.value); - } - this.setState({ - selectedValues - }); - } + onChange(e) { + const { onChange, type } = this.props; + let value = e.target.value; + if (type === 'number') { + if (value === '') { + value = undefined; + } else { + value = Number(value); + } + } + this.setState({ + value + }); + onChange(value); + } - onChange(e) { - const {onChange, type} = this.props; - let value = e.target.value; - if (type === 'number') { - if (value === '') { - value = undefined; - } else { - value = Number(value); - } - } - this.setState({ - value - }); - onChange(value); - } + onChangeCheckBox(e) { + let { onChange } = this.props; + let checked = e.target.checked; + this.setState({ + checked + }); + onChange(checked); + } - onChangeCheckBox(e) { - let {onChange} = this.props; - let checked = e.target.checked; - this.setState({ - checked - }); - onChange(checked); - } + onChangeRadio(isChecked) { + let { onChange } = this.props; + this.setState({ + checked: isChecked + }); + onChange(this.state.value); + } - onChangeRadio(isChecked) { - let {onChange} = this.props; - this.setState({ - checked: isChecked - }); - onChange(this.state.value); - } + focus() { + ReactDOM.findDOMNode(this.input).focus(); + } - focus() { - ReactDOM.findDOMNode(this.input).focus(); - } + renderErrorOverlay() { + let position = 'right'; + const { errorText = '', isValid = true, type, overlayPos } = this.props; - renderErrorOverlay() { - let position = 'right'; - const {errorText = '', isValid = true, type, overlayPos} = this.props; - - if (overlayPos) { - position = overlayPos; - } - else if (type === 'text' - || type === 'email' - || type === 'number' - || type === 'radio' - || type === 'password' - || type === 'date') { - position = 'bottom'; - } - - return ( - <Overlay - show={!isValid} - placement={position} - target={() => { - let target = ReactDOM.findDOMNode(this.input); - return target.offsetParent ? target : undefined; - }} - container={this}> - <Tooltip - id={`error-${errorText.replace(' ', '-')}`} - className='validation-error-message'> - {errorText} - </Tooltip> - </Overlay> - ); - } + if (overlayPos) { + position = overlayPos; + } else if ( + type === 'text' || + type === 'email' || + type === 'number' || + type === 'radio' || + type === 'password' || + type === 'date' + ) { + position = 'bottom'; + } + return ( + <Overlay + show={!isValid} + placement={position} + target={() => { + let target = ReactDOM.findDOMNode(this.input); + return target.offsetParent ? target : undefined; + }} + container={this}> + <Tooltip + id={`error-${errorText.replace(' ', '-')}`} + className="validation-error-message"> + {errorText} + </Tooltip> + </Overlay> + ); + } } -export default Input; +export default Input; diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx index 11b07ba9da..019b6a5c70 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/InputOptions.jsx @@ -22,260 +22,341 @@ import Select from 'nfvo-components/input/SelectInput.jsx'; import Overlay from 'react-bootstrap/lib/Overlay.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; -export const other = {OTHER: 'Other'}; +export const other = { OTHER: 'Other' }; class InputOptions extends React.Component { + static propTypes = { + values: PropTypes.arrayOf( + PropTypes.shape({ + enum: PropTypes.string, + title: PropTypes.string + }) + ), + isEnabledOther: PropTypes.bool, + label: PropTypes.string, + selectedValue: PropTypes.string, + multiSelectedEnum: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.array + ]), + selectedEnum: PropTypes.string, + otherValue: PropTypes.string, + overlayPos: PropTypes.string, + onEnumChange: PropTypes.func, + onOtherChange: PropTypes.func, + onBlur: PropTypes.func, + isRequired: PropTypes.bool, + isMultiSelect: PropTypes.bool, + isValid: PropTypes.bool, + disabled: PropTypes.bool + }; - static propTypes = { - values: PropTypes.arrayOf(PropTypes.shape({ - enum: PropTypes.string, - title: PropTypes.string - })), - isEnabledOther: PropTypes.bool, - label: PropTypes.string, - selectedValue: PropTypes.string, - multiSelectedEnum: PropTypes.oneOfType([ - PropTypes.string, - PropTypes.array - ]), - selectedEnum: PropTypes.string, - otherValue: PropTypes.string, - overlayPos: PropTypes.string, - onEnumChange: PropTypes.func, - onOtherChange: PropTypes.func, - onBlur: PropTypes.func, - isRequired: PropTypes.bool, - isMultiSelect: PropTypes.bool, - isValid: PropTypes.bool, - disabled: PropTypes.bool - }; + state = { + otherInputDisabled: !this.props.otherValue + }; - state = { - otherInputDisabled: !this.props.otherValue - }; + oldProps = { + selectedEnum: '', + otherValue: '', + multiSelectedEnum: [] + }; - oldProps = { - selectedEnum: '', - otherValue: '', - multiSelectedEnum: [] - }; + render() { + let { + label, + isRequired, + values, + otherValue, + onOtherChange, + isMultiSelect, + onBlur, + multiSelectedEnum, + selectedEnum, + isValid, + children, + isReadOnlyMode + } = this.props; + const dataTestId = this.props['data-test-id'] + ? { 'data-test-id': this.props['data-test-id'] } + : {}; + let currentMultiSelectedEnum = []; + let currentSelectedEnum = ''; + let otherInputDisabled = + (isMultiSelect && + (multiSelectedEnum === undefined || + multiSelectedEnum.length === 0 || + multiSelectedEnum[0] !== other.OTHER)) || + (!isMultiSelect && + (selectedEnum === undefined || selectedEnum !== other.OTHER)); + if (isMultiSelect) { + currentMultiSelectedEnum = multiSelectedEnum; + if (!otherInputDisabled) { + currentSelectedEnum = multiSelectedEnum + ? multiSelectedEnum.toString() + : undefined; + } + } else if (selectedEnum) { + currentSelectedEnum = selectedEnum; + } + if (!onBlur) { + onBlur = () => {}; + } - render() { - let {label, isRequired, values, otherValue, onOtherChange, isMultiSelect, onBlur, multiSelectedEnum, selectedEnum, isValid, children, isReadOnlyMode} = this.props; - const dataTestId = this.props['data-test-id'] ? {'data-test-id': this.props['data-test-id']} : {}; - let currentMultiSelectedEnum = []; - let currentSelectedEnum = ''; - let otherInputDisabled = (isMultiSelect && (multiSelectedEnum === undefined || multiSelectedEnum.length === 0 || multiSelectedEnum[0] !== other.OTHER)) - || (!isMultiSelect && (selectedEnum === undefined || selectedEnum !== other.OTHER)); - if (isMultiSelect) { - currentMultiSelectedEnum = multiSelectedEnum; - if(!otherInputDisabled) { - currentSelectedEnum = multiSelectedEnum ? multiSelectedEnum.toString() : undefined; - } - } - else if(selectedEnum){ - currentSelectedEnum = selectedEnum; - } - if (!onBlur) { - onBlur = () => {}; - } + return ( + <div className="validation-input-wrapper"> + <div + className={classNames('form-group', { + required: isRequired, + 'has-error': !isValid + })}> + {label && <label className="control-label">{label}</label>} + {isMultiSelect && otherInputDisabled ? ( + <Select + {...dataTestId} + ref={input => (this.input = input)} + value={currentMultiSelectedEnum} + className="options-input" + clearable={false} + required={isRequired} + disabled={ + isReadOnlyMode || Boolean(this.props.disabled) + } + onBlur={() => onBlur()} + onMultiSelectChanged={value => + this.multiSelectEnumChanged(value) + } + options={this.renderMultiSelectOptions(values)} + multi + /> + ) : ( + <div + className={classNames('input-options', { + 'has-error': !isValid + })}> + <select + {...dataTestId} + ref={input => (this.input = input)} + label={label} + className="form-control input-options-select" + value={currentSelectedEnum} + style={{ + width: otherInputDisabled ? '100%' : '100px' + }} + onBlur={() => onBlur()} + disabled={ + isReadOnlyMode || + Boolean(this.props.disabled) + } + onChange={value => this.enumChanged(value)} + type="select"> + {children || + (values && + values.length && + values.map((val, index) => + this.renderOptions(val, index) + ))} + {onOtherChange && ( + <option key="other" value={other.OTHER}> + {i18n(other.OTHER)} + </option> + )} + </select> - return( - <div className='validation-input-wrapper' > - <div className={classNames('form-group', {'required' : isRequired, 'has-error' : !isValid})} > - {label && <label className='control-label'>{label}</label>} - {isMultiSelect && otherInputDisabled ? - <Select - {...dataTestId} - ref={(input) => this.input = input} - value={currentMultiSelectedEnum} - className='options-input' - clearable={false} - required={isRequired} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - onBlur={() => onBlur()} - onMultiSelectChanged={value => this.multiSelectEnumChanged(value)} - options={this.renderMultiSelectOptions(values)} - multi/> : - <div className={classNames('input-options',{'has-error' : !isValid})} > - <select - {...dataTestId} - ref={(input) => this.input = input} - label={label} - className='form-control input-options-select' - value={currentSelectedEnum} - style={{'width' : otherInputDisabled ? '100%' : '100px'}} - onBlur={() => onBlur()} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - onChange={ value => this.enumChanged(value)} - type='select'> - {children || (values && values.length && values.map((val, index) => this.renderOptions(val, index)))} - {onOtherChange && <option key='other' value={other.OTHER}>{i18n(other.OTHER)}</option>} - </select> + {!otherInputDisabled && ( + <div className="input-options-separator" /> + )} + <input + className="form-control input-options-other" + placeholder={i18n('other')} + ref={otherValue => + (this.otherValue = otherValue) + } + style={{ + display: otherInputDisabled + ? 'none' + : 'block' + }} + disabled={ + isReadOnlyMode || + Boolean(this.props.disabled) + } + value={otherValue || ''} + onBlur={() => onBlur()} + onChange={() => this.changedOtherInput()} + /> + </div> + )} + </div> + {this.renderErrorOverlay()} + </div> + ); + } - {!otherInputDisabled && <div className='input-options-separator'/>} - <input - className='form-control input-options-other' - placeholder={i18n('other')} - ref={(otherValue) => this.otherValue = otherValue} - style={{'display' : otherInputDisabled ? 'none' : 'block'}} - disabled={isReadOnlyMode || Boolean(this.props.disabled)} - value={otherValue || ''} - onBlur={() => onBlur()} - onChange={() => this.changedOtherInput()}/> - </div> - } - </div> - { this.renderErrorOverlay() } - </div> - ); - } + renderOptions(val, index) { + return ( + <option key={index} value={val.enum}> + {val.title} + </option> + ); + } - renderOptions(val, index){ - return ( - <option key={index} value={val.enum}>{val.title}</option> - ); - } + renderMultiSelectOptions(values) { + let { onOtherChange } = this.props; + let optionsList = []; + if (onOtherChange) { + optionsList = values + .map(option => { + return { + label: option.title, + value: option.enum + }; + }) + .concat([ + { + label: i18n(other.OTHER), + value: i18n(other.OTHER) + } + ]); + } else { + optionsList = values.map(option => { + return { + label: option.title, + value: option.enum + }; + }); + } + if (optionsList.length > 0 && optionsList[0].value === '') { + optionsList.shift(); + } + return optionsList; + } + renderErrorOverlay() { + let position = 'right'; + const { errorText = '', isValid = true, type, overlayPos } = this.props; - renderMultiSelectOptions(values) { - let {onOtherChange} = this.props; - let optionsList = []; - if (onOtherChange) { - optionsList = values.map(option => { - return { - label: option.title, - value: option.enum, - }; - }).concat([{ - label: i18n(other.OTHER), - value: i18n(other.OTHER), - }]); - } - else { - optionsList = values.map(option => { - return { - label: option.title, - value: option.enum, - }; - }); - } - if (optionsList.length > 0 && optionsList[0].value === '') { - optionsList.shift(); - } - return optionsList; - } + if (overlayPos) { + position = overlayPos; + } else if ( + type === 'text' || + type === 'email' || + type === 'number' || + type === 'password' + ) { + position = 'bottom'; + } - renderErrorOverlay() { - let position = 'right'; - const {errorText = '', isValid = true, type, overlayPos} = this.props; + return ( + <Overlay + show={!isValid} + placement={position} + target={() => { + let { otherInputDisabled } = this.state; + let target = otherInputDisabled + ? ReactDOM.findDOMNode(this.input) + : ReactDOM.findDOMNode(this.otherValue); + return target.offsetParent ? target : undefined; + }} + container={this}> + <Tooltip + id={`error-${errorText.replace(' ', '-')}`} + className="validation-error-message"> + {errorText} + </Tooltip> + </Overlay> + ); + } - if (overlayPos) { - position = overlayPos; - } - else if (type === 'text' - || type === 'email' - || type === 'number' - || type === 'password') { - position = 'bottom'; - } + getValue() { + let res = ''; + let { isMultiSelect } = this.props; + let { otherInputDisabled } = this.state; - return ( - <Overlay - show={!isValid} - placement={position} - target={() => { - let {otherInputDisabled} = this.state; - let target = otherInputDisabled ? ReactDOM.findDOMNode(this.input) : ReactDOM.findDOMNode(this.otherValue); - return target.offsetParent ? target : undefined; - }} - container={this}> - <Tooltip - id={`error-${errorText.replace(' ', '-')}`} - className='validation-error-message'> - {errorText} - </Tooltip> - </Overlay> - ); - } + if (otherInputDisabled) { + res = isMultiSelect ? this.input.getValue() : this.input.value; + } else { + res = this.otherValue.value; + } + return res; + } - getValue() { - let res = ''; - let {isMultiSelect} = this.props; - let {otherInputDisabled} = this.state; + enumChanged() { + let enumValue = this.input.value; + let { + onEnumChange, + onOtherChange, + isMultiSelect, + onChange + } = this.props; + this.setState({ + otherInputDisabled: + !Boolean(onOtherChange) || enumValue !== other.OTHER + }); - if (otherInputDisabled) { - res = isMultiSelect ? this.input.getValue() : this.input.value; - } else { - res = this.otherValue.value; - } - return res; - } + let value = isMultiSelect ? [enumValue] : enumValue; + if (onEnumChange) { + onEnumChange(value); + } + if (onChange) { + onChange(value); + } + } - enumChanged() { - let enumValue = this.input.value; - let {onEnumChange, onOtherChange, isMultiSelect, onChange} = this.props; - this.setState({ - otherInputDisabled: !Boolean(onOtherChange) || enumValue !== other.OTHER - }); + multiSelectEnumChanged(enumValue) { + let { onEnumChange, onOtherChange } = this.props; + let selectedValues = enumValue.map(enumVal => { + return enumVal.value; + }); - let value = isMultiSelect ? [enumValue] : enumValue; - if (onEnumChange) { - onEnumChange(value); - } - if (onChange) { - onChange(value); - } - } + if (this.state.otherInputDisabled === false) { + selectedValues.shift(); + } else if (selectedValues.includes(i18n(other.OTHER))) { + selectedValues = [i18n(other.OTHER)]; + } - multiSelectEnumChanged(enumValue) { - let {onEnumChange, onOtherChange} = this.props; - let selectedValues = enumValue.map(enumVal => { - return enumVal.value; - }); + this.setState({ + otherInputDisabled: + !Boolean(onOtherChange) || + !selectedValues.includes(i18n(other.OTHER)) + }); + onEnumChange(selectedValues); + } - if (this.state.otherInputDisabled === false) { - selectedValues.shift(); - } - else if (selectedValues.includes(i18n(other.OTHER))) { - selectedValues = [i18n(other.OTHER)]; - } + changedOtherInput() { + let { onOtherChange } = this.props; + onOtherChange(this.otherValue.value); + } - this.setState({ - otherInputDisabled: !Boolean(onOtherChange) || !selectedValues.includes(i18n(other.OTHER)) - }); - onEnumChange(selectedValues); - } - - changedOtherInput() { - let {onOtherChange} = this.props; - onOtherChange(this.otherValue.value); - } - - componentDidUpdate() { - let {otherValue, selectedEnum, onInputChange, multiSelectedEnum} = this.props; - if (this.oldProps.otherValue !== otherValue - || this.oldProps.selectedEnum !== selectedEnum - || this.oldProps.multiSelectedEnum !== multiSelectedEnum) { - this.oldProps = { - otherValue, - selectedEnum, - multiSelectedEnum - }; - onInputChange(); - } - } - - static getTitleByName(values, name) { - for (let key of Object.keys(values)) { - let option = values[key].find(option => option.enum === name); - if (option) { - return option.title; - } - } - return name; - } + componentDidUpdate() { + let { + otherValue, + selectedEnum, + onInputChange, + multiSelectedEnum + } = this.props; + if ( + this.oldProps.otherValue !== otherValue || + this.oldProps.selectedEnum !== selectedEnum || + this.oldProps.multiSelectedEnum !== multiSelectedEnum + ) { + this.oldProps = { + otherValue, + selectedEnum, + multiSelectedEnum + }; + onInputChange(); + } + } + static getTitleByName(values, name) { + for (let key of Object.keys(values)) { + let option = values[key].find(option => option.enum === name); + if (option) { + return option.title; + } + } + return name; + } } export default InputOptions; diff --git a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx index e440fcda69..3e0bb32ca9 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/InputWrapper.jsx @@ -22,114 +22,149 @@ import FormGroup from 'react-bootstrap/lib/FormGroup.js'; import FormControl from 'react-bootstrap/lib/FormControl.js'; class InputWrapper extends React.Component { - - state = { - value: this.props.value, - checked: this.props.checked, - selectedValues: [] - } - - render() { - const {label, hasError, validations = {}, isReadOnlyMode, value, onBlur, onKeyDown, type, disabled, checked, name} = this.props; - const {groupClassName, ...inputProps} = this.props; - return( - <FormGroup className={classNames('form-group', [groupClassName], {'required' : validations.required , 'has-error' : hasError})} > - {(label && (type !== 'checkbox' && type !== 'radio')) && <label className='control-label'>{label}</label>} - {(type === 'text' || type === 'number') && - <FormControl - bsClass={'form-control input-options-other'} - onChange={(e) => this.onChange(e)} - disabled={isReadOnlyMode || Boolean(disabled)} - onBlur={onBlur} - onKeyDown={onKeyDown} - value={value || ''} - ref={(input) => this.inputWrapper = input} - type={type} - data-test-id={this.props['data-test-id']}/>} - - {type === 'textarea' && - <FormControl - className='form-control input-options-other' - disabled={isReadOnlyMode || Boolean(disabled)} - value={value || ''} - onBlur={onBlur} - onKeyDown={onKeyDown} - componentClass={type} - onChange={(e) => this.onChange(e)} - data-test-id={this.props['data-test-id']}/>} - - {type === 'checkbox' && - <Checkbox - className={classNames({'required' : validations.required , 'has-error' : hasError})} - onChange={(e)=>this.onChangeCheckBox(e)} - disabled={isReadOnlyMode || Boolean(disabled)} - checked={value} - data-test-id={this.props['data-test-id']}>{label}</Checkbox>} - - {type === 'radio' && - <Radio name={name} - checked={checked} - disabled={isReadOnlyMode || Boolean(disabled)} - value={value} - ref={(input) => this.inputWrapper = input} - onChange={(isChecked)=>this.onChangeRadio(isChecked)} label={label} - data-test-id={this.props['data-test-id']} />} - {type === 'select' && - <FormControl onClick={ (e) => this.optionSelect(e) } - componentClass={type} - name={name} {...inputProps} - data-test-id={this.props['data-test-id']}/>} - - </FormGroup> - - ); - } - - getValue() { - return this.props.type !== 'select' ? this.state.value : this.state.selectedValues; - } - - getChecked() { - return this.state.checked; - } - - optionSelect(e) { - let selectedValues = []; - if (e.target.value) { - selectedValues.push(e.target.value); - } - this.setState({ - selectedValues - }); - } - - onChange(e) { - let {onChange} = this.props; - this.setState({ - value: e.target.value - }); - onChange(e.target.value); - } - - onChangeCheckBox(e) { - let {onChange} = this.props; - this.setState({ - checked: e.target.checked - }); - onChange(e.target.checked); - } - - onChangeRadio(isChecked) { - let {onChange} = this.props; - this.setState({ - checked: isChecked - }); - onChange(this.state.value); - } - - focus() { - ReactDOM.findDOMNode(this.inputWrapper).focus(); - } - + state = { + value: this.props.value, + checked: this.props.checked, + selectedValues: [] + }; + + render() { + const { + label, + hasError, + validations = {}, + isReadOnlyMode, + value, + onBlur, + onKeyDown, + type, + disabled, + checked, + name + } = this.props; + const { groupClassName, ...inputProps } = this.props; + return ( + <FormGroup + className={classNames('form-group', [groupClassName], { + required: validations.required, + 'has-error': hasError + })}> + {label && + (type !== 'checkbox' && type !== 'radio') && ( + <label className="control-label">{label}</label> + )} + {(type === 'text' || type === 'number') && ( + <FormControl + bsClass={'form-control input-options-other'} + onChange={e => this.onChange(e)} + disabled={isReadOnlyMode || Boolean(disabled)} + onBlur={onBlur} + onKeyDown={onKeyDown} + value={value || ''} + ref={input => (this.inputWrapper = input)} + type={type} + data-test-id={this.props['data-test-id']} + /> + )} + + {type === 'textarea' && ( + <FormControl + className="form-control input-options-other" + disabled={isReadOnlyMode || Boolean(disabled)} + value={value || ''} + onBlur={onBlur} + onKeyDown={onKeyDown} + componentClass={type} + onChange={e => this.onChange(e)} + data-test-id={this.props['data-test-id']} + /> + )} + + {type === 'checkbox' && ( + <Checkbox + className={classNames({ + required: validations.required, + 'has-error': hasError + })} + onChange={e => this.onChangeCheckBox(e)} + disabled={isReadOnlyMode || Boolean(disabled)} + checked={value} + data-test-id={this.props['data-test-id']}> + {label} + </Checkbox> + )} + + {type === 'radio' && ( + <Radio + name={name} + checked={checked} + disabled={isReadOnlyMode || Boolean(disabled)} + value={value} + ref={input => (this.inputWrapper = input)} + onChange={isChecked => this.onChangeRadio(isChecked)} + label={label} + data-test-id={this.props['data-test-id']} + /> + )} + {type === 'select' && ( + <FormControl + onClick={e => this.optionSelect(e)} + componentClass={type} + name={name} + {...inputProps} + data-test-id={this.props['data-test-id']} + /> + )} + </FormGroup> + ); + } + + getValue() { + return this.props.type !== 'select' + ? this.state.value + : this.state.selectedValues; + } + + getChecked() { + return this.state.checked; + } + + optionSelect(e) { + let selectedValues = []; + if (e.target.value) { + selectedValues.push(e.target.value); + } + this.setState({ + selectedValues + }); + } + + onChange(e) { + let { onChange } = this.props; + this.setState({ + value: e.target.value + }); + onChange(e.target.value); + } + + onChangeCheckBox(e) { + let { onChange } = this.props; + this.setState({ + checked: e.target.checked + }); + onChange(e.target.checked); + } + + onChangeRadio(isChecked) { + let { onChange } = this.props; + this.setState({ + checked: isChecked + }); + onChange(this.state.value); + } + + focus() { + ReactDOM.findDOMNode(this.inputWrapper).focus(); + } } -export default InputWrapper; +export default InputWrapper; diff --git a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx index 0982c133e6..429985a902 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/Tabs.jsx @@ -16,64 +16,76 @@ import React from 'react'; import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; -import {default as SDCTabs} from 'sdc-ui/lib/react/Tabs.js'; +import { default as SDCTabs } from 'sdc-ui/lib/react/Tabs.js'; import Overlay from 'react-bootstrap/lib/Overlay.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -export default -class Tabs extends React.Component { +export default class Tabs extends React.Component { + static propTypes = { + children: PropTypes.node + }; - static propTypes = { - children: PropTypes.node - }; + cloneTab(element) { + const { invalidTabs } = this.props; + return React.cloneElement(element, { + key: element.props.tabId, + className: + invalidTabs.indexOf(element.props.tabId) > -1 + ? 'invalid-tab' + : 'valid-tab' + }); + } - cloneTab(element) { - const {invalidTabs} = this.props; - return React.cloneElement( - element, - { - key: element.props.tabId, - className: invalidTabs.indexOf(element.props.tabId) > -1 ? 'invalid-tab' : 'valid-tab' - } - ); - } + showTabsError() { + const { invalidTabs } = this.props; + const showError = + (invalidTabs.length === 1 && + invalidTabs[0] !== this.props.activeTab) || + invalidTabs.length > 1; + return showError; + } - showTabsError() { - const {invalidTabs} = this.props; - const showError = ((invalidTabs.length === 1 && invalidTabs[0] !== this.props.activeTab) || (invalidTabs.length > 1)); - return showError; - } - - render() { - // eslint-disable-next-line no-unused-vars - let {invalidTabs, ...tabProps} = this.props; - return ( - <div> - <SDCTabs {...tabProps} ref='tabsList' id='tabsList' > - {this.props.children.map(element => this.cloneTab(element))} - </SDCTabs> - <Overlay - animation={false} - show={this.showTabsError()} - placement='bottom' - target={() => { - let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.sdc-tab-active):nth-of-type(n)'); - return target && target.offsetParent ? target : undefined; - } - } - container={() => { - let target = ReactDOM.findDOMNode(this.refs.tabsList).querySelector('ul > li.invalid-tab:not(.sdc-tab-active):nth-of-type(n)'); - return target && target.offsetParent ? target.offsetParent : this; - }}> - <Tooltip - id='error-some-tabs-contain-errors' - className='validation-error-message'> - {i18n('One or more tabs are invalid')} - </Tooltip> - </Overlay> - </div> - ); - } + render() { + // eslint-disable-next-line no-unused-vars + let { invalidTabs, ...tabProps } = this.props; + return ( + <div> + <SDCTabs {...tabProps} ref="tabsList" id="tabsList"> + {this.props.children.map(element => this.cloneTab(element))} + </SDCTabs> + <Overlay + animation={false} + show={this.showTabsError()} + placement="bottom" + target={() => { + let target = ReactDOM.findDOMNode( + this.refs.tabsList + ).querySelector( + 'ul > li.invalid-tab:not(.sdc-tab-active):nth-of-type(n)' + ); + return target && target.offsetParent + ? target + : undefined; + }} + container={() => { + let target = ReactDOM.findDOMNode( + this.refs.tabsList + ).querySelector( + 'ul > li.invalid-tab:not(.sdc-tab-active):nth-of-type(n)' + ); + return target && target.offsetParent + ? target.offsetParent + : this; + }}> + <Tooltip + id="error-some-tabs-contain-errors" + className="validation-error-message"> + {i18n('One or more tabs are invalid')} + </Tooltip> + </Overlay> + </div> + ); + } } diff --git a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx index 151d3fe859..e460f68a98 100644 --- a/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx +++ b/openecomp-ui/src/nfvo-components/input/validation/ValidationButtons.jsx @@ -27,32 +27,63 @@ 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: PropTypes.bool.isRequired, + isReadOnlyMode: PropTypes.bool, + submitButtonText: PropTypes.string, + cancelButtonText: PropTypes.string + }; - static propTypes = { - labledButtons: PropTypes.bool.isRequired, - isReadOnlyMode: PropTypes.bool, - submitButtonText: PropTypes.string, - cancelButtonText: PropTypes.string - }; + state = { + isValid: this.props.formValid + }; - state = { - isValid: this.props.formValid - }; - - render() { - 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 type='submit' data-test-id='form-submit-button' disabled={!this.state.isValid}>{submitBtn}</Button> - <Button btnType='outline' type='reset' data-test-id='form-close-button'>{closeBtn}</Button> - </div> - : <Button btnType='outline' type='reset' data-test-id='form-close-button'>{i18n('Close')}</Button> - } - </div> - ); - } + render() { + 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 + type="submit" + data-test-id="form-submit-button" + disabled={!this.state.isValid}> + {submitBtn} + </Button> + <Button + btnType="outline" + type="reset" + data-test-id="form-close-button"> + {closeBtn} + </Button> + </div> + ) : ( + <Button + btnType="outline" + type="reset" + data-test-id="form-close-button"> + {i18n('Close')} + </Button> + )} + </div> + ); + } } export default ValidationButtons; diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx index 60c559a3d1..359af9d3b8 100644 --- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx +++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemView.jsx @@ -19,50 +19,78 @@ import classnames from 'classnames'; import i18n from 'nfvo-utils/i18n/i18n.js'; 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'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; class ListEditorItem extends React.Component { - static propTypes = { - onSelect: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), - onDelete: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), - onEdit: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), - children: PropTypes.node, - isReadOnlyMode: PropTypes.bool - }; + static propTypes = { + onSelect: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), + onDelete: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), + onEdit: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]), + children: PropTypes.node, + isReadOnlyMode: PropTypes.bool + }; - render() { - let {onDelete, onSelect, onEdit, children, isReadOnlyMode} = this.props; - let isAbilityToDelete = isReadOnlyMode === undefined ? true : !isReadOnlyMode; - return ( - <div className={classnames('list-editor-item-view', {'selectable': Boolean(onSelect)})} data-test-id='list-editor-item'> - <div className='list-editor-item-view-content' onClick={onSelect}> - {children} - </div> - {(onEdit || onDelete) && <div className='list-editor-item-view-controller'> - {onEdit && <SVGIcon name='sliders' onClick={() => this.onClickedItem(onEdit)}/>} - {onDelete && isAbilityToDelete && <SVGIcon name='trashO' data-test-id='delete-list-item' onClick={() => this.onClickedItem(onDelete)}/>} - </div>} - </div> - ); - } + render() { + let { + onDelete, + onSelect, + onEdit, + children, + isReadOnlyMode + } = this.props; + let isAbilityToDelete = + isReadOnlyMode === undefined ? true : !isReadOnlyMode; + return ( + <div + className={classnames('list-editor-item-view', { + selectable: Boolean(onSelect) + })} + data-test-id="list-editor-item"> + <div + className="list-editor-item-view-content" + onClick={onSelect}> + {children} + </div> + {(onEdit || onDelete) && ( + <div className="list-editor-item-view-controller"> + {onEdit && ( + <SVGIcon + name="sliders" + onClick={() => this.onClickedItem(onEdit)} + /> + )} + {onDelete && + isAbilityToDelete && ( + <SVGIcon + name="trashO" + data-test-id="delete-list-item" + onClick={() => this.onClickedItem(onDelete)} + /> + )} + </div> + )} + </div> + ); + } - onClickedItem(callBackFunc) { - if(typeof callBackFunc === 'function') { - let {isCheckedOut} = this.props; - if (isCheckedOut === false) { - store.dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Error'), - msg: i18n('This item is checkedin/submitted, Click Check Out to continue') - } - }); - } - else { - callBackFunc(); - } - } - } + onClickedItem(callBackFunc) { + if (typeof callBackFunc === 'function') { + let { isCheckedOut } = this.props; + if (isCheckedOut === false) { + store.dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Error'), + msg: i18n( + 'This item is checkedin/submitted, Click Check Out to continue' + ) + } + }); + } else { + callBackFunc(); + } + } + } } export default ListEditorItem; diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx index 839f9a504a..509ea176a5 100644 --- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx +++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorItemViewField.jsx @@ -15,10 +15,8 @@ */ import React from 'react'; -export const ListEditorItemViewField = ({children}) => ( - <div className='list-editor-item-view-field'> - {children} - </div> +export const ListEditorItemViewField = ({ children }) => ( + <div className="list-editor-item-view-field">{children}</div> ); export default ListEditorItemViewField; diff --git a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx index 16823b7dc5..f71372ce1a 100644 --- a/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx +++ b/openecomp-ui/src/nfvo-components/listEditor/ListEditorView.jsx @@ -19,69 +19,107 @@ import Button from 'sdc-ui/lib/react/Button.js'; import classnames from 'classnames'; import ExpandableInput from 'nfvo-components/input/ExpandableInput.jsx'; -const ListEditorHeader = ({onAdd, isReadOnlyMode, title, plusButtonTitle}) => { - return ( - <div className='list-editor-view-header'> - {title && <div className='list-editor-view-title'>{title}</div>} - <div> - { onAdd && - <Button data-test-id='add-button' iconName='plusThin' btnType='link' onClick={onAdd} disabled={isReadOnlyMode === true}>{plusButtonTitle}</Button> - } - </div> - </div> - ); +const ListEditorHeader = ({ + onAdd, + isReadOnlyMode, + title, + plusButtonTitle +}) => { + return ( + <div className="list-editor-view-header"> + {title && <div className="list-editor-view-title">{title}</div>} + <div> + {onAdd && ( + <Button + data-test-id="add-button" + iconName="plusThin" + btnType="link" + onClick={onAdd} + disabled={isReadOnlyMode === true}> + {plusButtonTitle} + </Button> + )} + </div> + </div> + ); }; -const ListEditorScroller = ({children, twoColumns}) => { - return ( - <div className='list-editor-view-list-scroller'> - <div className={classnames('list-editor-view-list', {'two-columns': twoColumns})}> - {children} - </div> - </div> - ); +const ListEditorScroller = ({ children, twoColumns }) => { + return ( + <div className="list-editor-view-list-scroller"> + <div + className={classnames('list-editor-view-list', { + 'two-columns': twoColumns + })}> + {children} + </div> + </div> + ); }; -const FilterWrapper = ({onFilter, filterValue}) => { - return ( - <div className='expandble-search-wrapper'> - <ExpandableInput - onChange={onFilter} - iconType='search' - value={filterValue}/> - </div> - ); +const FilterWrapper = ({ onFilter, filterValue }) => { + return ( + <div className="expandble-search-wrapper"> + <ExpandableInput + onChange={onFilter} + iconType="search" + value={filterValue} + /> + </div> + ); }; class ListEditorView extends React.Component { + static defaultProps = { + className: '', + twoColumns: false + }; - static defaultProps = { - className: '', - twoColumns: false - }; - - static propTypes = { - title: PropTypes.string, - plusButtonTitle: PropTypes.string, - children: PropTypes.node, - filterValue: PropTypes.string, - onFilter: PropTypes.func, - className: PropTypes.string, - isReadOnlyMode: PropTypes.bool, - placeholder: PropTypes.string, - twoColumns: PropTypes.bool - }; - - render() { - let {title, plusButtonTitle, onAdd, children, onFilter, className, isReadOnlyMode, twoColumns, filterValue} = this.props; - return ( - <div className={classnames('list-editor-view', className)}> - <ListEditorHeader onAdd={onAdd} isReadOnlyMode={isReadOnlyMode} plusButtonTitle={plusButtonTitle} title={title}/> - {onFilter && (children.length || filterValue) && <FilterWrapper onFilter={onFilter} filterValue={filterValue}/>} - <ListEditorScroller children={children} twoColumns={twoColumns}/> - </div> - ); - } + static propTypes = { + title: PropTypes.string, + plusButtonTitle: PropTypes.string, + children: PropTypes.node, + filterValue: PropTypes.string, + onFilter: PropTypes.func, + className: PropTypes.string, + isReadOnlyMode: PropTypes.bool, + placeholder: PropTypes.string, + twoColumns: PropTypes.bool + }; + render() { + let { + title, + plusButtonTitle, + onAdd, + children, + onFilter, + className, + isReadOnlyMode, + twoColumns, + filterValue + } = this.props; + return ( + <div className={classnames('list-editor-view', className)}> + <ListEditorHeader + onAdd={onAdd} + isReadOnlyMode={isReadOnlyMode} + plusButtonTitle={plusButtonTitle} + title={title} + /> + {onFilter && + (children.length || filterValue) && ( + <FilterWrapper + onFilter={onFilter} + filterValue={filterValue} + /> + )} + <ListEditorScroller + children={children} + twoColumns={twoColumns} + /> + </div> + ); + } } export default ListEditorView; diff --git a/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js index 81125c84ba..67258c956d 100644 --- a/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js +++ b/openecomp-ui/src/nfvo-components/listEditor/listEditor.stories.js @@ -1,27 +1,25 @@ import React from 'react'; -import {storiesOf, action} from '@kadira/storybook'; +import { storiesOf, action } from '@kadira/storybook'; import ListEditorView from './ListEditorView.jsx'; import ListEditorItemView from './ListEditorItemView.jsx'; import ListEditorItemField from './ListEditorItemViewField.jsx'; -import {text, number} from '@kadira/storybook-addon-knobs'; -import {withKnobs} from '@kadira/storybook-addon-knobs'; +import { text, number } from '@kadira/storybook-addon-knobs'; +import { withKnobs } from '@kadira/storybook-addon-knobs'; -function makeChildren({onEdit = false, onDelete = false} = {}) { - return ( - [...Array(number('Items', 2)).keys()].map(index => ( - <ListEditorItemView - key={index} - onEdit={onEdit ? onEdit : undefined} - onDelete={onDelete ? onDelete : undefined}> - <ListEditorItemField> - <div>{text('field 1', 'Lorum Ipsum')}</div> - </ListEditorItemField> - <ListEditorItemField> - <div>{text('field 2', 'Lorum Ipsum')}</div> - </ListEditorItemField> - </ListEditorItemView>) - ) - ); +function makeChildren({ onEdit = false, onDelete = false } = {}) { + return [...Array(number('Items', 2)).keys()].map(index => ( + <ListEditorItemView + key={index} + onEdit={onEdit ? onEdit : undefined} + onDelete={onDelete ? onDelete : undefined}> + <ListEditorItemField> + <div>{text('field 1', 'Lorum Ipsum')}</div> + </ListEditorItemField> + <ListEditorItemField> + <div>{text('field 2', 'Lorum Ipsum')}</div> + </ListEditorItemField> + </ListEditorItemView> + )); } const stories = storiesOf('ListEditor', module); @@ -29,32 +27,49 @@ stories.addDecorator(withKnobs); stories .add('regular', () => ( - <ListEditorView title='List Editor'> - {makeChildren()} - </ListEditorView> + <ListEditorView title="List Editor">{makeChildren()}</ListEditorView> )) .add('two columns', () => ( - <ListEditorView title='List Editor' twoColumns> + <ListEditorView title="List Editor" twoColumns> {makeChildren()} </ListEditorView> )) .add('with add', () => ( - <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns> - {makeChildren()} + <ListEditorView + title="List Editor" + onAdd={action('onAdd')} + plusButtonTitle="Add" + twoColumns> + {makeChildren()} </ListEditorView> )) .add('with delete', () => ( - <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns> - {makeChildren({onDelete: action('onDelete')})} + <ListEditorView + title="List Editor" + onAdd={action('onAdd')} + plusButtonTitle="Add" + twoColumns> + {makeChildren({ onDelete: action('onDelete') })} </ListEditorView> )) .add('with edit', () => ( - <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns> - {makeChildren({onEdit: action('onEdit')})} + <ListEditorView + title="List Editor" + onAdd={action('onAdd')} + plusButtonTitle="Add" + twoColumns> + {makeChildren({ onEdit: action('onEdit') })} </ListEditorView> )) .add('with edit and delete', () => ( - <ListEditorView title='List Editor' onAdd={action('onAdd')} plusButtonTitle='Add' twoColumns> - {makeChildren({onDelete: action('onDelete'), onEdit: action('onEdit')})} + <ListEditorView + title="List Editor" + onAdd={action('onAdd')} + plusButtonTitle="Add" + twoColumns> + {makeChildren({ + onDelete: action('onDelete'), + onEdit: action('onEdit') + })} </ListEditorView> )); diff --git a/openecomp-ui/src/nfvo-components/loader/Loader.jsx b/openecomp-ui/src/nfvo-components/loader/Loader.jsx index 9ebe52dcfc..076351bf7a 100644 --- a/openecomp-ui/src/nfvo-components/loader/Loader.jsx +++ b/openecomp-ui/src/nfvo-components/loader/Loader.jsx @@ -16,40 +16,39 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; -const mapStateToProps = ({loader}) => { - return { - isLoading: loader.isLoading - }; +const mapStateToProps = ({ loader }) => { + return { + isLoading: loader.isLoading + }; }; class Loader extends React.Component { - - static propTypes = { - isLoading: PropTypes.bool.isRequired - }; - - static defaultProps = { - isLoading: false - }; - - shouldComponentUpdate(nextProps) { - return (nextProps.isLoading !== this.props.isLoading); - } - - render() { - let {isLoading} = this.props; - return ( - <div className='onboarding-loader'> - { - isLoading && <div className='onboarding-loader-backdrop'> - <div className='tlv-loader large'></div> - </div> - } - </div> - ); - } + static propTypes = { + isLoading: PropTypes.bool.isRequired + }; + + static defaultProps = { + isLoading: false + }; + + shouldComponentUpdate(nextProps) { + return nextProps.isLoading !== this.props.isLoading; + } + + render() { + let { isLoading } = this.props; + return ( + <div className="onboarding-loader"> + {isLoading && ( + <div className="onboarding-loader-backdrop"> + <div className="tlv-loader large" /> + </div> + )} + </div> + ); + } } -export default connect(mapStateToProps) (Loader); +export default connect(mapStateToProps)(Loader); diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js index 2b531b08fa..e367a74352 100644 --- a/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js +++ b/openecomp-ui/src/nfvo-components/loader/LoaderConstants.js @@ -16,9 +16,9 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - SHOW: null, - HIDE: null, + SHOW: null, + HIDE: null, - SEND_REQUEST: null, - RECEIVE_RESPONSE: null + SEND_REQUEST: null, + RECEIVE_RESPONSE: null }); diff --git a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js index 3afdad0573..1d0f6790e1 100644 --- a/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js +++ b/openecomp-ui/src/nfvo-components/loader/LoaderReducer.js @@ -13,43 +13,54 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {actionTypes} from './LoaderConstants.js'; +import { actionTypes } from './LoaderConstants.js'; -export default (state = {fetchingRequests : 0, currentlyFetching : [], isLoading : false}, action) => { - let fetchingRequests = state.fetchingRequests; - let newArray; - switch (action.type) { - case actionTypes.SEND_REQUEST: - fetchingRequests++; - newArray = state.currentlyFetching.slice(); - newArray.splice(0, 0, action.url); - if (DEBUG) { - console.log('Loader SEND REQUEST url: ' + action.url); - console.log('Loader SEND REQUEST number of fetching requests: ' + fetchingRequests); - } - return { - fetchingRequests: fetchingRequests, - currentlyFetching : newArray, - isLoading: true - }; - case actionTypes.RECEIVE_RESPONSE: - fetchingRequests--; +export default ( + state = { fetchingRequests: 0, currentlyFetching: [], isLoading: false }, + action +) => { + let fetchingRequests = state.fetchingRequests; + let newArray; + switch (action.type) { + case actionTypes.SEND_REQUEST: + fetchingRequests++; + newArray = state.currentlyFetching.slice(); + newArray.splice(0, 0, action.url); + if (DEBUG) { + console.log('Loader SEND REQUEST url: ' + action.url); + console.log( + 'Loader SEND REQUEST number of fetching requests: ' + + fetchingRequests + ); + } + return { + fetchingRequests: fetchingRequests, + currentlyFetching: newArray, + isLoading: true + }; + case actionTypes.RECEIVE_RESPONSE: + fetchingRequests--; - newArray = state.currentlyFetching.filter((item) => {return item !== action.url;}); - if (DEBUG) { - console.log('Loader RECEIVE_RESPONSE url: ' + action.url); - console.log('Loader RECEIVE_RESPONSE: number of fetching requests: ' + fetchingRequests); - } - return { - currentlyFetching : newArray, - fetchingRequests: fetchingRequests, - isLoading: (fetchingRequests !== 0) - }; - case actionTypes.SHOW: - return {isLoading: true}; - case actionTypes.HIDE: - return {isLoading: false}; - default: - return state; - } + newArray = state.currentlyFetching.filter(item => { + return item !== action.url; + }); + if (DEBUG) { + console.log('Loader RECEIVE_RESPONSE url: ' + action.url); + console.log( + 'Loader RECEIVE_RESPONSE: number of fetching requests: ' + + fetchingRequests + ); + } + return { + currentlyFetching: newArray, + fetchingRequests: fetchingRequests, + isLoading: fetchingRequests !== 0 + }; + case actionTypes.SHOW: + return { isLoading: true }; + case actionTypes.HIDE: + return { isLoading: false }; + default: + return state; + } }; diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js index 75b7983ac3..3f19bd76a3 100644 --- a/openecomp-ui/src/nfvo-components/modal/GlobalModal.js +++ b/openecomp-ui/src/nfvo-components/modal/GlobalModal.js @@ -16,145 +16,195 @@ import React from 'react'; import PropTypes from 'prop-types'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import Modal from 'nfvo-components/modal/Modal.jsx'; 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'; - +import { modalContentComponents } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes, typeEnum } from './GlobalModalConstants.js'; const typeClass = { - 'default': 'primary', - error: 'negative', - warning: 'warning', - success: 'positive' + default: 'primary', + error: 'negative', + warning: 'warning', + success: 'positive' }; const type2HeaderColor = { - 'default': 'primary', - error: 'danger', - warning: 'warning', - success: 'success' + default: 'primary', + error: 'danger', + warning: 'warning', + success: 'success' }; - -const ModalFooter = ({type, onConfirmed, onDeclined, onClose, confirmationButtonText, cancelButtonText}) => { - let myPropsForNoConfirmed = {}; - if (onConfirmed) { - myPropsForNoConfirmed.btnType = 'outline'; - } - return ( - <Modal.Footer> - <div className='sdc-modal-footer'> - {onConfirmed && <Button data-test-id='sdc-modal-confirm-button' color={typeClass[type]} onClick={() => { - onConfirmed(); - onClose(); - }}>{confirmationButtonText}</Button>} - <Button {...myPropsForNoConfirmed} data-test-id='sdc-modal-cancel-button' btnType='outline' color={typeClass[type]} onClick={onDeclined ? () => { - onDeclined(); - onClose();} : () => onClose()}> - {cancelButtonText} - </Button> - </div> - </Modal.Footer> - ); +const ModalFooter = ({ + type, + onConfirmed, + onDeclined, + onClose, + confirmationButtonText, + cancelButtonText +}) => { + let myPropsForNoConfirmed = {}; + if (onConfirmed) { + myPropsForNoConfirmed.btnType = 'outline'; + } + return ( + <Modal.Footer> + <div className="sdc-modal-footer"> + {onConfirmed && ( + <Button + data-test-id="sdc-modal-confirm-button" + color={typeClass[type]} + onClick={() => { + onConfirmed(); + onClose(); + }}> + {confirmationButtonText} + </Button> + )} + <Button + {...myPropsForNoConfirmed} + data-test-id="sdc-modal-cancel-button" + btnType="outline" + color={typeClass[type]} + onClick={ + onDeclined + ? () => { + onDeclined(); + onClose(); + } + : () => onClose() + }> + {cancelButtonText} + </Button> + </div> + </Modal.Footer> + ); }; ModalFooter.defaultProps = { - type: 'default', - confirmationButtonText: i18n('OK'), - cancelButtonText: i18n('Cancel') + type: 'default', + confirmationButtonText: i18n('OK'), + cancelButtonText: i18n('Cancel') }; ModalFooter.PropTypes = { - type: PropTypes.string, - confirmationButtonText: PropTypes.string, - cancelButtonText: PropTypes.string + type: PropTypes.string, + confirmationButtonText: PropTypes.string, + cancelButtonText: PropTypes.string }; -export const mapStateToProps = ({modal}) => { - const show = !!modal; - return { - show, - ...modal - }; +export const mapStateToProps = ({ modal }) => { + const show = !!modal; + return { + show, + ...modal + }; }; -export const mapActionToProps = (dispatch) => { - return { - onClose: () => dispatch({type: actionTypes.GLOBAL_MODAL_CLOSE}) - }; +export const mapActionToProps = dispatch => { + return { + onClose: () => dispatch({ type: actionTypes.GLOBAL_MODAL_CLOSE }) + }; }; - -export class GlobalModalView extends React.Component { - - static propTypes = { - show: PropTypes.bool, - type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), - title: PropTypes.string, - modalComponentProps: PropTypes.object, - modalComponentName: PropTypes.string, - onConfirmed: PropTypes.func, - onDeclined: PropTypes.func, - confirmationButtonText: PropTypes.string, - cancelButtonText: PropTypes.string - }; - - static defaultProps = { - show: false, - type: 'default', - title: '' - }; - - render() { - let {title, type, show, modalComponentName, modalComponentProps, - modalClassName, msg, onConfirmed, onDeclined, confirmationButtonText, cancelButtonText, onClose} = this.props; - const ComponentToRender = modalContentComponents[modalComponentName]; - return ( - <Modal show={show} bsSize={modalComponentProps && modalComponentProps.size} className={`onborading-modal ${modalClassName || ''} ${type2HeaderColor[type]}`}> - <Modal.Header> - <Modal.Title>{title}</Modal.Title> - </Modal.Header> - <Modal.Body> - {ComponentToRender ? - <ComponentToRender {...modalComponentProps}/> : - msg && typeof msg === 'string' ? - <div> {msg.split('\n').map((txt, i) => <span key={i}> {txt} <br/> </span>)} </div> : - msg - } - </Modal.Body> - {(onConfirmed || onDeclined || type !== typeEnum.DEFAULT) && - <ModalFooter - type={type} - onConfirmed={onConfirmed} - onDeclined={onDeclined} - onClose={onClose} - confirmationButtonText={confirmationButtonText} - cancelButtonText={cancelButtonText}/>} - </Modal> - ); - } - - componentDidUpdate() { - if (this.props.timeout) { - setTimeout(this.props.onClose, this.props.timeout); - } - } -}; +export class GlobalModalView extends React.Component { + static propTypes = { + show: PropTypes.bool, + type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), + title: PropTypes.string, + modalComponentProps: PropTypes.object, + modalComponentName: PropTypes.string, + onConfirmed: PropTypes.func, + onDeclined: PropTypes.func, + confirmationButtonText: PropTypes.string, + cancelButtonText: PropTypes.string + }; + + static defaultProps = { + show: false, + type: 'default', + title: '' + }; + + render() { + let { + title, + type, + show, + modalComponentName, + modalComponentProps, + modalClassName, + msg, + onConfirmed, + onDeclined, + confirmationButtonText, + cancelButtonText, + onClose + } = this.props; + const ComponentToRender = modalContentComponents[modalComponentName]; + return ( + <Modal + show={show} + bsSize={modalComponentProps && modalComponentProps.size} + className={`onborading-modal ${modalClassName || ''} ${ + type2HeaderColor[type] + }`}> + <Modal.Header> + <Modal.Title>{title}</Modal.Title> + </Modal.Header> + <Modal.Body> + {ComponentToRender ? ( + <ComponentToRender {...modalComponentProps} /> + ) : msg && typeof msg === 'string' ? ( + <div> + {' '} + {msg.split('\n').map((txt, i) => ( + <span key={i}> + {' '} + {txt} <br />{' '} + </span> + ))}{' '} + </div> + ) : ( + msg + )} + </Modal.Body> + {(onConfirmed || onDeclined || type !== typeEnum.DEFAULT) && ( + <ModalFooter + type={type} + onConfirmed={onConfirmed} + onDeclined={onDeclined} + onClose={onClose} + confirmationButtonText={confirmationButtonText} + cancelButtonText={cancelButtonText} + /> + )} + </Modal> + ); + } + + componentDidUpdate() { + if (this.props.timeout) { + setTimeout(this.props.onClose, this.props.timeout); + } + } +} GlobalModalView.propTypes = { - show: PropTypes.bool, - type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), - title: PropTypes.string, - modalComponentProps: PropTypes.object, - modalComponentName: PropTypes.string, - onConfirmed: PropTypes.func, - onDeclined: PropTypes.func, - confirmationButtonText: PropTypes.string, - cancelButtonText: PropTypes.string + show: PropTypes.bool, + type: PropTypes.oneOf(['default', 'error', 'warning', 'success']), + title: PropTypes.string, + modalComponentProps: PropTypes.object, + modalComponentName: PropTypes.string, + onConfirmed: PropTypes.func, + onDeclined: PropTypes.func, + confirmationButtonText: PropTypes.string, + cancelButtonText: PropTypes.string }; -export default connect(mapStateToProps, mapActionToProps, null, {withRef: true})(GlobalModalView); +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 3e5545371a..e9c1853c97 100644 --- a/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js +++ b/openecomp-ui/src/nfvo-components/modal/GlobalModalConstants.js @@ -16,23 +16,21 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - GLOBAL_MODAL_SHOW: null, - GLOBAL_MODAL_CLOSE: null, - GLOBAL_MODAL_ERROR: null, - GLOBAL_MODAL_WARNING: null, - GLOBAL_MODAL_SUCCESS: null, - + GLOBAL_MODAL_SHOW: null, + GLOBAL_MODAL_CLOSE: null, + GLOBAL_MODAL_ERROR: null, + GLOBAL_MODAL_WARNING: null, + GLOBAL_MODAL_SUCCESS: null }); - export const typeEnum = { - DEFAULT: 'default', - ERROR: 'error', - WARNING: 'warning', - SUCCESS: 'success' + DEFAULT: 'default', + ERROR: 'error', + WARNING: 'warning', + SUCCESS: 'success' }; -export const modalSizes = { - LARGE: 'large', - SMALL: 'small' +export const modalSizes = { + LARGE: 'large', + SMALL: 'small' }; diff --git a/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js b/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js index 28674ea569..b2273fa7a7 100644 --- a/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js +++ b/openecomp-ui/src/nfvo-components/modal/GlobalModalReducer.js @@ -14,37 +14,37 @@ * permissions and limitations under the License. */ -import {actionTypes, typeEnum} from './GlobalModalConstants.js'; +import { actionTypes, typeEnum } from './GlobalModalConstants.js'; export default (state = null, action) => { - switch (action.type) { - case actionTypes.GLOBAL_MODAL_SHOW: - return { - ...action.data - }; - case actionTypes.GLOBAL_MODAL_ERROR: - return { - type: typeEnum.ERROR, - modalClassName: 'notification-modal', - ...action.data - }; - case actionTypes.GLOBAL_MODAL_WARNING: - return { - type: typeEnum.WARNING, - modalClassName: 'notification-modal', - ...action.data - }; + switch (action.type) { + case actionTypes.GLOBAL_MODAL_SHOW: + return { + ...action.data + }; + case actionTypes.GLOBAL_MODAL_ERROR: + return { + type: typeEnum.ERROR, + modalClassName: 'notification-modal', + ...action.data + }; + case actionTypes.GLOBAL_MODAL_WARNING: + return { + type: typeEnum.WARNING, + modalClassName: 'notification-modal', + ...action.data + }; - case actionTypes.GLOBAL_MODAL_SUCCESS: - return { - type: typeEnum.SUCCESS, - modalClassName: 'notification-modal', - ...action.data - }; + case actionTypes.GLOBAL_MODAL_SUCCESS: + return { + type: typeEnum.SUCCESS, + modalClassName: 'notification-modal', + ...action.data + }; - case actionTypes.GLOBAL_MODAL_CLOSE: - return null; - default: - return state; - } + case actionTypes.GLOBAL_MODAL_CLOSE: + return null; + default: + return state; + } }; diff --git a/openecomp-ui/src/nfvo-components/modal/Modal.jsx b/openecomp-ui/src/nfvo-components/modal/Modal.jsx index b0f704dba9..cfd757501f 100644 --- a/openecomp-ui/src/nfvo-components/modal/Modal.jsx +++ b/openecomp-ui/src/nfvo-components/modal/Modal.jsx @@ -20,65 +20,63 @@ import BootstrapModal from 'react-bootstrap/lib/Modal.js'; let nextModalId = 0; export default class Modal extends React.Component { + static Header = BootstrapModal.Header; - static Header = BootstrapModal.Header; + static Title = BootstrapModal.Title; - static Title = BootstrapModal.Title; + static Footer = BootstrapModal.Footer; - static Footer = BootstrapModal.Footer; + static Body = class ModalBody extends React.Component { + render() { + let { children, ...props } = this.props; + return ( + <BootstrapModal.Body {...props}>{children}</BootstrapModal.Body> + ); + } - static Body = class ModalBody extends React.Component { + componentDidMount() { + let element = ReactDOM.findDOMNode(this); + element.addEventListener('click', event => { + if (event.target.tagName === 'A') { + event.preventDefault(); + } + }); + ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => + element.addEventListener(eventType, event => + event.stopPropagation() + ) + ); + } + }; - render() { - let {children, ...props} = this.props; - return ( - <BootstrapModal.Body {...props}> - {children} - </BootstrapModal.Body> - ); - } + componentWillMount() { + this.modalId = `dox-ui-modal-${nextModalId++}`; + } - componentDidMount() { - let element = ReactDOM.findDOMNode(this); - element.addEventListener('click', event => { - if (event.target.tagName === 'A') { - event.preventDefault(); - } - }); - ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => - element.addEventListener(eventType, event => event.stopPropagation()) - ); - } - }; + componentDidMount() { + this.ensureRootClass(); + } - componentWillMount() { - this.modalId = `dox-ui-modal-${nextModalId++}`; - } + componentDidUpdate() { + this.ensureRootClass(); + } - componentDidMount() { - this.ensureRootClass(); - } + ensureRootClass() { + let element = document.getElementById(this.modalId); + while (element && !element.hasAttribute('data-reactroot')) { + element = element.parentElement; + } + if (element && !element.classList.contains('dox-ui')) { + element.classList.add('dox-ui'); + } + } - componentDidUpdate() { - this.ensureRootClass(); - } - - ensureRootClass() { - let element = document.getElementById(this.modalId); - while(element && !element.hasAttribute('data-reactroot')) { - element = element.parentElement; - } - if (element && !element.classList.contains('dox-ui')) { - element.classList.add('dox-ui'); - } - } - - render() { - let {children, ...props} = this.props; - return ( - <BootstrapModal {...props} id={this.modalId}> - {children} - </BootstrapModal> - ); - } + render() { + let { children, ...props } = this.props; + return ( + <BootstrapModal {...props} id={this.modalId}> + {children} + </BootstrapModal> + ); + } } diff --git a/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx b/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx index 054c1e2852..7ed898e593 100644 --- a/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx +++ b/openecomp-ui/src/nfvo-components/overlay/Overlay.jsx @@ -18,23 +18,21 @@ import React from 'react'; import enhanceWithClickOutside from 'react-click-outside'; class Overlay extends React.Component { + handleClickOutside() { + if (this.props.onClose) { + this.props.onClose(); + } + } - handleClickOutside() { - if (this.props.onClose) { - this.props.onClose(); - } - } - - render() { - return ( - <div className='onboarding-overlay'> - <div className='arrow-up'></div> - <div className='arrow-border'/> - {this.props.children} - </div> - ); - } - -}; + render() { + return ( + <div className="onboarding-overlay"> + <div className="arrow-up" /> + <div className="arrow-border" /> + {this.props.children} + </div> + ); + } +} export default enhanceWithClickOutside(Overlay); diff --git a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx index 2eda7e69bf..61121df335 100644 --- a/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx +++ b/openecomp-ui/src/nfvo-components/panel/NavigationSideBar.jsx @@ -19,116 +19,159 @@ import classnames from 'classnames'; import Collapse from 'react-bootstrap/lib/Collapse.js'; class NavigationSideBar extends React.Component { - static PropTypes = { - activeItemId: PropTypes.string.isRequired, - onSelect: PropTypes.func, - onToggle: PropTypes.func, - groups: PropTypes.array, - disabled: PropTypes.bool - }; + static PropTypes = { + activeItemId: PropTypes.string.isRequired, + onSelect: PropTypes.func, + onToggle: PropTypes.func, + groups: PropTypes.array, + disabled: PropTypes.bool + }; - constructor(props) { - super(props); - this.state = { - activeItemId: null - }; - this.handleItemClicked = this.handleItemClicked.bind(this); - } + constructor(props) { + super(props); + this.state = { + activeItemId: null + }; + this.handleItemClicked = this.handleItemClicked.bind(this); + } - render() { - let {groups, activeItemId, disabled = false} = this.props; + render() { + let { groups, activeItemId, disabled = false } = this.props; - return ( - <div className={`navigation-side-content ${disabled ? 'disabled' : ''}`}> - {groups.map(group => ( - <NavigationMenu menu={group} activeItemId={activeItemId} onNavigationItemClick={this.handleItemClicked} key={'menu_' + group.id} /> - ))} - </div> - ); - } + return ( + <div + className={`navigation-side-content ${ + disabled ? 'disabled' : '' + }`}> + {groups.map(group => ( + <NavigationMenu + menu={group} + activeItemId={activeItemId} + onNavigationItemClick={this.handleItemClicked} + key={'menu_' + group.id} + /> + ))} + </div> + ); + } - handleItemClicked(event, item) { - event.stopPropagation(); - if(this.props.onToggle) { - this.props.onToggle(this.props.groups, item.id); - } - if(item.onSelect) { - item.onSelect(); - } - if(this.props.onSelect) { - this.props.onSelect(item); - } - } + handleItemClicked(event, item) { + event.stopPropagation(); + if (this.props.onToggle) { + this.props.onToggle(this.props.groups, item.id); + } + if (item.onSelect) { + item.onSelect(); + } + if (this.props.onSelect) { + this.props.onSelect(item); + } + } } class NavigationMenu extends React.Component { - static PropTypes = { - activeItemId: PropTypes.string.isRequired, - onNavigationItemClick: PropTypes.func, - menu: PropTypes.array - }; + static PropTypes = { + activeItemId: PropTypes.string.isRequired, + onNavigationItemClick: PropTypes.func, + menu: PropTypes.array + }; - render() { - const {menu, activeItemId, onNavigationItemClick} = this.props; - return ( - <div className='navigation-group' key={menu.id}> - <NavigationMenuHeader title={menu.name} /> - <NavigationMenuItems items={menu.items} activeItemId={activeItemId} onNavigationItemClick={onNavigationItemClick} /> - </div>); - } + render() { + const { menu, activeItemId, onNavigationItemClick } = this.props; + return ( + <div className="navigation-group" key={menu.id}> + <NavigationMenuHeader title={menu.name} /> + <NavigationMenuItems + items={menu.items} + activeItemId={activeItemId} + onNavigationItemClick={onNavigationItemClick} + /> + </div> + ); + } } function NavigationMenuHeader(props) { - return <div className='group-name' data-test-id='navbar-group-name'>{props.title}</div>; + return ( + <div className="group-name" data-test-id="navbar-group-name"> + {props.title} + </div> + ); } function getItemDataTestId(itemId) { - return itemId.split('|')[0]; + return itemId.split('|')[0]; } function NavigationMenuItems(props) { - const {items, activeItemId, onNavigationItemClick} = props; - return ( - <div className='navigation-group-items'> - { - items && items.map(item => (<NavigationMenuItem key={'menuItem_' + item.id} item={item} activeItemId={activeItemId} onNavigationItemClick={onNavigationItemClick} />)) - } - </div> - ); + const { items, activeItemId, onNavigationItemClick } = props; + return ( + <div className="navigation-group-items"> + {items && + items.map(item => ( + <NavigationMenuItem + key={'menuItem_' + item.id} + item={item} + activeItemId={activeItemId} + onNavigationItemClick={onNavigationItemClick} + /> + ))} + </div> + ); } function NavigationMenuItem(props) { - const {onNavigationItemClick, item, activeItemId} = props; - const isGroup = item.items && item.items.length > 0; - return ( - <div className={classnames('navigation-group-item', {'selected-item': item.id === activeItemId})} key={'item_' + item.id}> - <NavigationLink item={item} activeItemId={activeItemId} onClick={onNavigationItemClick} /> - {isGroup && <Collapse in={item.expanded} data-test-id={'navigation-group-' + getItemDataTestId(item.id)}> - <div> - {item.items.map(subItem => (<NavigationMenuItem key={'menuItem_' + subItem.id} item={subItem} onNavigationItemClick={onNavigationItemClick} activeItemId={activeItemId} />)) } - </div> - </Collapse> - } - </div> - ); + const { onNavigationItemClick, item, activeItemId } = props; + const isGroup = item.items && item.items.length > 0; + return ( + <div + className={classnames('navigation-group-item', { + 'selected-item': item.id === activeItemId + })} + key={'item_' + item.id}> + <NavigationLink + item={item} + activeItemId={activeItemId} + onClick={onNavigationItemClick} + /> + {isGroup && ( + <Collapse + in={item.expanded} + data-test-id={ + 'navigation-group-' + getItemDataTestId(item.id) + }> + <div> + {item.items.map(subItem => ( + <NavigationMenuItem + key={'menuItem_' + subItem.id} + item={subItem} + onNavigationItemClick={onNavigationItemClick} + activeItemId={activeItemId} + /> + ))} + </div> + </Collapse> + )} + </div> + ); } function NavigationLink(props) { - const {item, activeItemId, onClick} = props; - // todo should this be button - return ( - <div - key={'navAction_' + item.id} - className={classnames('navigation-group-item-name', { - 'selected': item.id === activeItemId, - 'disabled': item.disabled, - 'bold-name': item.expanded, - 'hidden': item.hidden - })} - onClick={(event) => onClick(event, item)} - data-test-id={'navbar-group-item-' + getItemDataTestId(item.id)}> - {item.name} - </div> - ); + const { item, activeItemId, onClick } = props; + // todo should this be button + return ( + <div + key={'navAction_' + item.id} + className={classnames('navigation-group-item-name', { + selected: item.id === activeItemId, + disabled: item.disabled, + 'bold-name': item.expanded, + hidden: item.hidden + })} + onClick={event => onClick(event, item)} + data-test-id={'navbar-group-item-' + getItemDataTestId(item.id)}> + {item.name} + </div> + ); } export default NavigationSideBar; diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx index 57fa86f561..c9c5789622 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx +++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionController.jsx @@ -17,125 +17,224 @@ import React from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionsEnum} from './VersionControllerConstants.js'; +import { actionsEnum } from './VersionControllerConstants.js'; import ActionButtons from './components/ActionButtons.jsx'; import NotificationsView from 'sdc-app/onboarding/userNotifications/NotificationsView.jsx'; - class VersionController extends React.Component { - - static propTypes = { - version: PropTypes.object, - viewableVersions: PropTypes.array, - onVersionSwitching: PropTypes.func, - callVCAction: PropTypes.func, - onSave: PropTypes.func, - onClose: PropTypes.func, - isFormDataValid: PropTypes.bool, - onOpenCommentCommitModal: PropTypes.func, - isReadOnlyMode: PropTypes.bool - }; - - state = { - showPermissions: false, - showRevisions: false - }; - - render() { - let {version = {}, viewableVersions = [], onVersionSwitching, onMoreVersionsClick, callVCAction, onSave, isReadOnlyMode, itemPermission, - isFormDataValid, onClose, onManagePermissions, permissions = {}, userInfo, usersList, itemName, - onOpenCommentCommitModal, onOpenRevisionsModal, isManual, candidateInProcess, isArchived} = this.props; - return ( - <div className='version-controller-bar'> - <div className={`vc-container ${candidateInProcess ? 'disabled' : ''}`}> - <div className='version-status-container'> - <VersionSelector - viewableVersions={viewableVersions} - version={version} - onVersionSwitching={onVersionSwitching} - onMoreVersionsClick={() => onMoreVersionsClick({itemName, users: usersList})}/> - {isArchived && <div className='depricated-item-status'>{i18n('Archived')}</div>} - </div> - <div className='save-submit-cancel-container'> - <ActionButtons onSubmit={callVCAction ? () => this.submit(callVCAction, version) : undefined} - onRevert={callVCAction ? () => this.revert(callVCAction, version) : undefined} - onOpenRevisionsModal={onOpenRevisionsModal} - onSave={onSave ? () => onSave() : undefined} - permissions={permissions} - userInfo={userInfo} - onManagePermissions={onManagePermissions} - showPermissions={this.state.showPermissions} - onClosePermissions={()=>this.setState({showPermissions: false})} - onClickPermissions={() => this.onClickPermissions()} - onSync={callVCAction ? () => this.sync(callVCAction, version) : undefined} - onOpenCommentCommitModal={onOpenCommentCommitModal} - onCommit={callVCAction ? (comment) => this.commit(callVCAction, version, comment) : undefined} - isFormDataValid={isFormDataValid} - itemPermissions={itemPermission} - isArchived={isArchived} - isReadOnlyMode={isReadOnlyMode || candidateInProcess} - isManual={isManual} /> - <div className='vc-separator'></div> - <NotificationsView /> - {onClose && <div className='vc-nav-item-close' onClick={() => onClose()} data-test-id='vc-cancel-btn'> X</div>} - </div> - </div> - </div> - ); - } - - onClickPermissions() { - let {onOpenPermissions, usersList} = this.props; - let {showPermissions} = this.state; - let promise = showPermissions ? Promise.resolve() : onOpenPermissions({users: usersList}); - promise.then(() => this.setState({showPermissions: !showPermissions})); - } - - - submit(callVCAction, version) { - const action = actionsEnum.SUBMIT; - callVCAction(action, version); - } - - revert(callVCAction, version) { - const action = actionsEnum.REVERT; - callVCAction(action, version); - } - - sync(callVCAction, version) { - const action = actionsEnum.SYNC; - callVCAction(action, version); - } - - commit(callVCAction, version, comment) { - const action = actionsEnum.COMMIT; - callVCAction(action, version, comment); - } - - permissions() { - - } + static propTypes = { + version: PropTypes.object, + viewableVersions: PropTypes.array, + onVersionSwitching: PropTypes.func, + callVCAction: PropTypes.func, + onSave: PropTypes.func, + onClose: PropTypes.func, + isFormDataValid: PropTypes.bool, + onOpenCommentCommitModal: PropTypes.func, + isReadOnlyMode: PropTypes.bool + }; + + state = { + showPermissions: false, + showRevisions: false + }; + + render() { + let { + version = {}, + viewableVersions = [], + onVersionSwitching, + onMoreVersionsClick, + callVCAction, + onSave, + isReadOnlyMode, + itemPermission, + isFormDataValid, + onClose, + onManagePermissions, + permissions = {}, + userInfo, + usersList, + itemName, + onOpenCommentCommitModal, + onOpenRevisionsModal, + isManual, + candidateInProcess, + isArchived + } = this.props; + return ( + <div className="version-controller-bar"> + <div + className={`vc-container ${ + candidateInProcess ? 'disabled' : '' + }`}> + <div className="version-status-container"> + <VersionSelector + viewableVersions={viewableVersions} + version={version} + onVersionSwitching={onVersionSwitching} + onMoreVersionsClick={() => + onMoreVersionsClick({ + itemName, + users: usersList + }) + } + /> + {isArchived && ( + <div className="depricated-item-status"> + {i18n('Archived')} + </div> + )} + </div> + <div className="save-submit-cancel-container"> + <ActionButtons + onSubmit={ + callVCAction + ? () => this.submit(callVCAction, version) + : undefined + } + onRevert={ + callVCAction + ? () => this.revert(callVCAction, version) + : undefined + } + onOpenRevisionsModal={onOpenRevisionsModal} + onSave={onSave ? () => onSave() : undefined} + permissions={permissions} + userInfo={userInfo} + onManagePermissions={onManagePermissions} + showPermissions={this.state.showPermissions} + onClosePermissions={() => + this.setState({ showPermissions: false }) + } + onClickPermissions={() => this.onClickPermissions()} + onSync={ + callVCAction + ? () => this.sync(callVCAction, version) + : undefined + } + onOpenCommentCommitModal={onOpenCommentCommitModal} + onCommit={ + callVCAction + ? comment => + this.commit( + callVCAction, + version, + comment + ) + : undefined + } + isFormDataValid={isFormDataValid} + itemPermissions={itemPermission} + isArchived={isArchived} + isReadOnlyMode={ + isReadOnlyMode || candidateInProcess + } + isManual={isManual} + /> + <div className="vc-separator" /> + <NotificationsView /> + {onClose && ( + <div + className="vc-nav-item-close" + onClick={() => onClose()} + data-test-id="vc-cancel-btn"> + {' '} + X + </div> + )} + </div> + </div> + </div> + ); + } + + onClickPermissions() { + let { onOpenPermissions, usersList } = this.props; + let { showPermissions } = this.state; + let promise = showPermissions + ? Promise.resolve() + : onOpenPermissions({ users: usersList }); + promise.then(() => + this.setState({ showPermissions: !showPermissions }) + ); + } + + submit(callVCAction, version) { + const action = actionsEnum.SUBMIT; + callVCAction(action, version); + } + + revert(callVCAction, version) { + const action = actionsEnum.REVERT; + callVCAction(action, version); + } + + sync(callVCAction, version) { + const action = actionsEnum.SYNC; + callVCAction(action, version); + } + + commit(callVCAction, version, comment) { + const action = actionsEnum.COMMIT; + callVCAction(action, version, comment); + } + + permissions() {} } function VersionSelector(props) { - let {version = {}, onMoreVersionsClick, viewableVersions = [], onVersionSwitching} = props; - const includedVersions = viewableVersions.filter(ver => {return ver.id === version.id;}); - return (<div className='version-section-wrapper'> - <select className='version-selector' - onChange={ev => onVersionSwitching && onVersionSwitching(viewableVersions.find(version => version.id === ev.target.value))} - value={version.id} - data-test-id='vc-versions-select-box'> - {viewableVersions && viewableVersions.map(viewVersion => { - return ( - <option key={viewVersion.id} value={viewVersion.id} data-test-id='vc-version-option'>{`V ${viewVersion.name} ${viewVersion.status}`}</option> - ); - }) - } - {!includedVersions.length && - <option key={version.id} value={version.id} data-test-id='vc-selected-version-option'>{`V ${version.name} ${version.status}`}</option>} - </select> - <span onClick={onMoreVersionsClick} className='version-selector-more-versions' data-test-id='vc-versions-page-link'>{i18n('Versions Page')}</span> - </div>); + let { + version = {}, + onMoreVersionsClick, + viewableVersions = [], + onVersionSwitching + } = props; + const includedVersions = viewableVersions.filter(ver => { + return ver.id === version.id; + }); + return ( + <div className="version-section-wrapper"> + <select + className="version-selector" + onChange={ev => + onVersionSwitching && + onVersionSwitching( + viewableVersions.find( + version => version.id === ev.target.value + ) + ) + } + value={version.id} + data-test-id="vc-versions-select-box"> + {viewableVersions && + viewableVersions.map(viewVersion => { + return ( + <option + key={viewVersion.id} + value={viewVersion.id} + data-test-id="vc-version-option">{`V ${ + viewVersion.name + } ${viewVersion.status}`}</option> + ); + })} + {!includedVersions.length && ( + <option + key={version.id} + value={version.id} + data-test-id="vc-selected-version-option">{`V ${ + version.name + } ${version.status}`}</option> + )} + </select> + <span + onClick={onMoreVersionsClick} + className="version-selector-more-versions" + data-test-id="vc-versions-page-link"> + {i18n('Versions Page')} + </span> + </div> + ); } export default VersionController; diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js index ddb428a1e9..54f10c1acf 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js +++ b/openecomp-ui/src/nfvo-components/panel/versionController/VersionControllerConstants.js @@ -16,9 +16,9 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionsEnum = keyMirror({ - REVERT: 'Revert', - SYNC: 'Sync', - SUBMIT: 'Submit', - COMMIT: 'Commit', - CREATE_PACKAGE: 'Create_Package' + REVERT: 'Revert', + SYNC: 'Sync', + SUBMIT: 'Submit', + COMMIT: 'Commit', + CREATE_PACKAGE: 'Create_Package' }); diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx index b5750817ba..4dfa117803 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx +++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/ActionButtons.jsx @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import enhanceWithClickOutside from 'react-click-outside'; import i18n from 'nfvo-utils/i18n/i18n.js'; @@ -22,88 +22,171 @@ import Overlay from 'nfvo-components/overlay/Overlay.jsx'; import Permissions from './Permissions.jsx'; class ClickOutsideWrapper extends Component { - handleClickOutside() { - this.props.onClose(); - } - render() { - return <div>{this.props.children}</div>; - } + handleClickOutside() { + this.props.onClose(); + } + render() { + return <div>{this.props.children}</div>; + } } -const EnhancedClickOutsideWrapper = enhanceWithClickOutside(ClickOutsideWrapper); +const EnhancedClickOutsideWrapper = enhanceWithClickOutside( + ClickOutsideWrapper +); -const VCButton = ({name, tooltipText, disabled, onClick, dataTestId}) => { - let onClickAction = disabled ? ()=>{} : onClick; - return ( - <div className={`action-button-wrapper ${disabled ? 'disabled' : 'clickable'}`} onClick={onClickAction}> - <div className='action-buttons-svg'> - <SVGIcon label={tooltipText} labelPosition='bottom' labelClassName='action-button-label' - data-test-id={dataTestId} name={name} disabled={disabled}/> - </div> - </div> - ); +const VCButton = ({ name, tooltipText, disabled, onClick, dataTestId }) => { + let onClickAction = disabled ? () => {} : onClick; + return ( + <div + className={`action-button-wrapper ${ + disabled ? 'disabled' : 'clickable' + }`} + onClick={onClickAction}> + <div className="action-buttons-svg"> + <SVGIcon + label={tooltipText} + labelPosition="bottom" + labelClassName="action-button-label" + data-test-id={dataTestId} + name={name} + disabled={disabled} + /> + </div> + </div> + ); }; -const Separator = () => (<div className='vc-separator'></div>); +const Separator = () => <div className="vc-separator" />; -const SubmitButton = ({onClick, disabled}) => ( - <div onClick={()=>onClick()} data-test-id='vc-submit-btn' className={`vc-submit-button ${disabled ? 'disabled' : ''}`}> - <SVGIcon name='check' iconClassName='vc-v-submit' disabled={disabled} /> - {i18n('Submit')} - </div> +const SubmitButton = ({ onClick, disabled }) => ( + <div + onClick={() => onClick()} + data-test-id="vc-submit-btn" + className={`vc-submit-button ${disabled ? 'disabled' : ''}`}> + <SVGIcon name="check" iconClassName="vc-v-submit" disabled={disabled} /> + {i18n('Submit')} + </div> ); - -const ActionButtons = ({isReadOnlyMode, onSubmit, onRevert, onSave, isFormDataValid, onClickPermissions, onSync, onCommit, isArchived, - onOpenCommentCommitModal, showPermissions, onClosePermissions, permissions, onManagePermissions, userInfo, onOpenRevisionsModal, isManual, - itemPermissions: {isCertified, isCollaborator, isDirty, isOutOfSync, isUpToDate}}) => ( - <div className='action-buttons'> - <EnhancedClickOutsideWrapper onClose={onClosePermissions}> - <VCButton disabled={isManual} dataTestId='vc-permission-btn' onClick={onClickPermissions} - name='version-controller-permissions' tooltipText={i18n('Permissons')} /> - {showPermissions && - <Overlay> - <Permissions userInfo={userInfo} onManagePermissions={onManagePermissions} permissions={permissions} onClosePermissions={onClosePermissions}/> - </Overlay> - } - </EnhancedClickOutsideWrapper> - {isCollaborator && !isArchived && <div className='collaborator-action-buttons'> - <Separator /> - {onSave && <div className='vc-save-section'> - <VCButton dataTestId='vc-save-btn' onClick={() => onSave()} - name='version-controller-save' tooltipText={i18n('Save')} disabled={isReadOnlyMode || !isFormDataValid} /> - <Separator /> - </div> - } - <VCButton dataTestId='vc-sync-btn' onClick={onSync} - name='version-controller-sync' tooltipText={i18n('Sync')} disabled={!isCollaborator || isUpToDate || isCertified} /> - <VCButton dataTestId='vc-commit-btn' onClick={() => onOpenCommentCommitModal({onCommit, title: i18n('Commit')})} - name='version-controller-commit' tooltipText={i18n('Share')} disabled={isReadOnlyMode || !isDirty || isOutOfSync} /> - {onRevert && - <VCButton dataTestId='vc-revert-btn' onClick={onOpenRevisionsModal} - name='version-controller-revert' tooltipText={i18n('Revert')} disabled={isReadOnlyMode || isOutOfSync} /> - } - {onSubmit && - <div className='vc-submit-section'> - <Separator /> - <SubmitButton onClick={onSubmit} - disabled={isReadOnlyMode || isOutOfSync || !isUpToDate || isCertified} /> - </div> - } - </div>} - </div> +const ActionButtons = ({ + isReadOnlyMode, + onSubmit, + onRevert, + onSave, + isFormDataValid, + onClickPermissions, + onSync, + onCommit, + isArchived, + onOpenCommentCommitModal, + showPermissions, + onClosePermissions, + permissions, + onManagePermissions, + userInfo, + onOpenRevisionsModal, + isManual, + itemPermissions: { + isCertified, + isCollaborator, + isDirty, + isOutOfSync, + isUpToDate + } +}) => ( + <div className="action-buttons"> + <EnhancedClickOutsideWrapper onClose={onClosePermissions}> + <VCButton + disabled={isManual} + dataTestId="vc-permission-btn" + onClick={onClickPermissions} + name="version-controller-permissions" + tooltipText={i18n('Permissons')} + /> + {showPermissions && ( + <Overlay> + <Permissions + userInfo={userInfo} + onManagePermissions={onManagePermissions} + permissions={permissions} + onClosePermissions={onClosePermissions} + /> + </Overlay> + )} + </EnhancedClickOutsideWrapper> + {isCollaborator && + !isArchived && ( + <div className="collaborator-action-buttons"> + <Separator /> + {onSave && ( + <div className="vc-save-section"> + <VCButton + dataTestId="vc-save-btn" + onClick={() => onSave()} + name="version-controller-save" + tooltipText={i18n('Save')} + disabled={isReadOnlyMode || !isFormDataValid} + /> + <Separator /> + </div> + )} + <VCButton + dataTestId="vc-sync-btn" + onClick={onSync} + name="version-controller-sync" + tooltipText={i18n('Sync')} + disabled={!isCollaborator || isUpToDate || isCertified} + /> + <VCButton + dataTestId="vc-commit-btn" + onClick={() => + onOpenCommentCommitModal({ + onCommit, + title: i18n('Commit') + }) + } + name="version-controller-commit" + tooltipText={i18n('Share')} + disabled={isReadOnlyMode || !isDirty || isOutOfSync} + /> + {onRevert && ( + <VCButton + dataTestId="vc-revert-btn" + onClick={onOpenRevisionsModal} + name="version-controller-revert" + tooltipText={i18n('Revert')} + disabled={isReadOnlyMode || isOutOfSync} + /> + )} + {onSubmit && ( + <div className="vc-submit-section"> + <Separator /> + <SubmitButton + onClick={onSubmit} + disabled={ + isReadOnlyMode || + isOutOfSync || + !isUpToDate || + isCertified + } + /> + </div> + )} + </div> + )} + </div> ); ActionButtons.propTypes = { - version: PropTypes.object, - onSubmit: PropTypes.func, - onRevert: PropTypes.func, - onSave: PropTypes.func, - isLatestVersion: PropTypes.bool, - isCheckedIn: PropTypes.bool, - isCheckedOut: PropTypes.bool, - isFormDataValid: PropTypes.bool, - isReadOnlyMode: PropTypes.bool + version: PropTypes.object, + onSubmit: PropTypes.func, + onRevert: PropTypes.func, + onSave: PropTypes.func, + isLatestVersion: PropTypes.bool, + isCheckedIn: PropTypes.bool, + isCheckedOut: PropTypes.bool, + isFormDataValid: PropTypes.bool, + isReadOnlyMode: PropTypes.bool }; export default ActionButtons; diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx index 600eaeefaa..ae0913f3a9 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx +++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/CommitCommentModal.jsx @@ -15,59 +15,66 @@ */ import React from 'react'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; 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 {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import keyMirror from 'nfvo-utils/KeyMirror.js'; export const CommitModalType = keyMirror({ - COMMIT: null, - COMMIT_SUBMIT: null - + COMMIT: null, + COMMIT_SUBMIT: null }); -export const mapActionToProps = (dispatch) => { - return { - onClose: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }) - }; +export const mapActionToProps = dispatch => { + return { + onClose: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }) + }; }; class CommitCommentModal extends React.Component { + state = { + comment: '' + }; - state = { - comment: '' - }; - - render() { - const {onCommit, onClose, type} = this.props; - const [commitButtonText, descriptionText] = type === CommitModalType.COMMIT ? - [i18n('Commit'), i18n('You are about to commit your version')] : - [i18n('Commit & Submit'), i18n('You must commit your changes before the submit')]; + render() { + const { onCommit, onClose, type } = this.props; + const [commitButtonText, descriptionText] = + type === CommitModalType.COMMIT + ? [i18n('Commit'), i18n('You are about to commit your version')] + : [ + i18n('Commit & Submit'), + i18n('You must commit your changes before the submit') + ]; - return ( - <Form - ref='validationForm' - hasButtons={true} - onSubmit={ () => {onCommit(this.state.comment); onClose();} } - onReset={onClose} - submitButtonText={commitButtonText} - labledButtons={true} - isValid={true} - className='comment-commit-form'> - <div className='commit-modal-text'>{descriptionText}</div> - <Input - data-test-id='commit-comment-text' - onChange={comment => this.setState({comment: comment})} - label={i18n('Enter Commit Comment:')} - value={this.state.comment} - type='textarea'/> - </Form> - ); - } + return ( + <Form + ref="validationForm" + hasButtons={true} + onSubmit={() => { + onCommit(this.state.comment); + onClose(); + }} + onReset={onClose} + submitButtonText={commitButtonText} + labledButtons={true} + isValid={true} + className="comment-commit-form"> + <div className="commit-modal-text">{descriptionText}</div> + <Input + data-test-id="commit-comment-text" + onChange={comment => this.setState({ comment: comment })} + label={i18n('Enter Commit Comment:')} + value={this.state.comment} + type="textarea" + /> + </Form> + ); + } } export default connect(null, mapActionToProps)(CommitCommentModal); diff --git a/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx b/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx index 952bd4fb58..6e0ae8187b 100644 --- a/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx +++ b/openecomp-ui/src/nfvo-components/panel/versionController/components/Permissions.jsx @@ -18,48 +18,76 @@ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -const Contributor = ({name, role, id, userInfo}) => { +const Contributor = ({ name, role, id, userInfo }) => { + const selected = id === userInfo.userId ? 'selected' : ''; - const selected = id === userInfo.userId ? 'selected' : ''; - - return( - <div className='contributor'> - <div className='contributor-content'> - <div className={`contributor-icon-circle ${selected}`}> - <div className={`contributer-icon ${selected}`}> - <SVGIcon name='user'/> - </div> - </div> - <div className='contributer-info'> - <div className='contributer-name'>{name}</div> - <div className='contributer-role'><p>{role}</p></div> - </div> - </div> - </div> - ); + return ( + <div className="contributor"> + <div className="contributor-content"> + <div className={`contributor-icon-circle ${selected}`}> + <div className={`contributer-icon ${selected}`}> + <SVGIcon name="user" /> + </div> + </div> + <div className="contributer-info"> + <div className="contributer-name">{name}</div> + <div className="contributer-role"> + <p>{role}</p> + </div> + </div> + </div> + </div> + ); }; -const Permissions = ({permissions: {owner, contributors}, onManagePermissions, userInfo, onClosePermissions}) => { - - return ( - <div className='permissions-overlay'> - <div className='permissions-overlay-header'> - <h4 className='permissions-overlay-header-title'>{i18n('PERMISSIONS')}</h4> - </div> - <div className='permissions-overlay-content'> - <Contributor userInfo={userInfo} id={owner.userId} key={owner.fullName} name={owner.fullName} role={owner.role}/> - {contributors.map(item => item.userId !== owner.userId && <Contributor userInfo={userInfo} id={item.userId} key={item.fullName} name={item.fullName} role={item.role}/>)} - </div> - <div className='permissions-overlay-footer'> - { - owner.userId === userInfo.userId && - <div onClick={() => { onClosePermissions(); onManagePermissions(); }} className='manage-permissions-btn'> - {i18n('Manage Permissions')} - </div> - } - </div> - </div> - ); +const Permissions = ({ + permissions: { owner, contributors }, + onManagePermissions, + userInfo, + onClosePermissions +}) => { + return ( + <div className="permissions-overlay"> + <div className="permissions-overlay-header"> + <h4 className="permissions-overlay-header-title"> + {i18n('PERMISSIONS')} + </h4> + </div> + <div className="permissions-overlay-content"> + <Contributor + userInfo={userInfo} + id={owner.userId} + key={owner.fullName} + name={owner.fullName} + role={owner.role} + /> + {contributors.map( + item => + item.userId !== owner.userId && ( + <Contributor + userInfo={userInfo} + id={item.userId} + key={item.fullName} + name={item.fullName} + role={item.role} + /> + ) + )} + </div> + <div className="permissions-overlay-footer"> + {owner.userId === userInfo.userId && ( + <div + onClick={() => { + onClosePermissions(); + onManagePermissions(); + }} + className="manage-permissions-btn"> + {i18n('Manage Permissions')} + </div> + )} + </div> + </div> + ); }; export default Permissions; diff --git a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx index ca5cb3d765..cb10bb565e 100644 --- a/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx +++ b/openecomp-ui/src/nfvo-components/progressBar/ProgressBar.jsx @@ -17,22 +17,25 @@ import React from 'react'; import PropTypes from 'prop-types'; class ProgressBar extends React.Component { - static propTypes = { - label: PropTypes.string, - now: PropTypes.string.isRequired - } - render() { - let {label, now} = this.props; + static propTypes = { + label: PropTypes.string, + now: PropTypes.string.isRequired + }; + render() { + let { label, now } = this.props; - return( - <div className='progress-bar-view'> - <div className='progress-bar-outside'> - <div style={{width: now + '%'}} className='progress-bar-inside'></div> - </div> - <div className='progress-bar-view-label'>{label}</div> - </div> - ); - } + return ( + <div className="progress-bar-view"> + <div className="progress-bar-outside"> + <div + style={{ width: now + '%' }} + className="progress-bar-inside" + /> + </div> + <div className="progress-bar-view-label">{label}</div> + </div> + ); + } } export default ProgressBar; diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx index 3f8dbba53a..ee8a9dca45 100644 --- a/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx +++ b/openecomp-ui/src/nfvo-components/table/SelectActionTable.jsx @@ -5,26 +5,57 @@ import Button from 'sdc-ui/lib/react/Button.js'; import uuid from 'uuid-js'; export default class SelectActionTable extends React.Component { - - render() { - 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 && - <Button btnType='link' disabled={isReadOnlyMode === true} color='primary' iconName='plus' data-test-id='select-action-table-add' onClick={onAdd}>{onAddItem}</Button>} - <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>)} - {Array(numOfIcons).fill().map((e, i) => <SVGIcon name='trash-o' key={i} className='dummy-icon' />)} - </div> - <div className='select-action-table-body'> - {children} - </div> - </div> - </div> - ); - } + render() { + 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 && ( + <Button + btnType="link" + disabled={isReadOnlyMode === true} + color="primary" + iconName="plus" + data-test-id="select-action-table-add" + onClick={onAdd}> + {onAddItem} + </Button> + )} + <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> + ))} + {Array(numOfIcons) + .fill() + .map((e, i) => ( + <SVGIcon + name="trash-o" + key={i} + className="dummy-icon" + /> + ))} + </div> + <div className="select-action-table-body">{children}</div> + </div> + </div> + ); + } } diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx index 2664c8e944..20e4f2413c 100644 --- a/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx +++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableCell.jsx @@ -1,20 +1,28 @@ import React from 'react'; import SelectInput from 'nfvo-components/input/SelectInput.jsx'; -const SelectActionTableCell = ({options, selected, disabled, onChange, clearable = true, placeholder}) => { - return ( - <div className='select-action-table-cell'> - <SelectInput - placeholder={placeholder} - type='select' - value={selected} - data-test-id='select-action-table-dropdown' - disabled={disabled} - onChange={option => onChange(option ? option.value : null)} - clearable={clearable} - options={options} /> - </div> - ); +const SelectActionTableCell = ({ + options, + selected, + disabled, + onChange, + clearable = true, + placeholder +}) => { + return ( + <div className="select-action-table-cell"> + <SelectInput + placeholder={placeholder} + type="select" + value={selected} + data-test-id="select-action-table-dropdown" + disabled={disabled} + onChange={option => onChange(option ? option.value : null)} + clearable={clearable} + options={options} + /> + </div> + ); }; export default SelectActionTableCell; diff --git a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx index 260d39d31c..1c2c1529f2 100644 --- a/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx +++ b/openecomp-ui/src/nfvo-components/table/SelectActionTableRow.jsx @@ -3,38 +3,65 @@ 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'; -function tooltip (msg) { - return ( - <Tooltip className='select-action-table-error-tooltip' id='error-tooltip'>{msg}</Tooltip> - ); -}; +function tooltip(msg) { + return ( + <Tooltip + className="select-action-table-error-tooltip" + id="error-tooltip"> + {msg} + </Tooltip> + ); +} -const IconWithOverlay = ({overlayMsg}) => ( - <OverlayTrigger placement='bottom' overlay={tooltip(overlayMsg)}> - <SVGIcon name='errorCircle' color='negative'/> - </OverlayTrigger> +const IconWithOverlay = ({ overlayMsg }) => ( + <OverlayTrigger placement="bottom" overlay={tooltip(overlayMsg)}> + <SVGIcon name="errorCircle" color="negative" /> + </OverlayTrigger> ); -function renderErrorOrCheck({hasError, overlayMsg}) { - if (hasError === undefined) { - return <SVGIcon name='angleRight' className='dummy-icon' />; - } +function renderErrorOrCheck({ hasError, overlayMsg }) { + if (hasError === undefined) { + return <SVGIcon name="angleRight" className="dummy-icon" />; + } - if (hasError) { - return overlayMsg ? <IconWithOverlay overlayMsg={overlayMsg}/> : <SVGIcon color='negative' name='errorCircle'/>; - } + if (hasError) { + return overlayMsg ? ( + <IconWithOverlay overlayMsg={overlayMsg} /> + ) : ( + <SVGIcon color="negative" name="errorCircle" /> + ); + } - return <SVGIcon name='checkCircle' color='positive'/>; + return <SVGIcon name="checkCircle" color="positive" />; } -const SelectActionTableRow = ({children, actionIcon, onAction, showAction, hasError, hasErrorIndication, overlayMsg}) => ( - <div className='select-action-table-row-wrapper'> - <div className={`select-action-table-row ${hasError ? 'has-error' : ''}`}> - {children} - </div> - {onAction && <SVGIcon color='secondary' name={actionIcon} data-test-id={`select-action-table-${actionIcon}`} onClick={onAction} iconClassName={(showAction) ? '' : 'hideDelete'}/>} - {hasErrorIndication && renderErrorOrCheck({hasError, overlayMsg})} - </div> +const SelectActionTableRow = ({ + children, + actionIcon, + onAction, + showAction, + hasError, + hasErrorIndication, + overlayMsg +}) => ( + <div className="select-action-table-row-wrapper"> + <div + className={`select-action-table-row ${ + hasError ? 'has-error' : '' + }`}> + {children} + </div> + {onAction && ( + <SVGIcon + color="secondary" + name={actionIcon} + data-test-id={`select-action-table-${actionIcon}`} + onClick={onAction} + iconClassName={showAction ? '' : 'hideDelete'} + /> + )} + {hasErrorIndication && renderErrorOrCheck({ hasError, overlayMsg })} + </div> ); export default SelectActionTableRow; diff --git a/openecomp-ui/src/nfvo-components/tree/Tree.jsx b/openecomp-ui/src/nfvo-components/tree/Tree.jsx index 682f3b6d50..39434fcdf1 100644 --- a/openecomp-ui/src/nfvo-components/tree/Tree.jsx +++ b/openecomp-ui/src/nfvo-components/tree/Tree.jsx @@ -1,16 +1,28 @@ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import {select} from 'd3-selection'; -import {tree, stratify} from 'd3-hierarchy'; - +import { select } from 'd3-selection'; +import { tree, stratify } from 'd3-hierarchy'; function diagonal(d) { - - const offset = 50; - return 'M' + d.y + ',' + d.x - + 'C' + (d.parent.y + offset) + ',' + d.x - + ' ' + (d.parent.y + offset) + ',' + d.parent.x - + ' ' + d.parent.y + ',' + d.parent.x; + const offset = 50; + return ( + 'M' + + d.y + + ',' + + d.x + + 'C' + + (d.parent.y + offset) + + ',' + + d.x + + ' ' + + (d.parent.y + offset) + + ',' + + d.parent.x + + ' ' + + d.parent.y + + ',' + + d.parent.x + ); } const nodeRadius = 8; @@ -18,164 +30,226 @@ const verticalSpaceBetweenNodes = 70; const NARROW_HORIZONTAL_SPACES = 47; const WIDE_HORIZONTAL_SPACES = 65; -const stratifyFn = stratify().id(d => d.id).parentId(d => d.parent); +const stratifyFn = stratify() + .id(d => d.id) + .parentId(d => d.parent); class Tree extends Component { - - // state = { - // startingCoordinates: null, - // isDown: false - // } - - static propTypes = { - name: PropTypes.string, - width: PropTypes.number, - allowScaleWidth: PropTypes.bool, - nodes: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - parent: PropTypes.string - })), - selectedNodeId: PropTypes.string, - onNodeClick: PropTypes.func, - onRenderedBeyondWidth: PropTypes.func - }; - - static defaultProps = { - width: 500, - allowScaleWidth : true, - name: 'default-name' - }; - - render() { - let {width, name, scrollable = false} = this.props; - return ( - <div - className={`tree-view ${name}-container ${scrollable ? 'scrollable' : ''}`}> - <svg width={width} className={name}></svg> - </div> - ); - } - - componentDidMount() { - this.renderTree(); - } - - // handleMouseMove(e) { - // if (!this.state.isDown) { - // return; - // } - // const container = select(`.tree-view.${this.props.name}-container`); - // let coordinates = this.getCoordinates(e); - // container.property('scrollLeft' , container.property('scrollLeft') + coordinates.x - this.state.startingCoordinates.x); - // container.property('scrollTop' , container.property('scrollTop') + coordinates.y - this.state.startingCoordinates.y); - // } - - // handleMouseDown(e) { - // let startingCoordinates = this.getCoordinates(e); - // this.setState({ - // startingCoordinates, - // isDown: true - // }); - // } - - // handleMouseUp() { - // this.setState({ - // startingCorrdinates: null, - // isDown: false - // }); - // } - - // getCoordinates(e) { - // var bounds = e.target.getBoundingClientRect(); - // var x = e.clientX - bounds.left; - // var y = e.clientY - bounds.top; - // return {x, y}; - // } - - componentDidUpdate(prevProps) { - if (this.props.nodes.length !== prevProps.nodes.length || - this.props.selectedNodeId !== prevProps.selectedNodeId) { - console.log('update'); - this.renderTree(); - } - } - - renderTree() { - let {width, nodes, name, allowScaleWidth, selectedNodeId, onRenderedBeyondWidth, toWiden} = this.props; - if (nodes.length > 0) { - - let horizontalSpaceBetweenLeaves = toWiden ? WIDE_HORIZONTAL_SPACES : NARROW_HORIZONTAL_SPACES; - const treeFn = tree().nodeSize([horizontalSpaceBetweenLeaves, verticalSpaceBetweenNodes]);//.size([width - 50, height - 50]) - let root = stratifyFn(nodes).sort((a, b) => a.data.name.localeCompare(b.data.name)); - let svgHeight = verticalSpaceBetweenNodes * root.height + nodeRadius * 6; - - treeFn(root); - - let nodesXValue = root.descendants().map(node => node.x); - let maxX = Math.max(...nodesXValue); - let minX = Math.min(...nodesXValue); - - let svgTempWidth = (maxX - minX) / 30 * (horizontalSpaceBetweenLeaves); - let svgWidth = svgTempWidth < width ? (width - 5) : svgTempWidth; - const svgEL = select(`svg.${name}`); - const container = select(`.tree-view.${name}-container`); - svgEL.html(''); - svgEL.attr('height', svgHeight); - let canvasWidth = width; - if (svgTempWidth > width) { - if (allowScaleWidth) { - canvasWidth = svgTempWidth; - } - // we seems to have a margin of 25px that we can still see with text - if (((svgTempWidth - 25) > width) && onRenderedBeyondWidth !== undefined) { - onRenderedBeyondWidth(); - } - }; - svgEL.attr('width', canvasWidth); - let rootGroup = svgEL.append('g').attr('transform', `translate(${svgWidth / 2 + nodeRadius},${nodeRadius * 4}) rotate(90)`); - - // handle link - rootGroup.selectAll('.link') - .data(root.descendants().slice(1)) - .enter().append('path') - .attr('class', 'link') - .attr('d', diagonal); - - let node = rootGroup.selectAll('.node') - .data(root.descendants()) - .enter().append('g') - .attr('class', node => `node ${node.children ? ' has-children' : ' leaf'} ${node.id === selectedNodeId ? 'selectedNode' : ''} ${this.props.onNodeClick ? 'clickable' : ''}`) - .attr('transform', node => 'translate(' + node.y + ',' + node.x + ')') - .on('click', node => this.onNodeClick(node)); - - node.append('circle').attr('r', nodeRadius).attr('class', 'outer-circle'); - node.append('circle').attr('r', nodeRadius - 3).attr('class', 'inner-circle'); - - node.append('text') - .attr('y', nodeRadius / 4 + 1) - .attr('x', - nodeRadius * 1.8) - .text(node => node.data.name) - .attr('transform', 'rotate(-90)'); - - let selectedNode = selectedNodeId ? root.descendants().find(node => node.id === selectedNodeId) : null; - if (selectedNode) { - - container.property('scrollLeft', (svgWidth / 4) + (svgWidth / 4 - 100) - (selectedNode.x / 30 * horizontalSpaceBetweenLeaves)); - container.property('scrollTop', (selectedNode.y / 100 * verticalSpaceBetweenNodes)); - - } else { - container.property('scrollLeft', (svgWidth / 4) + (svgWidth / 4 - 100)); - } - } - } - - onNodeClick(node) { - if (this.props.onNodeClick) { - this.props.onNodeClick(node.data); - } - } - + // state = { + // startingCoordinates: null, + // isDown: false + // } + + static propTypes = { + name: PropTypes.string, + width: PropTypes.number, + allowScaleWidth: PropTypes.bool, + nodes: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + parent: PropTypes.string + }) + ), + selectedNodeId: PropTypes.string, + onNodeClick: PropTypes.func, + onRenderedBeyondWidth: PropTypes.func + }; + + static defaultProps = { + width: 500, + allowScaleWidth: true, + name: 'default-name' + }; + + render() { + let { width, name, scrollable = false } = this.props; + return ( + <div + className={`tree-view ${name}-container ${ + scrollable ? 'scrollable' : '' + }`}> + <svg width={width} className={name} /> + </div> + ); + } + + componentDidMount() { + this.renderTree(); + } + + // handleMouseMove(e) { + // if (!this.state.isDown) { + // return; + // } + // const container = select(`.tree-view.${this.props.name}-container`); + // let coordinates = this.getCoordinates(e); + // container.property('scrollLeft' , container.property('scrollLeft') + coordinates.x - this.state.startingCoordinates.x); + // container.property('scrollTop' , container.property('scrollTop') + coordinates.y - this.state.startingCoordinates.y); + // } + + // handleMouseDown(e) { + // let startingCoordinates = this.getCoordinates(e); + // this.setState({ + // startingCoordinates, + // isDown: true + // }); + // } + + // handleMouseUp() { + // this.setState({ + // startingCorrdinates: null, + // isDown: false + // }); + // } + + // getCoordinates(e) { + // var bounds = e.target.getBoundingClientRect(); + // var x = e.clientX - bounds.left; + // var y = e.clientY - bounds.top; + // return {x, y}; + // } + + componentDidUpdate(prevProps) { + if ( + this.props.nodes.length !== prevProps.nodes.length || + this.props.selectedNodeId !== prevProps.selectedNodeId + ) { + console.log('update'); + this.renderTree(); + } + } + + renderTree() { + let { + width, + nodes, + name, + allowScaleWidth, + selectedNodeId, + onRenderedBeyondWidth, + toWiden + } = this.props; + if (nodes.length > 0) { + let horizontalSpaceBetweenLeaves = toWiden + ? WIDE_HORIZONTAL_SPACES + : NARROW_HORIZONTAL_SPACES; + const treeFn = tree().nodeSize([ + horizontalSpaceBetweenLeaves, + verticalSpaceBetweenNodes + ]); //.size([width - 50, height - 50]) + let root = stratifyFn(nodes).sort((a, b) => + a.data.name.localeCompare(b.data.name) + ); + let svgHeight = + verticalSpaceBetweenNodes * root.height + nodeRadius * 6; + + treeFn(root); + + let nodesXValue = root.descendants().map(node => node.x); + let maxX = Math.max(...nodesXValue); + let minX = Math.min(...nodesXValue); + + let svgTempWidth = + (maxX - minX) / 30 * horizontalSpaceBetweenLeaves; + let svgWidth = svgTempWidth < width ? width - 5 : svgTempWidth; + const svgEL = select(`svg.${name}`); + const container = select(`.tree-view.${name}-container`); + svgEL.html(''); + svgEL.attr('height', svgHeight); + let canvasWidth = width; + if (svgTempWidth > width) { + if (allowScaleWidth) { + canvasWidth = svgTempWidth; + } + // we seems to have a margin of 25px that we can still see with text + if ( + svgTempWidth - 25 > width && + onRenderedBeyondWidth !== undefined + ) { + onRenderedBeyondWidth(); + } + } + svgEL.attr('width', canvasWidth); + let rootGroup = svgEL + .append('g') + .attr( + 'transform', + `translate(${svgWidth / 2 + nodeRadius},${nodeRadius * + 4}) rotate(90)` + ); + + // handle link + rootGroup + .selectAll('.link') + .data(root.descendants().slice(1)) + .enter() + .append('path') + .attr('class', 'link') + .attr('d', diagonal); + + let node = rootGroup + .selectAll('.node') + .data(root.descendants()) + .enter() + .append('g') + .attr( + 'class', + node => + `node ${node.children ? ' has-children' : ' leaf'} ${ + node.id === selectedNodeId ? 'selectedNode' : '' + } ${this.props.onNodeClick ? 'clickable' : ''}` + ) + .attr( + 'transform', + node => 'translate(' + node.y + ',' + node.x + ')' + ) + .on('click', node => this.onNodeClick(node)); + + node + .append('circle') + .attr('r', nodeRadius) + .attr('class', 'outer-circle'); + node + .append('circle') + .attr('r', nodeRadius - 3) + .attr('class', 'inner-circle'); + + node + .append('text') + .attr('y', nodeRadius / 4 + 1) + .attr('x', -nodeRadius * 1.8) + .text(node => node.data.name) + .attr('transform', 'rotate(-90)'); + + let selectedNode = selectedNodeId + ? root.descendants().find(node => node.id === selectedNodeId) + : null; + if (selectedNode) { + container.property( + 'scrollLeft', + svgWidth / 4 + + (svgWidth / 4 - 100) - + selectedNode.x / 30 * horizontalSpaceBetweenLeaves + ); + container.property( + 'scrollTop', + selectedNode.y / 100 * verticalSpaceBetweenNodes + ); + } else { + container.property( + 'scrollLeft', + svgWidth / 4 + (svgWidth / 4 - 100) + ); + } + } + } + + onNodeClick(node) { + if (this.props.onNodeClick) { + this.props.onNodeClick(node.data); + } + } } export default Tree; diff --git a/openecomp-ui/src/nfvo-components/tree/Tree.stories.js b/openecomp-ui/src/nfvo-components/tree/Tree.stories.js index b29920b3ec..aca1a13402 100644 --- a/openecomp-ui/src/nfvo-components/tree/Tree.stories.js +++ b/openecomp-ui/src/nfvo-components/tree/Tree.stories.js @@ -1,119 +1,141 @@ import React from 'react'; -import {storiesOf} from '@kadira/storybook'; -import {withKnobs} from '@kadira/storybook-addon-knobs'; +import { storiesOf } from '@kadira/storybook'; +import { withKnobs } from '@kadira/storybook-addon-knobs'; import Tree from './Tree.jsx'; -import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; const stories = storiesOf('Version Tree', module); stories.addDecorator(withKnobs); const response = { - listCount: 6, - results: [ - { - 'id': '123', - 'name': '1.0', - 'description': 'string', - 'baseId': '', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '1234', - 'name': '1.1', - 'description': 'string', - 'baseId': '123', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '12345', - 'name': '2.0', - 'description': 'string', - 'baseId': '123', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '123456', - 'name': '3.0', - 'description': 'string', - 'baseId': '12345', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '1234567', - 'name': '1.2', - 'description': 'string', - 'baseId': '1234', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '12345678', - 'name': '2.1', - 'description': 'string', - 'baseId': '12345', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '123456789', - 'name': '4.0', - 'description': 'string', - 'baseId': '123456', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - }, - { - 'id': '12345678910', - 'name': '3.1', - 'description': 'string', - 'baseId': '123456', - 'status': 'Draft', - 'creationTime': '2017-06-08T08:55:37.831Z', - 'modificationTime': '2017-06-08T08:55:37.831Z' - } - ] + listCount: 6, + results: [ + { + id: '123', + name: '1.0', + description: 'string', + baseId: '', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '1234', + name: '1.1', + description: 'string', + baseId: '123', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '12345', + name: '2.0', + description: 'string', + baseId: '123', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '123456', + name: '3.0', + description: 'string', + baseId: '12345', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '1234567', + name: '1.2', + description: 'string', + baseId: '1234', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '12345678', + name: '2.1', + description: 'string', + baseId: '12345', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '123456789', + name: '4.0', + description: 'string', + baseId: '123456', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + }, + { + id: '12345678910', + name: '3.1', + description: 'string', + baseId: '123456', + status: 'Draft', + creationTime: '2017-06-08T08:55:37.831Z', + modificationTime: '2017-06-08T08:55:37.831Z' + } + ] }; -const divStyle = { width: '200px', borderStyle: 'solid', borderColor: 'black', border: '1px solid black'}; -const tree = response.results.map(item => ({id: item.id, name: item.name, parent: item.baseId})); -const nodeClickHandler = function (node) { - window.alert(node.name); +const divStyle = { + width: '200px', + borderStyle: 'solid', + borderColor: 'black', + border: '1px solid black' }; -stories.add('Classic Version Tree', () => ( - <div> - <Tree nodes={tree} onNodeClick={nodeClickHandler} selectedNodeId={'1234'}/> - </div> -)).add('Single Version Tree', () => ( - <div> - <Tree nodes={[tree[0]]} onNodeClick={nodeClickHandler}/> - </div> -)).add('Single Path Version Tree', () => ( - <div> - <Tree nodes={[tree[0], tree[1]]} onNodeClick={nodeClickHandler}/> - </div> -)).add('Empty Tree', () => ( - <div> - <Tree nodes={[]}/> - </div> -)).add('Add Tree in Version Page Frame', () => ( - <div style={divStyle}> - Tree wider than frame<br/><br/><br/> - <Tree - name={'versions-tree'} - width={200} - nodes={tree} - onRenderedBeyondWidth={() => {console.log('rendered beyond width')}} - allowScaleWidth={false} - onNodeClick={nodeClickHandler}/> - </div> -)); +const tree = response.results.map(item => ({ + id: item.id, + name: item.name, + parent: item.baseId +})); +const nodeClickHandler = function(node) { + window.alert(node.name); +}; +stories + .add('Classic Version Tree', () => ( + <div> + <Tree + nodes={tree} + onNodeClick={nodeClickHandler} + selectedNodeId={'1234'} + /> + </div> + )) + .add('Single Version Tree', () => ( + <div> + <Tree nodes={[tree[0]]} onNodeClick={nodeClickHandler} /> + </div> + )) + .add('Single Path Version Tree', () => ( + <div> + <Tree nodes={[tree[0], tree[1]]} onNodeClick={nodeClickHandler} /> + </div> + )) + .add('Empty Tree', () => ( + <div> + <Tree nodes={[]} /> + </div> + )) + .add('Add Tree in Version Page Frame', () => ( + <div style={divStyle}> + Tree wider than frame<br /> + <br /> + <br /> + <Tree + name={'versions-tree'} + width={200} + nodes={tree} + onRenderedBeyondWidth={() => { + console.log('rendered beyond width'); + }} + allowScaleWidth={false} + onNodeClick={nodeClickHandler} + /> + </div> + )); diff --git a/openecomp-ui/src/nfvo-utils/DirectedGraph.js b/openecomp-ui/src/nfvo-utils/DirectedGraph.js index 197625a013..bdaf08b995 100644 --- a/openecomp-ui/src/nfvo-utils/DirectedGraph.js +++ b/openecomp-ui/src/nfvo-utils/DirectedGraph.js @@ -15,31 +15,31 @@ */ export default class Graph { - constructor() { - this.nodes = {}; - } + constructor() { + this.nodes = {}; + } - addNode(node) { - this.nodes[node] = []; - } + addNode(node) { + this.nodes[node] = []; + } - hasNode(node) { - return this.nodes.hasOwnProperty(node); - } + hasNode(node) { + return this.nodes.hasOwnProperty(node); + } - addEdge(firstNode, secondNode, payload) { - if (!this.hasNode(firstNode)) { - this.addNode(firstNode); - } + addEdge(firstNode, secondNode, payload) { + if (!this.hasNode(firstNode)) { + this.addNode(firstNode); + } - if (!this.hasNode(secondNode)) { - this.addNode(secondNode); - } + if (!this.hasNode(secondNode)) { + this.addNode(secondNode); + } - this.nodes[firstNode].push({...payload, target: secondNode}); - } + this.nodes[firstNode].push({ ...payload, target: secondNode }); + } - getEdges(node) { - return this.nodes[node]; - } -}
\ No newline at end of file + getEdges(node) { + return this.nodes[node]; + } +} diff --git a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js index 13dfb1f0ab..5c55855027 100644 --- a/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js +++ b/openecomp-ui/src/nfvo-utils/ErrorResponseHandler.js @@ -15,62 +15,71 @@ */ import store from 'sdc-app/AppStore.js'; import React from 'react'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SubmitErrorResponse from 'nfvo-components/SubmitErrorResponse.jsx'; function showVariablesInMessage(variables, msg) { - let regex; - variables.forEach((value, index) => { - value = value.replace(';', ','); - regex = new RegExp('\'\%' + (index + 1) + '\''); - msg = msg.replace(regex, value); - }); - return msg; + let regex; + variables.forEach((value, index) => { + value = value.replace(';', ','); + regex = new RegExp("'%" + (index + 1) + "'"); + msg = msg.replace(regex, value); + }); + return msg; } function parseCatalogExceptionObject(responseJSON) { - let title, msg; - if (responseJSON.requestError && responseJSON.requestError.policyException) { - title = 'Error: ' + responseJSON.requestError.policyException.messageId; - msg = responseJSON.requestError.policyException.text; - } - else if (responseJSON.requestError && responseJSON.requestError.serviceException) { - title = 'Error: ' + responseJSON.requestError.serviceException.messageId; - msg = responseJSON.requestError.serviceException.text; - let {variables} = responseJSON.requestError.serviceException; - if (variables) { - msg = showVariablesInMessage(variables, msg); - } - } - else if (responseJSON.uploadDataErrors) { - title = i18n('Error: Upload Data Error'); - msg = (<SubmitErrorResponse validationResponse={{uploadDataErrors: responseJSON.uploadDataErrors}} />); - } - else { - title = responseJSON.status; - msg = responseJSON.message; - } - return {title, msg}; + let title, msg; + if ( + responseJSON.requestError && + responseJSON.requestError.policyException + ) { + title = 'Error: ' + responseJSON.requestError.policyException.messageId; + msg = responseJSON.requestError.policyException.text; + } else if ( + responseJSON.requestError && + responseJSON.requestError.serviceException + ) { + title = + 'Error: ' + responseJSON.requestError.serviceException.messageId; + msg = responseJSON.requestError.serviceException.text; + let { variables } = responseJSON.requestError.serviceException; + if (variables) { + msg = showVariablesInMessage(variables, msg); + } + } else if (responseJSON.uploadDataErrors) { + title = i18n('Error: Upload Data Error'); + msg = ( + <SubmitErrorResponse + validationResponse={{ + uploadDataErrors: responseJSON.uploadDataErrors + }} + /> + ); + } else { + title = responseJSON.status; + msg = responseJSON.message; + } + return { title, msg }; } -var errorResponseHandler = (error) => { - let errorData; - if (error.data) { - errorData = parseCatalogExceptionObject(error.data); - } - else { - errorData = { - title: error.statusText, - msg: error.responseText ? error.responseText : i18n('GENERIC_ERROR'), - }; - } - store.dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - ...errorData - } - }); +var errorResponseHandler = error => { + let errorData; + if (error.data) { + errorData = parseCatalogExceptionObject(error.data); + } else { + errorData = { + title: error.statusText, + msg: error.responseText ? error.responseText : i18n('GENERIC_ERROR') + }; + } + store.dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + ...errorData + } + }); }; export default errorResponseHandler; diff --git a/openecomp-ui/src/nfvo-utils/KeyMirror.js b/openecomp-ui/src/nfvo-utils/KeyMirror.js index 220fe07430..dc351af57c 100644 --- a/openecomp-ui/src/nfvo-utils/KeyMirror.js +++ b/openecomp-ui/src/nfvo-utils/KeyMirror.js @@ -13,27 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -var keyMirror = function (obj) { - var ret = {}; - var key; - var val; - if (!(obj instanceof Object && !Array.isArray(obj))) { - throw new Error('keyMirror(...): Argument must be an object.'); - } - for (key in obj) { - if (obj.hasOwnProperty(key)) { - val = obj[key]; - if (val instanceof Object) { - ret[key] = keyMirror(obj[key]); - } else if(val !== null && val !== undefined){ - ret[key] = val; - } - else { - ret[key] = Symbol(key); - } - } - } - return Object.freeze(ret); +var keyMirror = function(obj) { + var ret = {}; + var key; + var val; + if (!(obj instanceof Object && !Array.isArray(obj))) { + throw new Error('keyMirror(...): Argument must be an object.'); + } + for (key in obj) { + if (obj.hasOwnProperty(key)) { + val = obj[key]; + if (val instanceof Object) { + ret[key] = keyMirror(obj[key]); + } else if (val !== null && val !== undefined) { + ret[key] = val; + } else { + ret[key] = Symbol(key); + } + } + } + return Object.freeze(ret); }; -export default keyMirror;
\ No newline at end of file +export default keyMirror; diff --git a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js index 5b07986390..1a5817de66 100644 --- a/openecomp-ui/src/nfvo-utils/RestAPIUtil.js +++ b/openecomp-ui/src/nfvo-utils/RestAPIUtil.js @@ -18,7 +18,7 @@ import md5 from 'md5'; import axios from 'axios'; import store from 'sdc-app/AppStore.js'; -import {actionTypes as LoaderConstants} from 'nfvo-components/loader/LoaderConstants.js'; +import { actionTypes as LoaderConstants } from 'nfvo-components/loader/LoaderConstants.js'; import Configuration from 'sdc-app/config/Configuration.js'; import errorResponseHandler from './ErrorResponseHandler.js'; @@ -39,124 +39,133 @@ const STORAGE_AUTH_KEY = 'sdc-auth-token'; const REQUEST_ID_HEADER = 'X-ECOMP-RequestID'; const CONTENT_MD5_HEADER = 'Content-MD5'; - function applySecurity(options, data) { - let headers = options.headers || (options.headers = {}); - - let authToken = localStorage.getItem(STORAGE_AUTH_KEY); - if (authToken) { - headers[AUTHORIZATION_HEADER] = authToken; - } - - let catalogApiHeaders = Configuration.get('CatalogApiHeaders'), - catalogUidHeader = catalogApiHeaders && catalogApiHeaders.userId; - if (catalogUidHeader) { - headers[catalogUidHeader.name] = catalogUidHeader.value; - } - - headers[REQUEST_ID_HEADER] = uuid.create().toString(); - if (options.md5) { - let headers = options.headers; - headers[CONTENT_MD5_HEADER] = window.btoa(md5(JSON.stringify(data)).toLowerCase()); - } + let headers = options.headers || (options.headers = {}); + + let authToken = localStorage.getItem(STORAGE_AUTH_KEY); + if (authToken) { + headers[AUTHORIZATION_HEADER] = authToken; + } + + let catalogApiHeaders = Configuration.get('CatalogApiHeaders'), + catalogUidHeader = catalogApiHeaders && catalogApiHeaders.userId; + if (catalogUidHeader) { + headers[catalogUidHeader.name] = catalogUidHeader.value; + } + + headers[REQUEST_ID_HEADER] = uuid.create().toString(); + if (options.md5) { + let headers = options.headers; + headers[CONTENT_MD5_HEADER] = window.btoa( + md5(JSON.stringify(data)).toLowerCase() + ); + } } - function handleSuccess(responseHeaders, requestHeaders) { - let authToken = responseHeaders[AUTHORIZATION_HEADER]; - let prevToken = requestHeaders && requestHeaders[AUTHORIZATION_HEADER]; - if (authToken && authToken !== prevToken) { - if (authToken === 'null') { - localStorage.removeItem(STORAGE_AUTH_KEY); - } else { - localStorage.setItem(STORAGE_AUTH_KEY, authToken); - } - } + let authToken = responseHeaders[AUTHORIZATION_HEADER]; + let prevToken = requestHeaders && requestHeaders[AUTHORIZATION_HEADER]; + if (authToken && authToken !== prevToken) { + if (authToken === 'null') { + localStorage.removeItem(STORAGE_AUTH_KEY); + } else { + localStorage.setItem(STORAGE_AUTH_KEY, authToken); + } + } } -class RestAPIUtil { - handleRequest(url, type, options = {}, data){ - if (DEBUG) { - console.log('axios --> Making REST call (' + type + '): ' + url); - } - - applySecurity(options, data); - - // TODO see ig necessary or in transformrequest funtion - if (type === POST || type === PUT) { - if (data instanceof FormData) { - options.headers.contentType = MULTIPART_FORM_DATA; - } - else { - options.headers.contentType = APPLICATION_JSON; -// config.data = JSON.stringify(data); - } - - } else { - data = null; - } - - let config = { - method: type, - url: url, - headers : options.headers, - data : data - }; - - store.dispatch({type: LoaderConstants.SEND_REQUEST, url: url}); - if (options.dataType === BINARY) { - config.responseType = 'arraybuffer'; - return axios(config). - then(result => { - store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : result.config.url}); - return ({ - blob : new Blob([result.data] ), - headers : result.headers - }); - }).catch(error => { - store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : error.config.url}); - errorResponseHandler(error.response); }); - } else { - return axios(config). - then(result => { - store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : result.config.url}); - handleSuccess(result.headers, result.config.headers); - return result.data; - }).catch(error => { - store.dispatch({type: LoaderConstants.RECEIVE_RESPONSE, url : error.config.url}); - errorResponseHandler(error.response); - return Promise.reject({responseJSON: error.response.data}); - }); - } - - } - - fetch(url, options) { - return this.handleRequest(url, GET, options); - } - - get(url, options) { - return this.fetch(url, options); - } - - post(url, data, options) { - return this.handleRequest(url, POST, options, data); - } - - put(url, data, options) { - return this.handleRequest(url, PUT, options, data); - } - - destroy(url, options) { - return this.handleRequest(url, DELETE, options); - } - - - +class RestAPIUtil { + handleRequest(url, type, options = {}, data) { + if (DEBUG) { + console.log('axios --> Making REST call (' + type + '): ' + url); + } + + applySecurity(options, data); + + // TODO see ig necessary or in transformrequest funtion + if (type === POST || type === PUT) { + if (data instanceof FormData) { + options.headers.contentType = MULTIPART_FORM_DATA; + } else { + options.headers.contentType = APPLICATION_JSON; + // config.data = JSON.stringify(data); + } + } else { + data = null; + } + + let config = { + method: type, + url: url, + headers: options.headers, + data: data + }; + + store.dispatch({ type: LoaderConstants.SEND_REQUEST, url: url }); + if (options.dataType === BINARY) { + config.responseType = 'arraybuffer'; + return axios(config) + .then(result => { + store.dispatch({ + type: LoaderConstants.RECEIVE_RESPONSE, + url: result.config.url + }); + return { + blob: new Blob([result.data]), + headers: result.headers + }; + }) + .catch(error => { + store.dispatch({ + type: LoaderConstants.RECEIVE_RESPONSE, + url: error.config.url + }); + errorResponseHandler(error.response); + }); + } else { + return axios(config) + .then(result => { + store.dispatch({ + type: LoaderConstants.RECEIVE_RESPONSE, + url: result.config.url + }); + handleSuccess(result.headers, result.config.headers); + return result.data; + }) + .catch(error => { + store.dispatch({ + type: LoaderConstants.RECEIVE_RESPONSE, + url: error.config.url + }); + errorResponseHandler(error.response); + return Promise.reject({ + responseJSON: error.response.data + }); + }); + } + } + + fetch(url, options) { + return this.handleRequest(url, GET, options); + } + + get(url, options) { + return this.fetch(url, options); + } + + post(url, data, options) { + return this.handleRequest(url, POST, options, data); + } + + put(url, data, options) { + return this.handleRequest(url, PUT, options, data); + } + + destroy(url, options) { + return this.handleRequest(url, DELETE, options); + } } const instance = new RestAPIUtil(); - - export default instance; diff --git a/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js b/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js index bddd49c700..990701c6f0 100644 --- a/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js +++ b/openecomp-ui/src/nfvo-utils/ShowFileSaveDialog.js @@ -15,35 +15,48 @@ */ function getTimestampString() { - let date = new Date(); - let z = n => n < 10 ? '0' + n : n; - return `${date.getFullYear()}-${z(date.getMonth())}-${z(date.getDate())}_${z(date.getHours())}-${z(date.getMinutes())}`; + let date = new Date(); + let z = n => (n < 10 ? '0' + n : n); + return `${date.getFullYear()}-${z(date.getMonth())}-${z( + date.getDate() + )}_${z(date.getHours())}-${z(date.getMinutes())}`; } +export default function showFileSaveDialog({ + blob, + headers, + defaultFilename, + addTimestamp +}) { + let filename; + let contentDisposition = headers['content-disposition'] + ? headers['content-disposition'] + : ''; + let match = contentDisposition + ? contentDisposition.match(/filename=(.*?)(;|$)/) + : false; + if (match) { + filename = match[1]; + } else { + filename = defaultFilename; + } -export default function showFileSaveDialog({blob, headers, defaultFilename, addTimestamp}) { - let filename; - let contentDisposition = headers['content-disposition'] ? headers['content-disposition'] : ''; - let match = contentDisposition ? contentDisposition.match(/filename=(.*?)(;|$)/) : false; - if (match) { - filename = match[1]; - } else { - filename = defaultFilename; - } + if (addTimestamp) { + filename = filename.replace( + /(^.*?)\.([^.]+$)/, + `$1_${getTimestampString()}.$2` + ); + } - if (addTimestamp) { - filename = filename.replace(/(^.*?)\.([^.]+$)/, `$1_${getTimestampString()}.$2`); - } - - let link = document.createElement('a'); - let url = URL.createObjectURL(blob); - link.href = url; - link.download = filename; - link.style.display = 'none'; - document.body.appendChild(link); - link.click(); - setTimeout(function(){ - document.body.removeChild(link); - URL.revokeObjectURL(url); - }, 0); -}; + let link = document.createElement('a'); + let url = URL.createObjectURL(blob); + link.href = url; + link.download = filename; + link.style.display = 'none'; + document.body.appendChild(link); + link.click(); + setTimeout(function() { + document.body.removeChild(link); + URL.revokeObjectURL(url); + }, 0); +} diff --git a/openecomp-ui/src/nfvo-utils/UUID.js b/openecomp-ui/src/nfvo-utils/UUID.js index e1d4c54b1f..37de994201 100644 --- a/openecomp-ui/src/nfvo-utils/UUID.js +++ b/openecomp-ui/src/nfvo-utils/UUID.js @@ -15,39 +15,39 @@ */ import UUID from 'uuid-js'; -let toCustomUUID = (uuid) => { - return 'U' + uuid.replace(/-/g, ''); +let toCustomUUID = uuid => { + return 'U' + uuid.replace(/-/g, ''); }; let getUUID = function(num, isSync) { - if (isSync) { - let uuid; - if (!num) { - uuid = toCustomUUID(UUID.create().toString()); - } else { - uuid = []; - for (var i = 0; i < num; i++) { - uuid[i] = toCustomUUID(UUID.create().toString()); - } - } - if (num === 1) { - return uuid[0]; - } else { - return uuid; - } - } - return new Promise(resolve => { - let uuid; - if (!num) { - uuid = toCustomUUID(UUID.create().toString()); - } else { - uuid = []; - for (var i = 0; i < num; i++) { - uuid[i] = toCustomUUID(UUID.create().toString()); - } - } - setTimeout(() => resolve(uuid), 100); - }); + if (isSync) { + let uuid; + if (!num) { + uuid = toCustomUUID(UUID.create().toString()); + } else { + uuid = []; + for (var i = 0; i < num; i++) { + uuid[i] = toCustomUUID(UUID.create().toString()); + } + } + if (num === 1) { + return uuid[0]; + } else { + return uuid; + } + } + return new Promise(resolve => { + let uuid; + if (!num) { + uuid = toCustomUUID(UUID.create().toString()); + } else { + uuid = []; + for (var i = 0; i < num; i++) { + uuid[i] = toCustomUUID(UUID.create().toString()); + } + } + setTimeout(() => resolve(uuid), 100); + }); }; export default getUUID; diff --git a/openecomp-ui/src/nfvo-utils/Validator.js b/openecomp-ui/src/nfvo-utils/Validator.js index 0cb1943d66..324198ef2e 100644 --- a/openecomp-ui/src/nfvo-utils/Validator.js +++ b/openecomp-ui/src/nfvo-utils/Validator.js @@ -18,119 +18,189 @@ import * as ValidatorJS from 'validator'; import i18n from 'nfvo-utils/i18n/i18n.js'; class Validator { - static get globalValidationFunctions() { - return { - required: value => { - return typeof value === 'string' ? value.replace(/\s+/g, '') !== '' : 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), - numeric: value => { - if (value === '') { - // to allow empty value which is not zero - return true; - } - return ValidatorJS.isNumeric(value); - }, - 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'), - validateVendorName: value => ValidatorJS.isAlphanumeric(value.replace(/[\x7F-\xFF]|\s/g, ''), 'en-US'), - 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), - alphanumericWithUnderscores: value => ValidatorJS.isAlphanumeric(value.replace(/_/g, '')), - requiredChoiceWithOther: (value, otherValue) => { - let chosen = value.choice; - // if we have an empty multiple select we have a problem since it's required - let validationFunc = this.globalValidationFunctions['required']; - if (value.choices) { - if (value.choices.length === 0) { - return false; - } else { - // continuing validation with the first chosen value in case we have the 'Other' field - chosen = value.choices[0]; - } - } - if (chosen !== otherValue) { - return validationFunc(chosen, true); - } else { // when 'Other' was chosen, validate other value - return validationFunc(value.other, true); - } - } - }; - } + static get globalValidationFunctions() { + return { + required: value => { + return typeof value === 'string' + ? value.replace(/\s+/g, '') !== '' + : 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), + numeric: value => { + if (value === '') { + // to allow empty value which is not zero + return true; + } + return ValidatorJS.isNumeric(value); + }, + 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' + ), + validateVendorName: value => + ValidatorJS.isAlphanumeric( + value.replace(/[\x7F-\xFF]|\s/g, ''), + 'en-US' + ), + 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), + alphanumericWithUnderscores: value => + ValidatorJS.isAlphanumeric(value.replace(/_/g, '')), + requiredChoiceWithOther: (value, otherValue) => { + let chosen = value.choice; + // if we have an empty multiple select we have a problem since it's required + let validationFunc = this.globalValidationFunctions['required']; + if (value.choices) { + if (value.choices.length === 0) { + return false; + } else { + // continuing validation with the first chosen value in case we have the 'Other' field + chosen = value.choices[0]; + } + } + if (chosen !== otherValue) { + return validationFunc(chosen, true); + } else { + // when 'Other' was chosen, validate other value + return validationFunc(value.other, true); + } + } + }; + } - static get globalValidationMessagingFunctions() { - return { - required: () => i18n('Field is required'), - requiredChooseOption: () => i18n('Field should have one of these options'), - requiredChoiceWithOther: () => i18n('Field is required'), - 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: minLength}), - pattern: (value, pattern) => i18n('Field value should match the pattern: {pattern}.', {pattern: pattern}), - numeric: () => i18n('Field value should contain numbers only.'), - maximum: (value, maxValue) => i18n('Field value should be less or equal to: {maxValue}.', {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: maxValue}), - minimumExclusive: (value, minValue) => i18n('Field value should be more than: {minValue}.', {minValue: 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.'), - validateVendorName: ()=> i18n('Field value should contain English letters digits and spaces only.'), - freeEnglishText: ()=> i18n('Field value should contain English letters, digits , spaces, underscores, dashes and dots only.'), - 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.'), - alphanumericWithUnderscores: () => i18n('Field value should contain letters, digits or _ only.') - }; - } + static get globalValidationMessagingFunctions() { + return { + required: () => i18n('Field is required'), + requiredChooseOption: () => + i18n('Field should have one of these options'), + requiredChoiceWithOther: () => i18n('Field is required'), + 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: minLength + } + ), + pattern: (value, pattern) => + i18n('Field value should match the pattern: {pattern}.', { + pattern: pattern + }), + numeric: () => i18n('Field value should contain numbers only.'), + maximum: (value, maxValue) => + i18n('Field value should be less or equal to: {maxValue}.', { + 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: maxValue + }), + minimumExclusive: (value, minValue) => + i18n('Field value should be more than: {minValue}.', { + minValue: 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.' + ), + validateVendorName: () => + i18n( + 'Field value should contain English letters digits and spaces only.' + ), + freeEnglishText: () => + i18n( + 'Field value should contain English letters, digits , spaces, underscores, dashes and dots only.' + ), + 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.'), + alphanumericWithUnderscores: () => + i18n('Field value should contain letters, digits or _ only.') + }; + } - static validateItem(value, data, type) { - let validationFunc = this.globalValidationFunctions[type]; - const isValid = validationFunc(value, data); - let errorText = ''; - if (!isValid) { - errorText = this.globalValidationMessagingFunctions[type](value, data); - } - return { - isValid, - errorText - }; - } + static validateItem(value, data, type) { + let validationFunc = this.globalValidationFunctions[type]; + const isValid = validationFunc(value, data); + let errorText = ''; + if (!isValid) { + errorText = this.globalValidationMessagingFunctions[type]( + value, + data + ); + } + return { + isValid, + errorText + }; + } - static validate(fieldName, value, validations, state, customValidations) { - let result = { isValid: true, errorText: '' }; - for (let validation of validations) { - result = this.validateItem(value, validation.data, validation.type); - if (!result.isValid) { - return result; - } - } - if (customValidations) { - let validationFunc = customValidations[fieldName]; - if (validationFunc) { - result = validationFunc(value, state); - } - } - return result; - } + static validate(fieldName, value, validations, state, customValidations) { + let result = { isValid: true, errorText: '' }; + for (let validation of validations) { + result = this.validateItem(value, validation.data, validation.type); + if (!result.isValid) { + return result; + } + } + if (customValidations) { + let validationFunc = customValidations[fieldName]; + if (validationFunc) { + result = validationFunc(value, state); + } + } + return result; + } - static isItemNameAlreadyExistsInList({itemId, itemName, list}) { - itemName = itemName.toLowerCase(); - return list[itemName] && list[itemName] !== itemId; - } + static isItemNameAlreadyExistsInList({ itemId, itemName, list }) { + itemName = itemName.toLowerCase(); + return list[itemName] && list[itemName] !== itemId; + } } export default Validator; diff --git a/openecomp-ui/src/nfvo-utils/WebSocketUtil.js b/openecomp-ui/src/nfvo-utils/WebSocketUtil.js index c9dd10f1af..69f44d4da5 100644 --- a/openecomp-ui/src/nfvo-utils/WebSocketUtil.js +++ b/openecomp-ui/src/nfvo-utils/WebSocketUtil.js @@ -16,41 +16,50 @@ import store from 'sdc-app/AppStore.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from 'sdc-app/onboarding/userNotifications/UserNotificationsConstants.js'; +import { actionTypes } from 'sdc-app/onboarding/userNotifications/UserNotificationsConstants.js'; - -export const websocketUrl = 'ws://' + window.location.hostname + ':' + Configuration.get('websocketPort') - + '/' + Configuration.get('websocketPath'); +export const websocketUrl = + 'ws://' + + window.location.hostname + + ':' + + Configuration.get('websocketPort') + + '/' + + Configuration.get('websocketPath'); /*** * Websocket is treated like a singleton. only need one for the application. */ var websocket; - export default { + open(url, { lastScanned }) { + if ( + websocket === undefined || + websocket.readyState === websocket.CLOSED + ) { + websocket = new WebSocket( + `${url}?LAST_DELIVERED_EVENT_ID=${lastScanned}` + ); + websocket.onmessage = event => + store.dispatch({ + type: actionTypes.NOTIFICATION, + data: JSON.parse(event.data) + }); + websocket.onclose = event => { + if (event.code && event.code === 1001) { + // - Idle Timeout + const { lastScanned } = store.getState().notifications; + console.log('Reconnecting to Websocket'); + this.open(websocketUrl, { lastScanned }); + } + }; + websocket.onerror = event => console.log(event); + } + }, - open(url, {lastScanned}) { - if (websocket === undefined || websocket.readyState === websocket.CLOSED) { - websocket = new WebSocket(`${url}?LAST_DELIVERED_EVENT_ID=${lastScanned}`); - websocket.onmessage = event => store.dispatch({ - type: actionTypes.NOTIFICATION, - data: JSON.parse(event.data) - }); - websocket.onclose = event => { - if(event.code && event.code === 1001) { // - Idle Timeout - const {lastScanned} = store.getState().notifications; - console.log('Reconnecting to Websocket'); - this.open(websocketUrl, {lastScanned}); - } - }; - websocket.onerror = event => console.log(event); - } - }, - - close() { - if (websocket !== undefined) { - websocket.close(); - } - } + close() { + if (websocket !== undefined) { + websocket.close(); + } + } }; diff --git a/openecomp-ui/src/nfvo-utils/getValue.js b/openecomp-ui/src/nfvo-utils/getValue.js index 5ab0c76d73..0cac3cd726 100644 --- a/openecomp-ui/src/nfvo-utils/getValue.js +++ b/openecomp-ui/src/nfvo-utils/getValue.js @@ -13,38 +13,50 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; function getValueFromObject(element) { - return element.choices && element.choices.length > 0 && element.choices[0] !== '' && element.choices[0] !== optionInputOther.OTHER || - element.other && element.choices[0] === optionInputOther.OTHER ? - element : undefined; + return (element.choices && + element.choices.length > 0 && + element.choices[0] !== '' && + element.choices[0] !== optionInputOther.OTHER) || + (element.other && element.choices[0] === optionInputOther.OTHER) + ? element + : undefined; } function getValueFromVariable(variable) { - return variable ? variable : undefined; + return variable ? variable : undefined; } function getArrayData(variable) { - return variable.length ? variable : undefined; + return variable.length ? variable : undefined; } - let getValue = element => { - return typeof element === 'object' ? - element instanceof Array ? getArrayData(element) : getValueFromObject(element) : - getValueFromVariable(element); - }; +let getValue = element => { + return typeof element === 'object' + ? element instanceof Array + ? getArrayData(element) + : getValueFromObject(element) + : getValueFromVariable(element); +}; export function getStrValue(choiceObject) { - if (!choiceObject) { - return undefined; - } - if (choiceObject.choice && choiceObject.choice !== '' && choiceObject.choice !== optionInputOther.OTHER) { - return choiceObject.choice; - } - else if (choiceObject.other && choiceObject.choice === optionInputOther.OTHER) { - return choiceObject.other; - } + if (!choiceObject) { + return undefined; + } + if ( + choiceObject.choice && + choiceObject.choice !== '' && + choiceObject.choice !== optionInputOther.OTHER + ) { + return choiceObject.choice; + } else if ( + choiceObject.other && + choiceObject.choice === optionInputOther.OTHER + ) { + return choiceObject.other; + } } - export default getValue; +export default getValue; diff --git a/openecomp-ui/src/nfvo-utils/i18n/i18n.js b/openecomp-ui/src/nfvo-utils/i18n/i18n.js index ef97b8bab4..43a183def4 100644 --- a/openecomp-ui/src/nfvo-utils/i18n/i18n.js +++ b/openecomp-ui/src/nfvo-utils/i18n/i18n.js @@ -22,88 +22,94 @@ 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 Intl = window.Intl || IntlObj.default, + IntlMessageFormat = IntlMessageFormatObj.default, + IntlRelativeFormat = IntlRelativeFormatObj.default, + createFormatCache = createFormatCacheObj.default; /*extract locale*/ var _locale = window.localStorage && localStorage.getItem('user_locale'); -if(!_locale) { - if(window.navigator) { - _locale = navigator.language || navigator.userLanguage; +if (!_locale) { + if (window.navigator) { + _locale = navigator.language || navigator.userLanguage; - //For now removing the dashes from the language. - let indexOfDash = _locale.indexOf('-'); - if(-1 !== indexOfDash) { - _locale = _locale.substr(0, indexOfDash); - } - } - if(!_locale) { - _locale = 'en'; - } + //For now removing the dashes from the language. + let indexOfDash = _locale.indexOf('-'); + if (-1 !== indexOfDash) { + _locale = _locale.substr(0, indexOfDash); + } + } + if (!_locale) { + _locale = 'en'; + } } var _localeUpper = _locale.toUpperCase(); var i18n = { + _locale: _locale, + _localeUpper: _localeUpper, + _i18nData: i18nJson || {}, - _locale: _locale, - _localeUpper: _localeUpper, - _i18nData: i18nJson || {}, + number(num) { + return createFormatCache(Intl.NumberFormat)(this._locale).format(num); + }, - number(num) { - return createFormatCache(Intl.NumberFormat)(this._locale).format(num); - }, + date(date, options, relativeDates) { + if (undefined === relativeDates || relativeDates) { + return this.dateRelative(date, options); + } else { + return this.dateNormal(date, options); + } + }, - date(date, options, relativeDates) { - if (undefined === relativeDates || relativeDates) { - return this.dateRelative(date, options); - } else { - return this.dateNormal(date, options); - } - }, - - dateNormal(date, options) { - return createFormatCache(Intl.DateTimeFormat)(this._locale, options).format(date); - }, - - dateRelative(date, options) { - return createFormatCache(IntlRelativeFormat)(this._locale, options).format(date); - }, - message(messageId, options) { - let messageTxt = null; - if (i18nJson && i18nJson[messageId]) { - messageTxt = i18nJson[messageId]; - } else { - messageTxt = String(messageId); - } - return createFormatCache(IntlMessageFormat)(messageTxt, this._locale).format(options); - - }, - getLocale() { - return this._locale; - }, - getLocaleUpper() { - return this._localeUpper; - }, - setLocale(locale) { - localStorage.setItem('user_locale', locale); - window.location.reload(); - } + dateNormal(date, options) { + return createFormatCache(Intl.DateTimeFormat)( + this._locale, + options + ).format(date); + }, + dateRelative(date, options) { + return createFormatCache(IntlRelativeFormat)( + this._locale, + options + ).format(date); + }, + message(messageId, options) { + let messageTxt = null; + if (i18nJson && i18nJson[messageId]) { + messageTxt = i18nJson[messageId]; + } else { + messageTxt = String(messageId); + } + return createFormatCache(IntlMessageFormat)( + messageTxt, + this._locale + ).format(options); + }, + 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); + return i18nWrapper.message.apply(i18nWrapper, arguments); } /*replace with some kind of extend method*/ var prop, propKey; for (propKey in i18n) { - prop = i18n[propKey]; - if (typeof prop === 'function') { - prop = prop.bind(i18nWrapper); - } - i18nWrapper[propKey] = prop; + prop = i18n[propKey]; + if (typeof prop === 'function') { + prop = prop.bind(i18nWrapper); + } + i18nWrapper[propKey] = prop; } export default i18nWrapper; diff --git a/openecomp-ui/src/nfvo-utils/i18n/i18n.stories.js b/openecomp-ui/src/nfvo-utils/i18n/i18n.stories.js index 816915b1c9..79f95057a0 100644 --- a/openecomp-ui/src/nfvo-utils/i18n/i18n.stories.js +++ b/openecomp-ui/src/nfvo-utils/i18n/i18n.stories.js @@ -1,35 +1,51 @@ import React from 'react'; -import {storiesOf, action} from '@kadira/storybook'; -import {text, number} from '@kadira/storybook-addon-knobs'; -import {withKnobs} from '@kadira/storybook-addon-knobs'; +import { storiesOf } from '@kadira/storybook'; +import { withKnobs } from '@kadira/storybook-addon-knobs'; import i18n from 'nfvo-utils/i18n/i18n.js'; import i18nJson from 'nfvo-utils/i18n/en.json'; const stories = storiesOf('i18n', module); stories.addDecorator(withKnobs); - i18nJson['added'] = 'this is my test'; i18nJson['added with {param}'] = 'this is my test with {param}'; -stories - .add('i18n tests', () => { - let keys = [ - 'I do not exist', - 'Delete', - 'OrchestrationTemplateCandidate/File Structure' - ]; - let translations = []; - let i=0; - translations.push(<div id={i++}>KEY: VALUE</div>) - keys.forEach((key) => { - translations.push((<div id={i++}>{key} : {i18n(key)} </div>)); - }); - var param = 'param'; - translations.push((<div id={i++}>added : {i18n('added')} </div>)); - translations.push((<div id={i++}><font color="red"><b>WRONG</b></font> - added with ${param} in translation : {i18n(`added with ${param}`)} </div>)); - translations.push((<div id={i++}><font color="green"><b>RIGHT</b></font> - added with ${param} and options object {JSON.stringify({param:param})}: {i18n('added with {param}', {param: param})} </div>)); +stories.add('i18n tests', () => { + let keys = [ + 'I do not exist', + 'Delete', + 'OrchestrationTemplateCandidate/File Structure' + ]; + let translations = []; + let i = 0; + translations.push(<div id={i++}>KEY: VALUE</div>); + keys.forEach(key => { + translations.push( + <div id={i++}> + {key} : {i18n(key)}{' '} + </div> + ); + }); + var param = 'param'; + translations.push(<div id={i++}>added : {i18n('added')} </div>); + translations.push( + <div id={i++}> + <font color="red"> + <b>WRONG</b> + </font>{' '} + - added with ${param} in translation : {i18n(`added with ${param}`)}{' '} + </div> + ); + translations.push( + <div id={i++}> + <font color="green"> + <b>RIGHT</b> + </font>{' '} + - added with ${param} and options object{' '} + {JSON.stringify({ param: param })}:{' '} + {i18n('added with {param}', { param: param })}{' '} + </div> + ); - return (<div>{translations}</div>); - }) -; + return <div>{translations}</div>; +}); diff --git a/openecomp-ui/src/nfvo-utils/json/JSONPointer.js b/openecomp-ui/src/nfvo-utils/json/JSONPointer.js index f4c0d4ed59..66c67dd234 100644 --- a/openecomp-ui/src/nfvo-utils/json/JSONPointer.js +++ b/openecomp-ui/src/nfvo-utils/json/JSONPointer.js @@ -14,44 +14,47 @@ * permissions and limitations under the License. */ const JSONPointer = { - - extractParentPointer(pointer) { - return pointer.replace(/\/[^\/]+$/, ''); - }, - - extractLastPart(pointer) { - const [,lastPart] = pointer.match(/\/([^\/]+)$/) || []; - return lastPart; - }, - - extractParts(pointer = '') { - return pointer.split('/').slice(1) - .map(part => part.replace(/~1/g, '/')) - .map(part => part.replace(/~0/g, '~')); - }, - - getValue(object, pointer) { - let parts = JSONPointer.extractParts(pointer); - return parts.reduce((object, part) => object && object[part], object); - }, - - setValue(object, pointer, value) { - let clone = obj => Array.isArray(obj) ? [...obj] : {...obj}; - - let parts = JSONPointer.extractParts(pointer), - newObject = clone(object), - subObject = object, - subNewObject = newObject; - - for(let i = 0, n = parts.length - 1; i < n; ++i) { - let nextSubObject = subObject && subObject[parts[i]]; - subNewObject = subNewObject[parts[i]] = nextSubObject ? clone(nextSubObject) : {}; - subObject = nextSubObject; - } - subNewObject[parts[parts.length - 1]] = value; - - return newObject; - } + extractParentPointer(pointer) { + return pointer.replace(/\/[^\/]+$/, ''); + }, + + extractLastPart(pointer) { + const [, lastPart] = pointer.match(/\/([^\/]+)$/) || []; + return lastPart; + }, + + extractParts(pointer = '') { + return pointer + .split('/') + .slice(1) + .map(part => part.replace(/~1/g, '/')) + .map(part => part.replace(/~0/g, '~')); + }, + + getValue(object, pointer) { + let parts = JSONPointer.extractParts(pointer); + return parts.reduce((object, part) => object && object[part], object); + }, + + setValue(object, pointer, value) { + let clone = obj => (Array.isArray(obj) ? [...obj] : { ...obj }); + + let parts = JSONPointer.extractParts(pointer), + newObject = clone(object), + subObject = object, + subNewObject = newObject; + + for (let i = 0, n = parts.length - 1; i < n; ++i) { + let nextSubObject = subObject && subObject[parts[i]]; + subNewObject = subNewObject[parts[i]] = nextSubObject + ? clone(nextSubObject) + : {}; + subObject = nextSubObject; + } + subNewObject[parts[parts.length - 1]] = value; + + return newObject; + } }; export default JSONPointer; diff --git a/openecomp-ui/src/nfvo-utils/json/JSONSchema.js b/openecomp-ui/src/nfvo-utils/json/JSONSchema.js index 3b3a9bf7b4..53d288f3ae 100644 --- a/openecomp-ui/src/nfvo-utils/json/JSONSchema.js +++ b/openecomp-ui/src/nfvo-utils/json/JSONSchema.js @@ -18,235 +18,264 @@ import cloneDeep from 'lodash/cloneDeep.js'; import JSONPointer from './JSONPointer.js'; export default class JSONSchema { - - setSchema(schema) { - this._schema = schema; - this._fragmentsCache = new Map(); - // this._ajv = new Ajv({ - // useDefaults: true, - // coerceTypes: true - // }); - // this._validate = this._ajv.compile(schema); - } - - processData(data) { - data = cloneDeep(data); - // this._validate(data); - return data; - } - - // array of names of validation functions - setSupportedValidationFunctions(supportedValidationFunctions) { - this._supportedValidationFunctions = supportedValidationFunctions; - } - - /* FYI - I was going to support "required" but then found out that server never sends it in its schema (it was a business decision. so leaving the code commented for now */ - flattenSchema(supportedValidationFunctions) { - if (supportedValidationFunctions) { this.setSupportedValidationFunctions(supportedValidationFunctions); } - let genericFieldInfo = {}; - if (this._schema && this._schema.properties) { - this.travelProperties(this._schema.properties, genericFieldInfo/*, this._schema.required*/); - } - return {genericFieldInfo}; - } - - extractGenericFieldInfo(item) { - let validationsArr = []; - let additionalInfo = { isValid: true, errorText: ''}; - for (let value in item) { - if (this._supportedValidationFunctions.includes(value)) { - let validationItem = this.extractValidations(item, value); - validationsArr[validationsArr.length] = validationItem; - } else { - let enumResult = this.extractEnum(item, value); - if (enumResult !== null) { - additionalInfo.enum = enumResult; - } - else { - additionalInfo[value] = item[value]; - } - /*if (required.includes (property)) { + setSchema(schema) { + this._schema = schema; + this._fragmentsCache = new Map(); + // this._ajv = new Ajv({ + // useDefaults: true, + // coerceTypes: true + // }); + // this._validate = this._ajv.compile(schema); + } + + processData(data) { + data = cloneDeep(data); + // this._validate(data); + return data; + } + + // array of names of validation functions + setSupportedValidationFunctions(supportedValidationFunctions) { + this._supportedValidationFunctions = supportedValidationFunctions; + } + + /* FYI - I was going to support "required" but then found out that server never sends it in its schema (it was a business decision. so leaving the code commented for now */ + flattenSchema(supportedValidationFunctions) { + if (supportedValidationFunctions) { + this.setSupportedValidationFunctions(supportedValidationFunctions); + } + let genericFieldInfo = {}; + if (this._schema && this._schema.properties) { + this.travelProperties( + this._schema.properties, + genericFieldInfo /*, this._schema.required*/ + ); + } + return { genericFieldInfo }; + } + + extractGenericFieldInfo(item) { + let validationsArr = []; + let additionalInfo = { isValid: true, errorText: '' }; + for (let value in item) { + if (this._supportedValidationFunctions.includes(value)) { + let validationItem = this.extractValidations(item, value); + validationsArr[validationsArr.length] = validationItem; + } else { + let enumResult = this.extractEnum(item, value); + if (enumResult !== null) { + additionalInfo.enum = enumResult; + } else { + additionalInfo[value] = item[value]; + } + /*if (required.includes (property)) { additionalInfo[value].isRequired = true ; }*/ - } - } - - additionalInfo.validations = validationsArr; - return additionalInfo; - } - - extractValidations(item, value) { - let validationItem; - let data = item[value]; - if (value === 'maximum') { - if (item.exclusiveMaximum) { - value = 'maximumExclusive'; - } - } - if (value === 'minimum') { - if (item.exclusiveMinimum) { - value = 'minimumExclusive'; - } - } - validationItem = {type: value, data: data}; - return validationItem; - } - - extractEnum(item, value) { - let enumResult = null; - if (value === 'type' && item[value] === 'array') { - let items = item.items; - if (items && items.enum && items.enum.length > 0) { - let values = items.enum - .filter(value => value) - .map(value => ({enum: value, title: value})); - enumResult = values; - } - } - else if (value === 'enum') { - let items = item[value]; - if (items && items.length > 0) { - let values = items - .filter(value => value) - .map(value => ({enum: value, title: value})); - enumResult = values; - } - } - return enumResult; - } - - travelProperties(properties, genericFieldDefs, /*required = [],*/ pointer = ''){ - let newPointer = pointer; - for (let property in properties) { - newPointer = newPointer ? newPointer + '/' + property : property; - if (properties[property].properties) { - this.travelProperties(properties[property].properties, genericFieldDefs /*, properties[property].required*/, newPointer); - } - else if (properties[property].$ref){ - let fragment = this._getSchemaFragmentByRef(properties[property].$ref); - if (fragment.properties) { - this.travelProperties(fragment.properties, genericFieldDefs /*, properties[property].required*/, newPointer); - } else { - genericFieldDefs[newPointer] = this.extractGenericFieldInfo(fragment.properties); - } - } - else { - genericFieldDefs[newPointer] = this.extractGenericFieldInfo(properties[property]); - } - newPointer = pointer; - } - } - - getTitle(pointer) { - return this._getSchemaFragment(pointer).title; - } - - exists(pointer) { - const fragment = this._getSchemaFragment(pointer); - return !!fragment; - } - - getDefault(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.default; - } - - getEnum(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && (fragment.type === 'array' ? fragment.items.enum : fragment.enum); - } - - isRequired(pointer) { - const parentPointer = JSONPointer.extractParentPointer(pointer); - const lastPart = JSONPointer.extractLastPart(pointer); - let parentFragment = this._getSchemaFragment(parentPointer); - return parentFragment && parentFragment.required && parentFragment.required.includes(lastPart); - } - - isNumber(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.type === 'number'; - } - - getMaxValue(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.exclusiveMaximum ? fragment.maximum - 1 : fragment.maximum; - } - - getMinValue(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.exclusiveMinimum ? fragment.minimum : fragment.minimum; - } - - isString(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.type === 'string'; - } - - getPattern(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.pattern; - } - - getMaxLength(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.maxLength; - } - - getMinLength(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.minLength; - } - - isArray(pointer) { - const fragment = this._getSchemaFragment(pointer); - return fragment && fragment.type === 'array'; - } - - _getSchemaFragment(pointer) { - if (this._fragmentsCache.has(pointer)) { - return this._fragmentsCache.get(pointer); - } - - let parts = JSONPointer.extractParts(pointer); - - let fragment = parts.reduce((fragment, part) => { - if (fragment === undefined) { - return undefined; - } - - if (fragment.$ref) { - fragment = this._getSchemaFragmentByRef(fragment.$ref); - } - - switch (fragment.type) { - case 'object': - return fragment.properties && fragment.properties[part]; - - case 'array': - return fragment.enum && fragment.enum[part]; - - default: - // throw new Error(`Incorrect/unsupported JSONPointer "${pointer}" from "${part}"`); - return undefined; - } - }, this._schema); - - while(fragment && fragment.$ref) { - fragment = this._getSchemaFragmentByRef(fragment.$ref); - } - - this._fragmentsCache.set(pointer, fragment); - return fragment; - } - - _getSchemaFragmentByRef($ref) { - let pointer = $ref.substr(1); - return JSONPointer.getValue(this._schema, pointer); - // let fragmentAjv = new Ajv(); - // fragmentAjv.addSchema(this._schema); - // let compiledFragment = fragmentAjv.compile({$ref}); - // let fragment = compiledFragment.refVal[compiledFragment.refs[$ref]]; - // return fragment; - } -}; + } + } + + additionalInfo.validations = validationsArr; + return additionalInfo; + } + + extractValidations(item, value) { + let validationItem; + let data = item[value]; + if (value === 'maximum') { + if (item.exclusiveMaximum) { + value = 'maximumExclusive'; + } + } + if (value === 'minimum') { + if (item.exclusiveMinimum) { + value = 'minimumExclusive'; + } + } + validationItem = { type: value, data: data }; + return validationItem; + } + + extractEnum(item, value) { + let enumResult = null; + if (value === 'type' && item[value] === 'array') { + let items = item.items; + if (items && items.enum && items.enum.length > 0) { + let values = items.enum + .filter(value => value) + .map(value => ({ enum: value, title: value })); + enumResult = values; + } + } else if (value === 'enum') { + let items = item[value]; + if (items && items.length > 0) { + let values = items + .filter(value => value) + .map(value => ({ enum: value, title: value })); + enumResult = values; + } + } + return enumResult; + } + + travelProperties( + properties, + genericFieldDefs, + /*required = [],*/ pointer = '' + ) { + let newPointer = pointer; + for (let property in properties) { + newPointer = newPointer ? newPointer + '/' + property : property; + if (properties[property].properties) { + this.travelProperties( + properties[property].properties, + genericFieldDefs /*, properties[property].required*/, + newPointer + ); + } else if (properties[property].$ref) { + let fragment = this._getSchemaFragmentByRef( + properties[property].$ref + ); + if (fragment.properties) { + this.travelProperties( + fragment.properties, + genericFieldDefs /*, properties[property].required*/, + newPointer + ); + } else { + genericFieldDefs[newPointer] = this.extractGenericFieldInfo( + fragment.properties + ); + } + } else { + genericFieldDefs[newPointer] = this.extractGenericFieldInfo( + properties[property] + ); + } + newPointer = pointer; + } + } + + getTitle(pointer) { + return this._getSchemaFragment(pointer).title; + } + + exists(pointer) { + const fragment = this._getSchemaFragment(pointer); + return !!fragment; + } + + getDefault(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.default; + } + + getEnum(pointer) { + const fragment = this._getSchemaFragment(pointer); + return ( + fragment && + (fragment.type === 'array' ? fragment.items.enum : fragment.enum) + ); + } + + isRequired(pointer) { + const parentPointer = JSONPointer.extractParentPointer(pointer); + const lastPart = JSONPointer.extractLastPart(pointer); + let parentFragment = this._getSchemaFragment(parentPointer); + return ( + parentFragment && + parentFragment.required && + parentFragment.required.includes(lastPart) + ); + } + + isNumber(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.type === 'number'; + } + + getMaxValue(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.exclusiveMaximum + ? fragment.maximum - 1 + : fragment.maximum; + } + + getMinValue(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.exclusiveMinimum + ? fragment.minimum + : fragment.minimum; + } + + isString(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.type === 'string'; + } + + getPattern(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.pattern; + } + + getMaxLength(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.maxLength; + } + + getMinLength(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.minLength; + } + + isArray(pointer) { + const fragment = this._getSchemaFragment(pointer); + return fragment && fragment.type === 'array'; + } + + _getSchemaFragment(pointer) { + if (this._fragmentsCache.has(pointer)) { + return this._fragmentsCache.get(pointer); + } + + let parts = JSONPointer.extractParts(pointer); + + let fragment = parts.reduce((fragment, part) => { + if (fragment === undefined) { + return undefined; + } + + if (fragment.$ref) { + fragment = this._getSchemaFragmentByRef(fragment.$ref); + } + + switch (fragment.type) { + case 'object': + return fragment.properties && fragment.properties[part]; + + case 'array': + return fragment.enum && fragment.enum[part]; + + default: + // throw new Error(`Incorrect/unsupported JSONPointer "${pointer}" from "${part}"`); + return undefined; + } + }, this._schema); + + while (fragment && fragment.$ref) { + fragment = this._getSchemaFragmentByRef(fragment.$ref); + } + + this._fragmentsCache.set(pointer, fragment); + return fragment; + } + + _getSchemaFragmentByRef($ref) { + let pointer = $ref.substr(1); + return JSONPointer.getValue(this._schema, pointer); + // let fragmentAjv = new Ajv(); + // fragmentAjv.addSchema(this._schema); + // let compiledFragment = fragmentAjv.compile({$ref}); + // let fragment = compiledFragment.refVal[compiledFragment.refs[$ref]]; + // return fragment; + } +} diff --git a/openecomp-ui/src/nfvo-utils/sortByStringProperty.js b/openecomp-ui/src/nfvo-utils/sortByStringProperty.js index b415dd7e07..89e9f4034c 100644 --- a/openecomp-ui/src/nfvo-utils/sortByStringProperty.js +++ b/openecomp-ui/src/nfvo-utils/sortByStringProperty.js @@ -14,5 +14,7 @@ * permissions and limitations under the License. */ export default function sortByStringProperty(array, property) { - return [...array].sort((a, b) => a[property].toLowerCase().localeCompare(b[property].toLowerCase())); + return [...array].sort((a, b) => + a[property].toLowerCase().localeCompare(b[property].toLowerCase()) + ); } diff --git a/openecomp-ui/src/sdc-app/AppStore.js b/openecomp-ui/src/sdc-app/AppStore.js index bafef7dcd6..bca750a930 100644 --- a/openecomp-ui/src/sdc-app/AppStore.js +++ b/openecomp-ui/src/sdc-app/AppStore.js @@ -14,24 +14,27 @@ * limitations under the License. */ -import {createStore, applyMiddleware, compose} from 'redux'; +import { createStore, applyMiddleware, compose } from 'redux'; import Reducers from './Reducers.js'; const thunk = store => next => action => - typeof action === 'function' ? - action(store.dispatch, store.getState) : - next(action); - + typeof action === 'function' + ? action(store.dispatch, store.getState) + : next(action); const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; -export const storeCreator = (initialState) => createStore(Reducers, initialState, composeEnhancers(applyMiddleware(thunk))); - +export const storeCreator = initialState => + createStore( + Reducers, + initialState, + composeEnhancers(applyMiddleware(thunk)) + ); const store = storeCreator(); if (module.hot) { - module.hot.accept('./Reducers.js', () => - store.replaceReducer(require('./Reducers.js').default) - ); + module.hot.accept('./Reducers.js', () => + store.replaceReducer(require('./Reducers.js').default) + ); } export default store; diff --git a/openecomp-ui/src/sdc-app/Application.jsx b/openecomp-ui/src/sdc-app/Application.jsx index aa81eb384c..abebb6d89a 100644 --- a/openecomp-ui/src/sdc-app/Application.jsx +++ b/openecomp-ui/src/sdc-app/Application.jsx @@ -15,7 +15,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {Provider} from 'react-redux'; +import { Provider } from 'react-redux'; import GlobalModal from 'nfvo-components/modal/GlobalModal.js'; import Loader from 'nfvo-components/loader/Loader.jsx'; import WebSocketUtil from 'nfvo-utils/WebSocketUtil.js'; @@ -24,31 +24,32 @@ import store from './AppStore.js'; import FeaturesActionHelper from 'sdc-app/features/FeaturesActionHelper.js'; class Application extends React.Component { - static propTypes = { - openSocket: PropTypes.bool - }; - componentDidMount() { - const {openSocket = true} = this.props; - if(openSocket) { - UserNotificationsActionHelper.notificationsFirstHandling(store.dispatch); - } - FeaturesActionHelper.getFeaturesList(store.dispatch); - } - componentWillUnmount() { - WebSocketUtil.close(); - } - render() { - return ( - <Provider store={store}> - <div> - <GlobalModal/> - {this.props.children} - <Loader /> - </div> - </Provider> - ); - } + static propTypes = { + openSocket: PropTypes.bool + }; + componentDidMount() { + const { openSocket = true } = this.props; + if (openSocket) { + UserNotificationsActionHelper.notificationsFirstHandling( + store.dispatch + ); + } + FeaturesActionHelper.getFeaturesList(store.dispatch); + } + componentWillUnmount() { + WebSocketUtil.close(); + } + render() { + return ( + <Provider store={store}> + <div> + <GlobalModal /> + {this.props.children} + <Loader /> + </div> + </Provider> + ); + } } export default Application; - diff --git a/openecomp-ui/src/sdc-app/ModulesOptions.jsx b/openecomp-ui/src/sdc-app/ModulesOptions.jsx index 28fab80da9..63296b57c9 100644 --- a/openecomp-ui/src/sdc-app/ModulesOptions.jsx +++ b/openecomp-ui/src/sdc-app/ModulesOptions.jsx @@ -15,7 +15,7 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import Input from 'nfvo-components/input/validation/InputWrapper.jsx'; import LicenseModelActionHelper from './onboarding/licenseModel/LicenseModelActionHelper.js'; @@ -27,140 +27,198 @@ import LicenseKeyGroupsListEditor from './onboarding/licenseModel/licenseKeyGrou import LicenseKeyGroupsActionHelper from './onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; import EntitlementPoolsListEditor from './onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js'; import EntitlementPoolsActionHelper from './onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js'; -import SoftwareProductLandingPage from './onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js'; -import SoftwareProductDetails from './onboarding/softwareProduct/details/SoftwareProductDetails.js'; +import SoftwareProductLandingPage from './onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js'; +import SoftwareProductDetails from './onboarding/softwareProduct/details/SoftwareProductDetails.js'; import Onboard from './onboarding/onboard/Onboard.js'; import SoftwareProductActionHelper from './onboarding/softwareProduct/SoftwareProductActionHelper.js'; import FlowsListEditor from './flows/FlowsListEditor.js'; import FlowsActions from './flows/FlowsActions.js'; - -const mapStateToProps = ({licenseModelList}) => { - return {licenseModelList}; +const mapStateToProps = ({ licenseModelList }) => { + return { licenseModelList }; }; - const mapActionsToProps = dispatch => { - return { - onBootstrapped: () => LicenseModelActionHelper.fetchLicenseModels(dispatch), - onLicenseAgreementListEditor: licenseModelId => LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId}), - onFeatureGroupsListEditor: licenseModelId => FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId}), - onLicenseKeyGroupsListEditor: licenseModelId =>LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId}), - onEntitlementPoolsListEditor: licenseModelId => EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId}), - onOnboardingCatalog: () => SoftwareProductActionHelper.fetchSoftwareProductList(dispatch), - onSoftwareProductDetails: () => SoftwareProductActionHelper.fetchSoftwareProductCategories(dispatch), - onFlowsListEditor: () => FlowsActions.fetchFlows(dispatch) - }; + return { + onBootstrapped: () => + LicenseModelActionHelper.fetchLicenseModels(dispatch), + onLicenseAgreementListEditor: licenseModelId => + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, { + licenseModelId + }), + onFeatureGroupsListEditor: licenseModelId => + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId + }), + onLicenseKeyGroupsListEditor: licenseModelId => + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, { + licenseModelId + }), + onEntitlementPoolsListEditor: licenseModelId => + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, { + licenseModelId + }), + onOnboardingCatalog: () => + SoftwareProductActionHelper.fetchSoftwareProductList(dispatch), + onSoftwareProductDetails: () => + SoftwareProductActionHelper.fetchSoftwareProductCategories( + dispatch + ), + onFlowsListEditor: () => FlowsActions.fetchFlows(dispatch) + }; }; class ModuleOptions extends React.Component { + static propTypes = { + onBootstrapped: PropTypes.func.isRequired, + onLicenseAgreementListEditor: PropTypes.func.isRequired, + onFeatureGroupsListEditor: PropTypes.func.isRequired, + onLicenseKeyGroupsListEditor: PropTypes.func.isRequired, + onEntitlementPoolsListEditor: PropTypes.func.isRequired, + onOnboardingCatalog: PropTypes.func.isRequired, + onSoftwareProductDetails: PropTypes.func.isRequired + }; - static propTypes = { - onBootstrapped: PropTypes.func.isRequired, - onLicenseAgreementListEditor: PropTypes.func.isRequired, - onFeatureGroupsListEditor: PropTypes.func.isRequired, - onLicenseKeyGroupsListEditor: PropTypes.func.isRequired, - onEntitlementPoolsListEditor: PropTypes.func.isRequired, - onOnboardingCatalog: PropTypes.func.isRequired, - onSoftwareProductDetails: PropTypes.func.isRequired, - }; - - state = { - currentModule: localStorage.getItem('default-module'), - licenseModelId: localStorage.getItem('default-license-model-id') - }; + state = { + currentModule: localStorage.getItem('default-module'), + licenseModelId: localStorage.getItem('default-license-model-id') + }; - componentDidMount() { - this.props.onBootstrapped(); - } + componentDidMount() { + this.props.onBootstrapped(); + } - render() { - let {currentModule, licenseModelId} = this.state; - let {licenseModelList} = this.props; - return ( - <div style={{marginTop:20}}> - <Input - name='licenseModel' - value={licenseModelId} - ref='licenseModelId' - type='select' - onChange={this.handleLicenseModelIdChange} - className='inner-pagination select-input'> - <option value='' key={null}>Select License Model</option> - { - licenseModelList.map(({id, vendorName}) => <option value={id} key={id}>{`${vendorName} License Model`}</option>) - } - </Input> - <Input - name='currentView' - value={currentModule} - ref='selectedModule' - type='select' - onChange={this.handleModuleSelection} - className='inner-pagination select-input'> - <option value=''>Select Module</option> - <option value='EntitlementPoolsListEditor'>Entitlement Pools</option> - <option value='LicenseAgreementListEditor'>License Agreements</option> - <option value='FutureGroupListEditor'>Feature Groups</option> - <option value='LicenseKeyGroupsListEditor'>License Key Groups</option> - <option value='SoftwareProductLanding'>Software Product Landing</option> - <option value='SoftwareProductDetails'>Software Product Details</option> - <option value='OnboardingCatalog'>Onboarding Catalog</option> - <option value='Flows'>Flows</option> - </Input> - <div className='sub-module-view' style={{paddingTop: 10, margin: 4, borderTop: '1px solid silver'}}> - {this.renderModule(currentModule)} - </div> - </div> - ); - } + render() { + let { currentModule, licenseModelId } = this.state; + let { licenseModelList } = this.props; + return ( + <div style={{ marginTop: 20 }}> + <Input + name="licenseModel" + value={licenseModelId} + ref="licenseModelId" + type="select" + onChange={this.handleLicenseModelIdChange} + className="inner-pagination select-input"> + <option value="" key={null}> + Select License Model + </option> + {licenseModelList.map(({ id, vendorName }) => ( + <option + value={id} + key={id}>{`${vendorName} License Model`}</option> + ))} + </Input> + <Input + name="currentView" + value={currentModule} + ref="selectedModule" + type="select" + onChange={this.handleModuleSelection} + className="inner-pagination select-input"> + <option value="">Select Module</option> + <option value="EntitlementPoolsListEditor"> + Entitlement Pools + </option> + <option value="LicenseAgreementListEditor"> + License Agreements + </option> + <option value="FutureGroupListEditor"> + Feature Groups + </option> + <option value="LicenseKeyGroupsListEditor"> + License Key Groups + </option> + <option value="SoftwareProductLanding"> + Software Product Landing + </option> + <option value="SoftwareProductDetails"> + Software Product Details + </option> + <option value="OnboardingCatalog"> + Onboarding Catalog + </option> + <option value="Flows">Flows</option> + </Input> + <div + className="sub-module-view" + style={{ + paddingTop: 10, + margin: 4, + borderTop: '1px solid silver' + }}> + {this.renderModule(currentModule)} + </div> + </div> + ); + } - renderModule(currentModule) { - const {licenseModelId} = this.state; - if (!licenseModelId) { - return; - } + renderModule(currentModule) { + const { licenseModelId } = this.state; + if (!licenseModelId) { + return; + } - switch (currentModule) { - case 'LicenseAgreementListEditor': - this.props.onLicenseAgreementListEditor(licenseModelId); - return <LicenseAgreementListEditor licenseModelId={licenseModelId}/>; - case 'FutureGroupListEditor': - this.props.onFeatureGroupsListEditor(licenseModelId); - return <FeatureGroupListEditor licenseModelId={licenseModelId}/>; - case 'EntitlementPoolsListEditor': - this.props.onEntitlementPoolsListEditor(licenseModelId); - return <EntitlementPoolsListEditor licenseModelId={licenseModelId}/>; - case 'LicenseKeyGroupsListEditor': - this.props.onLicenseKeyGroupsListEditor(licenseModelId); - return <LicenseKeyGroupsListEditor licenseModelId={licenseModelId}/>; - case 'SoftwareProductLanding': - return <SoftwareProductLandingPage licenseModelId={licenseModelId}/>; - case 'SoftwareProductDetails': - this.props.onSoftwareProductDetails(licenseModelId); - return <SoftwareProductDetails licenseModelId={licenseModelId}/>; - case 'OnboardingCatalog': - this.props.onOnboardingCatalog(); - return <Onboard/>; - case 'Flows': - this.props.onFlowsListEditor(); - return <FlowsListEditor/>; - default: - return; - } - } + switch (currentModule) { + case 'LicenseAgreementListEditor': + this.props.onLicenseAgreementListEditor(licenseModelId); + return ( + <LicenseAgreementListEditor + licenseModelId={licenseModelId} + /> + ); + case 'FutureGroupListEditor': + this.props.onFeatureGroupsListEditor(licenseModelId); + return ( + <FeatureGroupListEditor licenseModelId={licenseModelId} /> + ); + case 'EntitlementPoolsListEditor': + this.props.onEntitlementPoolsListEditor(licenseModelId); + return ( + <EntitlementPoolsListEditor + licenseModelId={licenseModelId} + /> + ); + case 'LicenseKeyGroupsListEditor': + this.props.onLicenseKeyGroupsListEditor(licenseModelId); + return ( + <LicenseKeyGroupsListEditor + licenseModelId={licenseModelId} + /> + ); + case 'SoftwareProductLanding': + return ( + <SoftwareProductLandingPage + licenseModelId={licenseModelId} + /> + ); + case 'SoftwareProductDetails': + this.props.onSoftwareProductDetails(licenseModelId); + return ( + <SoftwareProductDetails licenseModelId={licenseModelId} /> + ); + case 'OnboardingCatalog': + this.props.onOnboardingCatalog(); + return <Onboard />; + case 'Flows': + this.props.onFlowsListEditor(); + return <FlowsListEditor />; + default: + return; + } + } - handleModuleSelection = () => { - let selectedModule = this.refs.selectedModule.getValue(); - localStorage.setItem('default-module', selectedModule); - this.setState({currentModule: selectedModule}); - } + handleModuleSelection = () => { + let selectedModule = this.refs.selectedModule.getValue(); + localStorage.setItem('default-module', selectedModule); + this.setState({ currentModule: selectedModule }); + }; - handleLicenseModelIdChange = () => { - let licenseModelId = this.refs.licenseModelId.getValue(); - localStorage.setItem('default-license-model-id', licenseModelId); - this.setState({licenseModelId}); - } + handleLicenseModelIdChange = () => { + let licenseModelId = this.refs.licenseModelId.getValue(); + localStorage.setItem('default-license-model-id', licenseModelId); + this.setState({ licenseModelId }); + }; } export default connect(mapStateToProps, mapActionsToProps)(ModuleOptions); diff --git a/openecomp-ui/src/sdc-app/Reducers.js b/openecomp-ui/src/sdc-app/Reducers.js index a0a8ebafa1..9f424235cb 100644 --- a/openecomp-ui/src/sdc-app/Reducers.js +++ b/openecomp-ui/src/sdc-app/Reducers.js @@ -14,7 +14,7 @@ * limitations under the License. */ -import {combineReducers} from 'redux'; +import { combineReducers } from 'redux'; import onBoardingReducersMap from './onboarding/OnboardingReducersMap.js'; import flowsReducersMap from './flows/FlowsReducersMap.js'; import loaderReducer from 'nfvo-components/loader/LoaderReducer.js'; @@ -22,12 +22,12 @@ import globalModalReducer from 'nfvo-components/modal/GlobalModalReducer.js'; import notificationsReducer from 'sdc-app/onboarding/userNotifications/NotificationsReducer.js'; export default combineReducers({ - // on-boarding reducers - ...onBoardingReducersMap, + // on-boarding reducers + ...onBoardingReducersMap, - // flows reducers - ...flowsReducersMap, - modal: globalModalReducer, - loader: loaderReducer, - notifications: notificationsReducer + // flows reducers + ...flowsReducersMap, + modal: globalModalReducer, + loader: loaderReducer, + notifications: notificationsReducer }); diff --git a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js index a1ad437f5b..2978cacda4 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLog.js @@ -13,16 +13,28 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ActivityLogView from './ActivityLogView.jsx'; -export const mapStateToProps = ({users: {usersList}, licenseModel: {activityLog}}) => { - - let activities = activityLog; - return { - activities: activities.map(activity => ({...activity, user: {id: activity.user, name: usersList.find(userObject => userObject.userId === activity.user).fullName}})), - usersList - }; +export const mapStateToProps = ({ + users: { usersList }, + licenseModel: { activityLog } +}) => { + let activities = activityLog; + return { + activities: activities.map(activity => ({ + ...activity, + user: { + id: activity.user, + name: usersList.find( + userObject => userObject.userId === activity.user + ).fullName + } + })), + usersList + }; }; -export default connect(mapStateToProps, undefined, null, {withRef: true})(ActivityLogView); +export default connect(mapStateToProps, undefined, null, { withRef: true })( + ActivityLogView +); diff --git a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js index 729d8fb5f3..6856b08c8b 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogActionHelper.js @@ -17,8 +17,13 @@ import ActivityLogConstants from './ActivityLogConstants.js'; import ItemHelper from 'sdc-app/common/helpers/ItemsHelper.js'; export default { - - fetchActivityLog(dispatch, {itemId, versionId}){ - return ItemHelper.fetchActivityLog({itemId, versionId}).then(response => dispatch({type: ActivityLogConstants.ACTIVITY_LOG_UPDATED, response})); - } + fetchActivityLog(dispatch, { itemId, versionId }) { + return ItemHelper.fetchActivityLog({ itemId, versionId }).then( + response => + dispatch({ + type: ActivityLogConstants.ACTIVITY_LOG_UPDATED, + response + }) + ); + } }; diff --git a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js index 69faf7cbb6..2da3c7799e 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogConstants.js @@ -16,8 +16,5 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export default keyMirror({ - - ACTIVITY_LOG_UPDATED: null - + ACTIVITY_LOG_UPDATED: null }); - diff --git a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js index fc3dfa1515..418a9b9e3d 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogReducer.js @@ -16,10 +16,10 @@ import ActivityLogConstants from './ActivityLogConstants.js'; export default (state = [], action) => { - switch (action.type) { - case ActivityLogConstants.ACTIVITY_LOG_UPDATED: - return [...action.response.results]; - } + switch (action.type) { + case ActivityLogConstants.ACTIVITY_LOG_UPDATED: + return [...action.response.results]; + } - return state; + return state; }; diff --git a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx index 5b8c29b719..d65e667163 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx +++ b/openecomp-ui/src/sdc-app/common/activity-log/ActivityLogView.jsx @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +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'; @@ -21,108 +21,177 @@ 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}) { - //TODO check icon sdc-ui - if (isHeader) { - return ( - <span className='date-header' onClick={onSort}> - <span>{data}</span> - <span className={`header-sort-arrow ${isDes ? 'up' : 'down'}`}></span> - </span> - ); - } - return ( - <span className='date-cell'> - <span>{i18n.dateNormal(data, { - year: 'numeric', month: 'numeric', day: 'numeric' - })}</span> - <span>{i18n.dateNormal(data, { - hour: 'numeric', minute: 'numeric', - hour12: true - })}</span> - </span> - ); +function ActivityLogSortableCellHeader({ isHeader, data, isDes, onSort }) { + //TODO check icon sdc-ui + if (isHeader) { + return ( + <span className="date-header" onClick={onSort}> + <span>{data}</span> + <span + className={`header-sort-arrow ${isDes ? 'up' : 'down'}`} + /> + </span> + ); + } + return ( + <span className="date-cell"> + <span> + {i18n.dateNormal(data, { + year: 'numeric', + month: 'numeric', + day: 'numeric' + })} + </span> + <span> + {i18n.dateNormal(data, { + hour: 'numeric', + minute: 'numeric', + hour12: true + })} + </span> + </span> + ); } -function ActivityLogStatus({status, isHeader}) { - if (isHeader) { - return <span>{status}</span>; - } - let {message, success} = status; - return ( - <span> - <span className={`status-icon ${success}`}>{`${success ? i18n('Success') : i18n('Failure')}`}</span> - {success && <SVGIcon name='checkCircle' color='positive'/>} - {!success && <OverlayTrigger placement='bottom' overlay={<Tooltip className='activity-log-message-tooltip' id={'activity-log-message-tooltip'}> - <div className='message-block'>{message}</div> - </Tooltip>}> - <span className='message-further-info-icon'>{'?'}</span> - </OverlayTrigger>} - </span> - ); +function ActivityLogStatus({ status, isHeader }) { + if (isHeader) { + return <span>{status}</span>; + } + let { message, success } = status; + return ( + <span> + <span className={`status-icon ${success}`}>{`${ + success ? i18n('Success') : i18n('Failure') + }`}</span> + {success && <SVGIcon name="checkCircle" color="positive" />} + {!success && ( + <OverlayTrigger + placement="bottom" + overlay={ + <Tooltip + className="activity-log-message-tooltip" + id={'activity-log-message-tooltip'}> + <div className="message-block">{message}</div> + </Tooltip> + }> + <span className="message-further-info-icon">{'?'}</span> + </OverlayTrigger> + )} + </span> + ); } -export function ActivityListItem({activity, isHeader, isDes, onSort}) { - let {type, timestamp, comment, user, status} = activity; - return ( - <li className={`activity-list-item ${isHeader ? 'header' : ''}`} data-test-id='activity-list-item'> - <div className='table-cell activity-date' data-test-id='activity-date'><ActivityLogSortableCellHeader isHeader={isHeader} data={timestamp} isDes={isDes} onSort={onSort}/></div> - <div className='table-cell activity-action' data-test-id='activity-action'>{i18n(type)}</div> - <div className='table-cell activity-comment' title={isHeader ? '' : comment} data-test-id='activity-comment'><span>{i18n(comment)}</span></div> - <div className='table-cell activity-username' data-test-id='activity-username'>{isHeader ? i18n(activity.user) : `${i18n(user.name)} (${user.id})`}</div> - <div className='table-cell activity-status' data-test-id='activity-status'><ActivityLogStatus isHeader={isHeader} status={status}/></div> - </li> - ); +export function ActivityListItem({ activity, isHeader, isDes, onSort }) { + let { type, timestamp, comment, user, status } = activity; + return ( + <li + className={`activity-list-item ${isHeader ? 'header' : ''}`} + data-test-id="activity-list-item"> + <div + className="table-cell activity-date" + data-test-id="activity-date"> + <ActivityLogSortableCellHeader + isHeader={isHeader} + data={timestamp} + isDes={isDes} + onSort={onSort} + /> + </div> + <div + className="table-cell activity-action" + data-test-id="activity-action"> + {i18n(type)} + </div> + <div + className="table-cell activity-comment" + title={isHeader ? '' : comment} + data-test-id="activity-comment"> + <span>{i18n(comment)}</span> + </div> + <div + className="table-cell activity-username" + data-test-id="activity-username"> + {isHeader + ? i18n(activity.user) + : `${i18n(user.name)} (${user.id})`} + </div> + <div + className="table-cell activity-status" + data-test-id="activity-status"> + <ActivityLogStatus isHeader={isHeader} status={status} /> + </div> + </li> + ); } class ActivityLogView extends Component { + state = { + localFilter: '', + sortDescending: true + }; - state = { - localFilter: '', - sortDescending: true - }; + render() { + return ( + <div className="activity-log-view"> + <LogDetails display={this.state.localFilter} /> + <ListEditorView + title={i18n('Activity Log')} + filterValue={this.state.localFilter} + onFilter={filter => this.setState({ localFilter: filter })}> + <ActivityListItem + activity={{ + timestamp: 'Date', + type: 'Action', + comment: 'Comment', + user: 'Username', + status: 'Status' + }} + isDes={this.state.sortDescending} + onSort={() => + this.setState({ + sortDescending: !this.state.sortDescending + }) + } + isHeader + /> + {this.sortActivities( + this.filterActivities(), + this.state.sortDescending + ).map(activity => ( + <ActivityListItem + key={activity.id} + activity={activity} + /> + ))} + </ListEditorView> + </div> + ); + } - render() { - return ( - <div className='activity-log-view'> - <LogDetails display={this.state.localFilter}/> - <ListEditorView - title={i18n('Activity Log')} - filterValue={this.state.localFilter} - onFilter={filter => this.setState({localFilter: filter})}> - <ActivityListItem - activity={{timestamp: 'Date', type: 'Action', comment: 'Comment', user: 'Username', status: 'Status'}} - isDes={this.state.sortDescending} - onSort={() => this.setState({sortDescending: !this.state.sortDescending})} - isHeader/> - {this.sortActivities(this.filterActivities(), this.state.sortDescending).map(activity => <ActivityListItem key={activity.id} activity={activity}/>)} - </ListEditorView> - </div> - ); - } - - filterActivities() { - let {activities} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return activities.filter(({user = {id: '', name: ''}, comment = '', type = ''}) => - escape(user.id).match(filter) || escape(user.name).match(filter) || escape(comment).match(filter) || escape(type).match(filter)); - } - else { - return activities; - } - } - - sortActivities(activities) { - if (this.state.sortDescending) { - return activities.sort((a, b) => a.timestamp - b.timestamp); - } - else { - return activities.reverse(); - } - } + filterActivities() { + let { activities } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return activities.filter( + ({ user = { id: '', name: '' }, comment = '', type = '' }) => + escape(user.id).match(filter) || + escape(user.name).match(filter) || + escape(comment).match(filter) || + escape(type).match(filter) + ); + } else { + return activities; + } + } + sortActivities(activities) { + if (this.state.sortDescending) { + return activities.sort((a, b) => a.timestamp - b.timestamp); + } else { + return activities.reverse(); + } + } } export default ActivityLogView; diff --git a/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx b/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx index bd40e113e9..0dbf518768 100644 --- a/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx +++ b/openecomp-ui/src/sdc-app/common/activity-log/LogixUtil.jsx @@ -1,28 +1,36 @@ -import React, {Component} from 'react'; -// eslint-disable-next-line max-len -const style = 'LnJhYmJpdHt3aWR0aDo1ZW07aGVpZ2h0OjNlbTtiYWNrZ3JvdW5kOiM5OTk7Ym9yZGVyLXJhZGl1czo3MCUgOTAlIDYwJSA1MCU7cG9zaXRpb246cmVsYXRpdmU7LW1vei10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy1tcy10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoLTJlbSwwKTt0cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApO2FuaW1hdGlvbjpob3AgMXMgaW5maW5pdGUgbGluZWFyO3otaW5kZXg6MX0ucmFiYml0OmFmdGVyLC5yYWJiaXQ6YmVmb3Jle2NvbnRlbnQ6IiI7cG9zaXRpb246YWJzb2x1dGU7YmFja2dyb3VuZDojZjFmMWYxfS5uby1mbGV4Ym94IC5yYWJiaXR7bWFyZ2luOjEwZW0gYXV0byAwfS5yYWJiaXQ6YmVmb3Jle3dpZHRoOjFlbTtoZWlnaHQ6MWVtO2JvcmRlci1yYWRpdXM6MTAwJTt0b3A6LjVlbTtsZWZ0Oi0uM2VtO2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDFlbSAwICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uNGVtICNmMWYxZjE7YW5pbWF0aW9uOmtpY2sgMXMgaW5maW5pdGUgbGluZWFyfS5yYWJiaXQ6YWZ0ZXJ7d2lkdGg6Ljc1ZW07aGVpZ2h0OjJlbTtib3JkZXItcmFkaXVzOjUwJSAxMDAlIDAgMDstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTtyaWdodDoxZW07dG9wOi0xZW07Ym9yZGVyLXRvcDoxcHggc29saWQgI2Y3ZjVmNDtib3JkZXItbGVmdDoxcHggc29saWQgI2Y3ZjVmNDtib3gtc2hhZG93Oi0uNWVtIDAgMCAtLjFlbSAjZjFmMWYxfUBrZXlmcmFtZXMgaG9wezIwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pOy1tcy10cmFuc2Zvcm06cm90YXRlKC0xMGRlZykgdHJhbnNsYXRlKDFlbSwtMmVtKTstd2Via2l0LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pO3RyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pfTQwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LW1zLXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LXdlYmtpdC10cmFuc2Zvcm06cm90YXRlKDEwZGVnKSB0cmFuc2xhdGUoM2VtLC00ZW0pO3RyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSl9NjAlLDc1JXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApO3RyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKX19QGtleWZyYW1lcyBraWNrezIwJSw1MCV7Ym94LXNoYWRvdzo0ZW0gLjRlbSAwIC0uMzVlbSAjM2YzMzM0LC41ZW0gMS41ZW0gMCAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjllbSAwIC0uNGVtICNmMWYxZjF9NDAle2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDJlbSAwICNmMWYxZjEsNGVtIDEuNzVlbSAwIC0uM2VtICNmMWYxZjEsNC4yZW0gMS43NWVtIDAgLS4yZW0gI2YxZjFmMSw0LjRlbSAxLjllbSAwIC0uMmVtICNmMWYxZjF9fQ=='; +import React, { Component } from 'react'; /* eslint-disable max-len */ +const style = + 'LnJhYmJpdHt3aWR0aDo1ZW07aGVpZ2h0OjNlbTtiYWNrZ3JvdW5kOiM5OTk7Ym9yZGVyLXJhZGl1czo3MCUgOTAlIDYwJSA1MCU7cG9zaXRpb246cmVsYXRpdmU7LW1vei10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy1tcy10cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoLTJlbSwwKTt0cmFuc2Zvcm06cm90YXRlKDApIHRyYW5zbGF0ZSgtMmVtLDApO2FuaW1hdGlvbjpob3AgMXMgaW5maW5pdGUgbGluZWFyO3otaW5kZXg6MX0ucmFiYml0OmFmdGVyLC5yYWJiaXQ6YmVmb3Jle2NvbnRlbnQ6IiI7cG9zaXRpb246YWJzb2x1dGU7YmFja2dyb3VuZDojZjFmMWYxfS5uby1mbGV4Ym94IC5yYWJiaXR7bWFyZ2luOjEwZW0gYXV0byAwfS5yYWJiaXQ6YmVmb3Jle3dpZHRoOjFlbTtoZWlnaHQ6MWVtO2JvcmRlci1yYWRpdXM6MTAwJTt0b3A6LjVlbTtsZWZ0Oi0uM2VtO2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDFlbSAwICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uM2VtICNmMWYxZjEsNGVtIDFlbSAwIC0uNGVtICNmMWYxZjE7YW5pbWF0aW9uOmtpY2sgMXMgaW5maW5pdGUgbGluZWFyfS5yYWJiaXQ6YWZ0ZXJ7d2lkdGg6Ljc1ZW07aGVpZ2h0OjJlbTtib3JkZXItcmFkaXVzOjUwJSAxMDAlIDAgMDstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgtMzBkZWcpO3RyYW5zZm9ybTpyb3RhdGUoLTMwZGVnKTtyaWdodDoxZW07dG9wOi0xZW07Ym9yZGVyLXRvcDoxcHggc29saWQgI2Y3ZjVmNDtib3JkZXItbGVmdDoxcHggc29saWQgI2Y3ZjVmNDtib3gtc2hhZG93Oi0uNWVtIDAgMCAtLjFlbSAjZjFmMWYxfUBrZXlmcmFtZXMgaG9wezIwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pOy1tcy10cmFuc2Zvcm06cm90YXRlKC0xMGRlZykgdHJhbnNsYXRlKDFlbSwtMmVtKTstd2Via2l0LXRyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pO3RyYW5zZm9ybTpyb3RhdGUoLTEwZGVnKSB0cmFuc2xhdGUoMWVtLC0yZW0pfTQwJXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LW1zLXRyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSk7LXdlYmtpdC10cmFuc2Zvcm06cm90YXRlKDEwZGVnKSB0cmFuc2xhdGUoM2VtLC00ZW0pO3RyYW5zZm9ybTpyb3RhdGUoMTBkZWcpIHRyYW5zbGF0ZSgzZW0sLTRlbSl9NjAlLDc1JXstbW96LXRyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKTstbXMtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApOy13ZWJraXQtdHJhbnNmb3JtOnJvdGF0ZSgwKSB0cmFuc2xhdGUoNGVtLDApO3RyYW5zZm9ybTpyb3RhdGUoMCkgdHJhbnNsYXRlKDRlbSwwKX19QGtleWZyYW1lcyBraWNrezIwJSw1MCV7Ym94LXNoYWRvdzo0ZW0gLjRlbSAwIC0uMzVlbSAjM2YzMzM0LC41ZW0gMS41ZW0gMCAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjc1ZW0gMCAtLjNlbSAjZjFmMWYxLDRlbSAxLjllbSAwIC0uNGVtICNmMWYxZjF9NDAle2JveC1zaGFkb3c6NGVtIC40ZW0gMCAtLjM1ZW0gIzNmMzMzNCwuNWVtIDJlbSAwICNmMWYxZjEsNGVtIDEuNzVlbSAwIC0uM2VtICNmMWYxZjEsNC4yZW0gMS43NWVtIDAgLS4yZW0gI2YxZjFmMSw0LjRlbSAxLjllbSAwIC0uMmVtICNmMWYxZjF9fQ=='; +/* eslint-enable max-len */ class LogixUtil extends Component { + state = { + whatToDisplay: false + }; - 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> - ); - } + 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> + ); + } } export default LogixUtil; diff --git a/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js index 05affe981f..99ecae9887 100644 --- a/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js +++ b/openecomp-ui/src/sdc-app/common/helpers/ItemsHelper.js @@ -15,92 +15,110 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {permissionTypes} from 'sdc-app/onboarding/permissions/PermissionsConstants.js'; -import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; -import {actionTypes as onboardingActionTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { permissionTypes } from 'sdc-app/onboarding/permissions/PermissionsConstants.js'; +import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import { actionTypes as onboardingActionTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import restToggle from 'sdc-app/features/restToggle.js'; -import {featureToggleNames} from 'sdc-app/features/FeaturesConstants.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; export const archiveActions = { - ARCHIVE: 'ARCHIVE', - RESTORE: 'RESTORE' + ARCHIVE: 'ARCHIVE', + RESTORE: 'RESTORE' }; export const itemStatus = { - ARCHIVED: 'ARCHIVED', - DRAFT: 'Draft', - CERTIFIED: 'Certified' + ARCHIVED: 'ARCHIVED', + DRAFT: 'Draft', + CERTIFIED: 'Certified' }; - function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/items`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/items`; } const ItemsHelper = { - performVCAction({itemId, version, action, comment}) { - const {id: versionId} = version; - const data = { - action, - ...action === VersionControllerActionsEnum.COMMIT && {commitRequest: {message: comment}} - }; - return RestAPIUtil.put(`${baseUrl()}/${itemId}/versions/${versionId}/actions`, data); - }, + performVCAction({ itemId, version, action, comment }) { + const { id: versionId } = version; + const data = { + action, + ...(action === VersionControllerActionsEnum.COMMIT && { + commitRequest: { message: comment } + }) + }; + return RestAPIUtil.put( + `${baseUrl()}/${itemId}/versions/${versionId}/actions`, + data + ); + }, - fetchVersions({itemId}) { - return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/versions`); - }, + fetchVersions({ itemId }) { + return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/versions`); + }, - fetchVersion({itemId, versionId}) { - return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/versions/${versionId}`); - }, + fetchVersion({ itemId, versionId }) { + return RestAPIUtil.fetch( + `${baseUrl()}/${itemId}/versions/${versionId}` + ); + }, - fetchActivityLog({itemId, versionId}) { - return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/versions/${versionId}/activity-logs`); - }, + fetchActivityLog({ itemId, versionId }) { + return RestAPIUtil.fetch( + `${baseUrl()}/${itemId}/versions/${versionId}/activity-logs` + ); + }, - fetchUsers({itemId}) { - return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/permissions`); - }, + fetchUsers({ itemId }) { + return RestAPIUtil.fetch(`${baseUrl()}/${itemId}/permissions`); + }, - updateContributors({itemId, removedUsersIds, addedUsersIds}) { - return RestAPIUtil.put(`${baseUrl()}/${itemId}/permissions/${permissionTypes.CONTRIBUTOR}`, {removedUsersIds, addedUsersIds}); - }, + updateContributors({ itemId, removedUsersIds, addedUsersIds }) { + return RestAPIUtil.put( + `${baseUrl()}/${itemId}/permissions/${permissionTypes.CONTRIBUTOR}`, + { removedUsersIds, addedUsersIds } + ); + }, - changeOwner({itemId, ownerId}) { - return RestAPIUtil.put(`${baseUrl()}/${itemId}/permissions/${permissionTypes.OWNER}`, {removedUsersIds: [], addedUsersIds: [ownerId]}); - }, + changeOwner({ itemId, ownerId }) { + return RestAPIUtil.put( + `${baseUrl()}/${itemId}/permissions/${permissionTypes.OWNER}`, + { removedUsersIds: [], addedUsersIds: [ownerId] } + ); + }, - async checkItemStatus(dispatch, {itemId, versionId}) { - const response = await ItemsHelper.fetchVersion({itemId, versionId}); - let state = response && response.state || {}; - const {baseId, description, id, name, status} = response; - const item = await ItemsHelper.fetchItem(itemId); - dispatch({ - type: onboardingActionTypes.UPDATE_ITEM_STATUS, - itemState: state, - itemStatus: response.status, - archivedStatus: item.status, - updatedVersion: {baseId, description, id, name, status} - }); + async checkItemStatus(dispatch, { itemId, versionId }) { + const response = await ItemsHelper.fetchVersion({ itemId, versionId }); + let state = (response && response.state) || {}; + const { baseId, description, id, name, status } = response; + const item = await ItemsHelper.fetchItem(itemId); + dispatch({ + type: onboardingActionTypes.UPDATE_ITEM_STATUS, + itemState: state, + itemStatus: response.status, + archivedStatus: item.status, + updatedVersion: { baseId, description, id, name, status } + }); - return Promise.resolve({...response, archivedStatus: item.status}); - }, + return Promise.resolve({ ...response, archivedStatus: item.status }); + }, - fetchItem(itemId) { - return restToggle({restFunction: () => RestAPIUtil.fetch(`${baseUrl()}/${itemId}`), featureName: featureToggleNames.ARCHIVE_ITEM, mockResult: {}}); - }, + fetchItem(itemId) { + return restToggle({ + restFunction: () => RestAPIUtil.fetch(`${baseUrl()}/${itemId}`), + featureName: featureToggleNames.ARCHIVE_ITEM, + mockResult: {} + }); + }, - archiveItem(itemId) { - return RestAPIUtil.put(`${baseUrl()}/${itemId}/actions`, { - action: archiveActions.ARCHIVE - }); - }, - restoreItem(itemId) { - return RestAPIUtil.put(`${baseUrl()}/${itemId}/actions`, { - action: archiveActions.RESTORE - }); - } + archiveItem(itemId) { + return RestAPIUtil.put(`${baseUrl()}/${itemId}/actions`, { + action: archiveActions.ARCHIVE + }); + }, + restoreItem(itemId) { + return RestAPIUtil.put(`${baseUrl()}/${itemId}/actions`, { + action: archiveActions.RESTORE + }); + } }; export default ItemsHelper; diff --git a/openecomp-ui/src/sdc-app/common/helpers/ScreensHelper.js b/openecomp-ui/src/sdc-app/common/helpers/ScreensHelper.js index 7c05f8456b..6f69cd0e51 100644 --- a/openecomp-ui/src/sdc-app/common/helpers/ScreensHelper.js +++ b/openecomp-ui/src/sdc-app/common/helpers/ScreensHelper.js @@ -1,225 +1,356 @@ -import {itemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; -import {actionTypes as SoftwareProductActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { actionTypes as SoftwareProductActionTypes } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; const ScreensHelper = { - async loadScreen(dispatch, {screen, screenType, props}) { - if(screen === enums.SCREEN.ONBOARDING_CATALOG) { - OnboardingActionHelper.navigateToOnboardingCatalog(dispatch); - return; - } - - screenType = !screenType ? this.getScreenType(screen) : screenType; + async loadScreen(dispatch, { screen, screenType, props }) { + if (screen === enums.SCREEN.ONBOARDING_CATALOG) { + OnboardingActionHelper.navigateToOnboardingCatalog(dispatch); + return; + } - if(screenType === screenTypes.LICENSE_MODEL) { - const {licenseModelId, version, licenseModel, usersList} = props; - const item = await ItemsHelper.fetchItem(licenseModelId); - let itemStatusPromise = version && screen ? - ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}) : - Promise.resolve(); - itemStatusPromise.then((updatedVersion) => { - if (updatedVersion && updatedVersion.status !== version.status) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Commit error'), - msg: i18n('Item version was certified by Owner'), - cancelButtonText: i18n('Cancel') - } - }); - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: licenseModelId}); - } - let newVersion = updatedVersion ? updatedVersion : version; - const screenProps = {licenseModelId, version: newVersion, status: item.status}; - switch (screen) { - case enums.SCREEN.LICENSE_MODEL_OVERVIEW: - OnboardingActionHelper.navigateToLicenseModelOverview(dispatch, screenProps); - break; - case enums.SCREEN.LICENSE_AGREEMENTS: - OnboardingActionHelper.navigateToLicenseAgreements(dispatch, screenProps); - break; - case enums.SCREEN.FEATURE_GROUPS: - OnboardingActionHelper.navigateToFeatureGroups(dispatch, screenProps); - break; - case enums.SCREEN.ENTITLEMENT_POOLS: - OnboardingActionHelper.navigateToEntitlementPools(dispatch, screenProps); - break; - case enums.SCREEN.LICENSE_KEY_GROUPS: - OnboardingActionHelper.navigateToLicenseKeyGroups(dispatch, screenProps); - break; - case enums.SCREEN.ACTIVITY_LOG: - OnboardingActionHelper.navigateToLicenseModelActivityLog(dispatch, screenProps); - break; - case enums.SCREEN.VERSIONS_PAGE: - default: - OnboardingActionHelper.navigateToVersionsPage(dispatch, { - itemId: licenseModelId, - itemType: itemTypes.LICENSE_MODEL, - itemName: licenseModel.name, - users: usersList - }); - break; - } - }); - } + screenType = !screenType ? this.getScreenType(screen) : screenType; - else if(screenType === screenTypes.SOFTWARE_PRODUCT) { - const {softwareProductId, componentId, version, softwareProduct, usersList} = props; - const item = await ItemsHelper.fetchItem(softwareProductId); - let itemStatusPromise = version && screen ? - ItemsHelper.checkItemStatus(dispatch, {itemId: softwareProductId, versionId: version.id}) : - Promise.resolve(); - itemStatusPromise.then((updatedVersion) => { - if (updatedVersion && updatedVersion.status !== version.status) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Commit error'), - msg: i18n('Item version already Certified'), - cancelButtonText: i18n('Cancel') - } - }); - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.SOFTWARE_PRODUCT, itemId: softwareProductId}); - } + if (screenType === screenTypes.LICENSE_MODEL) { + const { licenseModelId, version, licenseModel, usersList } = props; + const item = await ItemsHelper.fetchItem(licenseModelId); + let itemStatusPromise = + version && screen + ? ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }) + : Promise.resolve(); + itemStatusPromise.then(updatedVersion => { + if ( + updatedVersion && + updatedVersion.status !== version.status + ) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Commit error'), + msg: i18n('Item version was certified by Owner'), + cancelButtonText: i18n('Cancel') + } + }); + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: licenseModelId + }); + } + let newVersion = updatedVersion ? updatedVersion : version; + const screenProps = { + licenseModelId, + version: newVersion, + status: item.status + }; + switch (screen) { + case enums.SCREEN.LICENSE_MODEL_OVERVIEW: + OnboardingActionHelper.navigateToLicenseModelOverview( + dispatch, + screenProps + ); + break; + case enums.SCREEN.LICENSE_AGREEMENTS: + OnboardingActionHelper.navigateToLicenseAgreements( + dispatch, + screenProps + ); + break; + case enums.SCREEN.FEATURE_GROUPS: + OnboardingActionHelper.navigateToFeatureGroups( + dispatch, + screenProps + ); + break; + case enums.SCREEN.ENTITLEMENT_POOLS: + OnboardingActionHelper.navigateToEntitlementPools( + dispatch, + screenProps + ); + break; + case enums.SCREEN.LICENSE_KEY_GROUPS: + OnboardingActionHelper.navigateToLicenseKeyGroups( + dispatch, + screenProps + ); + break; + case enums.SCREEN.ACTIVITY_LOG: + OnboardingActionHelper.navigateToLicenseModelActivityLog( + dispatch, + screenProps + ); + break; + case enums.SCREEN.VERSIONS_PAGE: + default: + OnboardingActionHelper.navigateToVersionsPage( + dispatch, + { + itemId: licenseModelId, + itemType: itemTypes.LICENSE_MODEL, + itemName: licenseModel.name, + users: usersList + } + ); + break; + } + }); + } else if (screenType === screenTypes.SOFTWARE_PRODUCT) { + const { + softwareProductId, + componentId, + version, + softwareProduct, + usersList + } = props; + const item = await ItemsHelper.fetchItem(softwareProductId); + let itemStatusPromise = + version && screen + ? ItemsHelper.checkItemStatus(dispatch, { + itemId: softwareProductId, + versionId: version.id + }) + : Promise.resolve(); + itemStatusPromise.then(updatedVersion => { + if ( + updatedVersion && + updatedVersion.status !== version.status + ) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Commit error'), + msg: i18n('Item version already Certified'), + cancelButtonText: i18n('Cancel') + } + }); + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.SOFTWARE_PRODUCT, + itemId: softwareProductId + }); + } - let newVersion = updatedVersion ? updatedVersion : version; - - const props = { - softwareProductId, - componentId, - version: newVersion, - status: item.status - }; - if (screen === screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL) { - OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, props); - } - - switch (screen) { - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: - OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: - OnboardingActionHelper.navigateToSoftwareProductComponentGeneral(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: - OnboardingActionHelper.navigateToComponentCompute(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: - OnboardingActionHelper.navigateToComponentLoadBalancing(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: - OnboardingActionHelper.navigateToComponentNetwork(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: - OnboardingActionHelper.navigateToComponentStorage(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - OnboardingActionHelper.navigateToSoftwareProductComponentProcesses(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: - OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: - OnboardingActionHelper.navigateToComponentImages(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - OnboardingActionHelper.navigateToSoftwareProductLandingPage(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: - OnboardingActionHelper.navigateToSoftwareProductDetails(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP: - OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION: - OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: - OnboardingActionHelper.navigateToSoftwareProductProcesses(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: - OnboardingActionHelper.navigateToSoftwareProductDeployment(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: - OnboardingActionHelper.navigateToSoftwareProductNetworks(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: - OnboardingActionHelper.navigateToSoftwareProductDependencies(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: - OnboardingActionHelper.navigateToSoftwareProductActivityLog(dispatch, props); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: - OnboardingActionHelper.navigateToSoftwareProductComponents(dispatch, props); - dispatch({ - type: SoftwareProductActionTypes.TOGGLE_NAVIGATION_ITEM, - mapOfExpandedIds: { - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: true - } - }); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE: - default: - OnboardingActionHelper.navigateToVersionsPage(dispatch, { - itemId: softwareProductId, - itemType: itemTypes.SOFTWARE_PRODUCT, - itemName: softwareProduct.name, - users: usersList, - additionalProps: { - licenseModelId: softwareProduct.vendorId, - licensingVersion: softwareProduct.licensingVersion - } - }); - break; - } - }); - } - }, + let newVersion = updatedVersion ? updatedVersion : version; - getScreenType(screen) { - switch (screen) { - case enums.SCREEN.LICENSE_MODEL_OVERVIEW: - case enums.SCREEN.LICENSE_AGREEMENTS: - case enums.SCREEN.FEATURE_GROUPS: - case enums.SCREEN.ENTITLEMENT_POOLS: - case enums.SCREEN.LICENSE_KEY_GROUPS: - case enums.SCREEN.ACTIVITY_LOG: - return screenTypes.LICENSE_MODEL; - case screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL: - 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_NETWORK: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - 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: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: - return screenTypes.SOFTWARE_PRODUCT; - } - }, + const props = { + softwareProductId, + componentId, + version: newVersion, + status: item.status + }; + if ( + screen === + screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL + ) { + OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel( + dispatch, + props + ); + } - loadLandingScreen(dispatch, {previousScreenName, screenType, props: {licenseModelId, softwareProductId, version}}) { - let selectedScreenType = screenType ? screenType : this.getScreenType(previousScreenName); - let screen = selectedScreenType === screenTypes.SOFTWARE_PRODUCT ? - enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE : - enums.SCREEN.LICENSE_MODEL_OVERVIEW; - let props = {licenseModelId, softwareProductId, version}; - return this.loadScreen(dispatch, {screen, screenType: selectedScreenType, props}); - } + switch (screen) { + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: + OnboardingActionHelper.navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: + OnboardingActionHelper.navigateToSoftwareProductComponentGeneral( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: + OnboardingActionHelper.navigateToComponentCompute( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: + OnboardingActionHelper.navigateToComponentLoadBalancing( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: + OnboardingActionHelper.navigateToComponentNetwork( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: + OnboardingActionHelper.navigateToComponentStorage( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + OnboardingActionHelper.navigateToSoftwareProductComponentProcesses( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: + OnboardingActionHelper.navigateToSoftwareProductComponentMonitoring( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: + OnboardingActionHelper.navigateToComponentImages( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: + OnboardingActionHelper.navigateToSoftwareProductLandingPage( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: + OnboardingActionHelper.navigateToSoftwareProductDetails( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP: + OnboardingActionHelper.navigateToSoftwareProductAttachmentsSetupTab( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION: + OnboardingActionHelper.navigateToSoftwareProductAttachmentsValidationTab( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: + OnboardingActionHelper.navigateToSoftwareProductProcesses( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT: + OnboardingActionHelper.navigateToSoftwareProductDeployment( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: + OnboardingActionHelper.navigateToSoftwareProductNetworks( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES: + OnboardingActionHelper.navigateToSoftwareProductDependencies( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG: + OnboardingActionHelper.navigateToSoftwareProductActivityLog( + dispatch, + props + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: + OnboardingActionHelper.navigateToSoftwareProductComponents( + dispatch, + props + ); + dispatch({ + type: + SoftwareProductActionTypes.TOGGLE_NAVIGATION_ITEM, + mapOfExpandedIds: { + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: true + } + }); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE: + default: + OnboardingActionHelper.navigateToVersionsPage( + dispatch, + { + itemId: softwareProductId, + itemType: itemTypes.SOFTWARE_PRODUCT, + itemName: softwareProduct.name, + users: usersList, + additionalProps: { + licenseModelId: softwareProduct.vendorId, + licensingVersion: + softwareProduct.licensingVersion + } + } + ); + break; + } + }); + } + }, + + getScreenType(screen) { + switch (screen) { + case enums.SCREEN.LICENSE_MODEL_OVERVIEW: + case enums.SCREEN.LICENSE_AGREEMENTS: + case enums.SCREEN.FEATURE_GROUPS: + case enums.SCREEN.ENTITLEMENT_POOLS: + case enums.SCREEN.LICENSE_KEY_GROUPS: + case enums.SCREEN.ACTIVITY_LOG: + return screenTypes.LICENSE_MODEL; + case screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL: + 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_NETWORK: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES: + case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: + 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: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: + return screenTypes.SOFTWARE_PRODUCT; + } + }, + + loadLandingScreen( + dispatch, + { + previousScreenName, + screenType, + props: { licenseModelId, softwareProductId, version } + } + ) { + let selectedScreenType = screenType + ? screenType + : this.getScreenType(previousScreenName); + let screen = + selectedScreenType === screenTypes.SOFTWARE_PRODUCT + ? enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE + : enums.SCREEN.LICENSE_MODEL_OVERVIEW; + let props = { licenseModelId, softwareProductId, version }; + return this.loadScreen(dispatch, { + screen, + screenType: selectedScreenType, + props + }); + } }; export default ScreensHelper; diff --git a/openecomp-ui/src/sdc-app/common/helpers/ValidationHelper.js b/openecomp-ui/src/sdc-app/common/helpers/ValidationHelper.js index cfa675278f..aa578c6692 100644 --- a/openecomp-ui/src/sdc-app/common/helpers/ValidationHelper.js +++ b/openecomp-ui/src/sdc-app/common/helpers/ValidationHelper.js @@ -13,80 +13,85 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes as commonActionTypes} from 'sdc-app/common/reducers/PlainDataReducerConstants.js'; -import {actionTypes as qcommonActionTypes} from 'sdc-app/common/reducers/JSONSchemaReducerConstants.js'; +import { actionTypes as commonActionTypes } from 'sdc-app/common/reducers/PlainDataReducerConstants.js'; +import { actionTypes as qcommonActionTypes } from 'sdc-app/common/reducers/JSONSchemaReducerConstants.js'; class ValidationHelper { + static dataChanged( + dispatch, + { deltaData, formName, customValidations = {} } + ) { + dispatch({ + type: commonActionTypes.DATA_CHANGED, + deltaData, + formName, + customValidations + }); + } - static dataChanged(dispatch, {deltaData, formName, customValidations = {}}){ - dispatch({ - type: commonActionTypes.DATA_CHANGED, - deltaData, - formName, - customValidations - }); - } + static validateForm(dispatch, formName) { + dispatch({ + type: commonActionTypes.VALIDATE_FORM, + formName + }); + } - static validateForm(dispatch, formName){ - dispatch({ - type: commonActionTypes.VALIDATE_FORM, - formName - }); - } + static validateData(dispatch, { formName, data }) { + dispatch({ + type: commonActionTypes.VALIDATE_DATA, + formName, + data + }); + } - static validateData(dispatch, {formName, data}) { - dispatch({ - type: commonActionTypes.VALIDATE_DATA, - formName, - data - }); - } + static qValidateData(dispatch, { data, qName, customValidations = {} }) { + dispatch({ + type: qcommonActionTypes.VALIDATE_DATA, + data, + qName, + customValidations + }); + } - static qValidateData(dispatch, {data, qName, customValidations = {}}) { - dispatch({ - type: qcommonActionTypes.VALIDATE_DATA, - data, - qName, - customValidations - }); - } + static qValidateForm(dispatch, qName, customValidations) { + dispatch({ + type: qcommonActionTypes.VALIDATE_FORM, + qName, + customValidations + }); + } - static qValidateForm(dispatch, qName, customValidations){ - dispatch({ - type: qcommonActionTypes.VALIDATE_FORM, - qName, - customValidations - }); - } + static qDataChanged( + dispatch, + { deltaData, qName, customValidations = {} } + ) { + dispatch({ + type: qcommonActionTypes.DATA_CHANGED, + deltaData, + qName, + customValidations + }); + } - static qDataChanged(dispatch, {deltaData, qName, customValidations = {}}){ - dispatch({ - type: qcommonActionTypes.DATA_CHANGED, - deltaData, - qName, - customValidations - }); - } + static qDataLoaded(dispatch, { qName, response: { qdata, qschema } }) { + dispatch({ + type: qcommonActionTypes.DATA_LOADED, + payload: { + qdata, + qschema + }, + qName + }); + } - static qDataLoaded(dispatch, {qName, response: {qdata, qschema}}) { - dispatch({ - type: qcommonActionTypes.DATA_LOADED, - payload: { - qdata, - qschema - }, - qName - }); - } - - static checkFormValid(genericFieldInfo) { - for (let field in genericFieldInfo) { - if (!genericFieldInfo[field].isValid) { - return false; - } - } - return true; - } + static checkFormValid(genericFieldInfo) { + for (let field in genericFieldInfo) { + if (!genericFieldInfo[field].isValid) { + return false; + } + } + return true; + } } export default ValidationHelper; diff --git a/openecomp-ui/src/sdc-app/common/merge/MergeEditor.js b/openecomp-ui/src/sdc-app/common/merge/MergeEditor.js index baf00cf0cf..81f7174623 100644 --- a/openecomp-ui/src/sdc-app/common/merge/MergeEditor.js +++ b/openecomp-ui/src/sdc-app/common/merge/MergeEditor.js @@ -13,25 +13,42 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import MergeEditorView from './MergeEditorView.jsx'; import MergeEditorActionHelper from './MergeEditorActionHelper.js'; -export const mapStateToProps = ({mergeEditor, currentScreen}) => { - let {props} = currentScreen; - let item = { - id: props.softwareProductId || props.licenseModelId, - version: props.version - }; - return {...mergeEditor, item, currentScreen}; +export const mapStateToProps = ({ mergeEditor, currentScreen }) => { + let { props } = currentScreen; + let item = { + id: props.softwareProductId || props.licenseModelId, + version: props.version + }; + return { ...mergeEditor, item, currentScreen }; }; -export const mapActionsToProps = (dispatch) => { - return { - fetchConflict: ({cid, itemId, version}) => MergeEditorActionHelper.fetchConflict(dispatch, {itemId, version, cid}), - onResolveConflict: ({conflictId, resolution, itemId, version, currentScreen}) => - MergeEditorActionHelper.resolveConflict(dispatch, {itemId, version, conflictId, resolution, currentScreen}) - }; +export const mapActionsToProps = dispatch => { + return { + fetchConflict: ({ cid, itemId, version }) => + MergeEditorActionHelper.fetchConflict(dispatch, { + itemId, + version, + cid + }), + onResolveConflict: ({ + conflictId, + resolution, + itemId, + version, + currentScreen + }) => + MergeEditorActionHelper.resolveConflict(dispatch, { + itemId, + version, + conflictId, + resolution, + currentScreen + }) + }; }; export default connect(mapStateToProps, mapActionsToProps)(MergeEditorView); diff --git a/openecomp-ui/src/sdc-app/common/merge/MergeEditorActionHelper.js b/openecomp-ui/src/sdc-app/common/merge/MergeEditorActionHelper.js index 92ec60b999..c54b9feb93 100644 --- a/openecomp-ui/src/sdc-app/common/merge/MergeEditorActionHelper.js +++ b/openecomp-ui/src/sdc-app/common/merge/MergeEditorActionHelper.js @@ -13,431 +13,532 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, rules, dataRules, SyncStates} from './MergeEditorConstants.js'; +import { + actionTypes, + rules, + dataRules, + SyncStates +} from './MergeEditorConstants.js'; import cloneDeep from 'lodash/cloneDeep.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; import ItemsHelper from '../../common/helpers/ItemsHelper.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {optionsInputValues as epOptionsValues} from 'sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js'; -import {optionsInputValues as laOptionsValues} from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js'; -import {optionsInputValues as processOptionValues} from 'sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js'; -import {selectValues as limitSelectValues} from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; +import { optionsInputValues as epOptionsValues } from 'sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js'; +import { optionsInputValues as laOptionsValues } from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js'; +import { optionsInputValues as processOptionValues } from 'sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js'; +import { selectValues as limitSelectValues } from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js'; import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js'; import moment from 'moment'; -import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { DATE_FORMAT } from 'sdc-app/onboarding/OnboardingConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; function softwareProductCategoriesUrl() { - const restCatalogPrefix = Configuration.get('restCatalogPrefix'); - return `${restCatalogPrefix}/v1/categories/resources/`; + const restCatalogPrefix = Configuration.get('restCatalogPrefix'); + return `${restCatalogPrefix}/v1/categories/resources/`; } function versionUrl(itemId, versionId) { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}`; } function baseUrl(itemId, version, conflictId) { - const versionId = version.id; - const restPrefix = Configuration.get('restPrefix'); - let baseUrl = `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}/conflicts`; - return conflictId ? `${baseUrl}/${conflictId}` : baseUrl; + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + let baseUrl = `${restPrefix}/v1.0/items/${itemId}/versions/${versionId}/conflicts`; + return conflictId ? `${baseUrl}/${conflictId}` : baseUrl; } -function fetchConflicts({itemId, version}) { - return RestAPIUtil.fetch(`${baseUrl(itemId, version)}`); +function fetchConflicts({ itemId, version }) { + return RestAPIUtil.fetch(`${baseUrl(itemId, version)}`); } -function fetchConflictById({itemId, version, cid}) { - return RestAPIUtil.fetch(`${baseUrl(itemId, version, cid)}`); +function fetchConflictById({ itemId, version, cid }) { + return RestAPIUtil.fetch(`${baseUrl(itemId, version, cid)}`); } -function resolveConflict({itemId, version, conflictId, resolution}) { - return RestAPIUtil.put(`${baseUrl(itemId, version, conflictId)}`, {resolution}); +function resolveConflict({ itemId, version, conflictId, resolution }) { + return RestAPIUtil.put(`${baseUrl(itemId, version, conflictId)}`, { + resolution + }); } function fetchCategories() { - return RestAPIUtil.fetch(softwareProductCategoriesUrl()); + return RestAPIUtil.fetch(softwareProductCategoriesUrl()); } -function fetchVersion({vendorId, licensingVersion}) { - return RestAPIUtil.fetch(versionUrl(vendorId, licensingVersion)); +function fetchVersion({ vendorId, licensingVersion }) { + return RestAPIUtil.fetch(versionUrl(vendorId, licensingVersion)); } -function createCategoryStr(data, {categories}) { - - let {category, subCategory} = data; - let foundCat = categories.find(element => element.uniqueId === category); - if (!foundCat) { return ''; } - - let catName = foundCat.name; - let foundSub = foundCat.subcategories.find(element => element.uniqueId === subCategory); - if (!foundSub) { return `${catName}`; } - - let subcatName = foundSub.name; - return `${catName} - ${subcatName}`; - +function createCategoryStr(data, { categories }) { + let { category, subCategory } = data; + let foundCat = categories.find(element => element.uniqueId === category); + if (!foundCat) { + return ''; + } + + let catName = foundCat.name; + let foundSub = foundCat.subcategories.find( + element => element.uniqueId === subCategory + ); + if (!foundSub) { + return `${catName}`; + } + + let subcatName = foundSub.name; + return `${catName} - ${subcatName}`; } -function getEnumValues({enums, list}) { - - if (!list) { return ''; } - return list.map(item => enums.find(el => el.enum === item).title); - +function getEnumValues({ enums, list }) { + if (!list) { + return ''; + } + return list.map(item => enums.find(el => el.enum === item).title); } const MergeEditorActionHelper = { - - analyzeSyncResult(dispatch, {itemId, version}) { - return ItemsHelper.checkItemStatus(dispatch, {itemId, versionId: version.id}).then((response) => { - let inMerge = response && response.state && response.state.synchronizationState === SyncStates.MERGE; - if (inMerge) { - MergeEditorActionHelper.fetchConflicts(dispatch, {itemId, version}).then(() => - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.MERGE_EDITOR, - modalClassName: 'merge-editor-modal', - title: `${i18n('Merge Required')} - ${version.description}`, - onDeclined: () => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - }, - modalComponentProps: { - size: 'lg', - type: 'default' - } - } - }) - ); - } - return Promise.resolve({updatedVersion: response, inMerge, isDirty: response.state.dirty}); - }); - }, - - fetchConflicts(dispatch, {itemId, version}) { - return fetchConflicts({itemId, version}).then( - (data) => { - dispatch({ - type: actionTypes.LOAD_CONFLICTS, - data - }); - return data; - } - ); - }, - - fetchConflict(dispatch, {itemId, version, cid}) { - fetchConflictById({itemId, version, cid}).then( - (data) => { - let newData = {}; - newData = MergeEditorActionHelper.processConflict(dispatch, {conflict: data, itemId, cid, version}); - dispatch({ - type: actionTypes.LOAD_CONFLICT, - data: newData - }); - } - ); - }, - - resolveConflict(dispatch, {itemId, version, conflictId, resolution, currentScreen}) { - resolveConflict({itemId, version, conflictId, resolution}).then(() => { - MergeEditorActionHelper.fetchConflicts(dispatch, {itemId, version}).then(conflicts => { - if(conflicts.conflictInfoList && conflicts.conflictInfoList.length === 0) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - ScreensHelper.loadLandingScreen(dispatch, {previousScreenName: currentScreen.screen, props: currentScreen.props}); - ItemsHelper.checkItemStatus(dispatch, {itemId, versionId: version.id}); - } - }); - }); - }, - - createConflictObject(data, {cid, conflict, dispatch, itemId, version, isYours}) { - - let newData = {}; - - for (let key in data) { - - if (data.hasOwnProperty(key)) { - let value = data[key]; - let fieldRule = dataRules[conflict.type] && dataRules[conflict.type][key] || dataRules.general[key]; - - if (fieldRule) { - switch (fieldRule.rule) { - - case rules.SKIP: - break; - - case rules.BOOLEAN: - let {trueValue, falseValue} = fieldRule; - newData[key] = value === trueValue ? true : value === falseValue ? false : undefined; - break; - - case rules.PARSE: - let {moveFields, subFields} = fieldRule; - if (moveFields) { - let fields = subFields || Object.keys(value); - fields.forEach(field => { - newData[field] = MergeEditorActionHelper.createConflictObject( - value[field], {cid, conflict, dispatch, itemId, version, isYours} - ); - }); - } else { - newData[key] = MergeEditorActionHelper.createConflictObject( - value, {cid, conflict, dispatch, itemId, version, isYours} - ); - } - break; - - case rules.FUNCTION: - let {args, functionName} = fieldRule; - newData[key] = MergeEditorActionHelper[functionName](data, { - cid, conflict, dispatch, version, fieldName: key, isYours, itemId, args - }); - break; - - default: - newData[key] = value; - break; - } - - } else { - newData[key] = value; - - } - } - } - - return newData; - - }, - - getNamesFromIDs(data, {version, cid, dispatch, itemId, fieldName, isYours, args}) { - - let idList = data[fieldName] || []; - let {fetchFunction, fetchField} = args; - - let promises = idList.map(id => - new Promise(resolve => - MergeEditorActionHelper[fetchFunction]( - dispatch, {licenseModelId: itemId, [fetchField]: id, version} - ).then(item => resolve(item.name)) - ) - ); - - Promise.all(promises).then(fetchedItems => { - let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; - dispatch({ - type: actionTypes.DATA_PROCESSED, - data: { - cid, - [yoursOrTheirs]: { name: fieldName, value: fetchedItems } - } - }); - }); - - return idList; - - }, - - getFeatureGroups(data, {version, cid, dispatch, itemId, fieldName, isYours}) { - - let featureGroups = data[fieldName] || []; - if (!(featureGroups instanceof Array)) { - featureGroups = [featureGroups]; - } - - let promises = featureGroups.map(featureGroupId => - new Promise(resolve => - FeatureGroupsActionHelper.fetchFeatureGroup( - dispatch, {licenseModelId: itemId, featureGroupId, version} - ).then(featureGroup => resolve(featureGroup.name)) - .catch(reason => console.log(`getFeatureGroups Promise rejected ('${reason}')`)) - ) - ); - - Promise.all(promises).then(fetchedGroups => { - let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; - dispatch({ - type: actionTypes.DATA_PROCESSED, - data: { - cid, - [yoursOrTheirs]: { name: fieldName, value: fetchedGroups } - } - }); - }); - - return featureGroups; - - }, - - getLicenseAgreements(data, {version, cid, dispatch, itemId, fieldName, isYours}) { - - let licenseAgreements = data[fieldName] || []; - if (!(licenseAgreements instanceof Array)) { - licenseAgreements = [licenseAgreements]; - } - - let promises = licenseAgreements.map(licenseAgreementId => - new Promise(resolve => - LicenseAgreementActionHelper.fetchLicenseAgreement( - dispatch, {licenseModelId: itemId, licenseAgreementId, version} - ).then(licenseAgreement => resolve(licenseAgreement.name)) - .catch(reason => console.log(`getLicenseAgreements Promise rejected ('${reason}')`)) - ) - ); - - Promise.all(promises).then(fetchedAgreements => { - let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; - dispatch({ - type: actionTypes.DATA_PROCESSED, - data: { - cid, - [yoursOrTheirs]: { name: fieldName, value: fetchedAgreements } - } - }); - }); - - return licenseAgreements; - - }, - - processConflict(dispatch, {conflict, cid, version, itemId,}) { - - let {id, type, yours, theirs} = conflict; - - let newYours = MergeEditorActionHelper.createConflictObject( - cloneDeep(yours), {cid, conflict, dispatch, itemId, version, isYours: true} - ); - let newTheirs = MergeEditorActionHelper.createConflictObject( - cloneDeep(theirs), {cid, conflict, dispatch, itemId, version, isYours: false} - ); - - return { - id, - type, - yours: newYours, - theirs: newTheirs - }; - - }, - - reduceList(data, {fieldName, args}) { - - let {subField} = args; - return data[fieldName].map(el => el[subField]); - - }, - - getEnumList({fieldName}) { - - const enumLists = { - 'licenseTerm': laOptionsValues.LICENSE_MODEL_TYPE, - 'operationalScope': epOptionsValues.OPERATIONAL_SCOPE, - 'processType': processOptionValues.PROCESS_TYPE, - 'limitType': [ - {title: 'Service Provider', enum: 'ServiceProvider'}, - {title: 'Vendor', enum: 'Vendor'} - ], - 'limitUnit': limitSelectValues.UNIT - }; - - return enumLists[fieldName]; - - }, - - getEnumValue(data, {fieldName, args = {}}) { - - let value = data[fieldName]; - let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); - let enumValue = enumValues.find(el => el.enum === value); - - return enumValue && enumValue.title || value; - - }, - - processChoice(data, {fieldName, args = {}}) { - - let value = data[fieldName]; - let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); - let newValue = value.other || enumValues && enumValues.find(el => el.enum === value.choice).title || value.choice; - - return newValue; - - }, - - processChoices(data, {fieldName, args = {}}) { - - let value = data[fieldName]; - let enumValues = MergeEditorActionHelper.getEnumList({fieldName: args.listName || fieldName}); - let newValue = value.other || getEnumValues({enums: enumValues, list: value.choices}) || value.choices; - - return newValue; - - }, - - convertArrayToObject(data, {fieldName}) { - let value = data[fieldName]; - let newValue = {}; - value.forEach((el, index) => { - newValue[index] = el; - }); - return newValue; - }, - - fetchCategory(data, {cid, isYours, fieldName, dispatch}) { - - fetchCategories().then((categories) => { - let value = createCategoryStr(data, {categories}); - let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; - - dispatch({ - type: actionTypes.DATA_PROCESSED, - data: { - cid, - [yoursOrTheirs]: { name: fieldName, value } - } - }); - - }); - }, - - fetchLMVersion(data, {cid, dispatch, isYours}) { - - let {licensingVersion, vendorId} = data; - let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; - - if (licensingVersion) { - fetchVersion({licensingVersion, vendorId}).then(response => { - dispatch({ - type: actionTypes.DATA_PROCESSED, - data: { - cid, - [yoursOrTheirs]: { - name: 'licensingVersion', - value: response.name - } - } - }); - }); - } - - }, - - parseDate(data, {fieldName}) { - - let date = data[fieldName]; - return date && moment(date, DATE_FORMAT).format(DATE_FORMAT); - - } - + analyzeSyncResult(dispatch, { itemId, version }) { + return ItemsHelper.checkItemStatus(dispatch, { + itemId, + versionId: version.id + }).then(response => { + let inMerge = + response && + response.state && + response.state.synchronizationState === SyncStates.MERGE; + if (inMerge) { + MergeEditorActionHelper.fetchConflicts(dispatch, { + itemId, + version + }).then(() => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.MERGE_EDITOR, + modalClassName: 'merge-editor-modal', + title: `${i18n('Merge Required')} - ${ + version.description + }`, + onDeclined: () => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + }, + modalComponentProps: { + size: 'lg', + type: 'default' + } + } + }) + ); + } + return Promise.resolve({ + updatedVersion: response, + inMerge, + isDirty: response.state.dirty + }); + }); + }, + + fetchConflicts(dispatch, { itemId, version }) { + return fetchConflicts({ itemId, version }).then(data => { + dispatch({ + type: actionTypes.LOAD_CONFLICTS, + data + }); + return data; + }); + }, + + fetchConflict(dispatch, { itemId, version, cid }) { + fetchConflictById({ itemId, version, cid }).then(data => { + let newData = {}; + newData = MergeEditorActionHelper.processConflict(dispatch, { + conflict: data, + itemId, + cid, + version + }); + dispatch({ + type: actionTypes.LOAD_CONFLICT, + data: newData + }); + }); + }, + + resolveConflict( + dispatch, + { itemId, version, conflictId, resolution, currentScreen } + ) { + resolveConflict({ itemId, version, conflictId, resolution }).then( + () => { + MergeEditorActionHelper.fetchConflicts(dispatch, { + itemId, + version + }).then(conflicts => { + if ( + conflicts.conflictInfoList && + conflicts.conflictInfoList.length === 0 + ) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + ScreensHelper.loadLandingScreen(dispatch, { + previousScreenName: currentScreen.screen, + props: currentScreen.props + }); + ItemsHelper.checkItemStatus(dispatch, { + itemId, + versionId: version.id + }); + } + }); + } + ); + }, + + createConflictObject( + data, + { cid, conflict, dispatch, itemId, version, isYours } + ) { + let newData = {}; + + for (let key in data) { + if (data.hasOwnProperty(key)) { + let value = data[key]; + let fieldRule = + (dataRules[conflict.type] && + dataRules[conflict.type][key]) || + dataRules.general[key]; + + if (fieldRule) { + switch (fieldRule.rule) { + case rules.SKIP: + break; + + case rules.BOOLEAN: + let { trueValue, falseValue } = fieldRule; + newData[key] = + value === trueValue + ? true + : value === falseValue ? false : undefined; + break; + + case rules.PARSE: + let { moveFields, subFields } = fieldRule; + if (moveFields) { + let fields = subFields || Object.keys(value); + fields.forEach(field => { + newData[ + field + ] = MergeEditorActionHelper.createConflictObject( + value[field], + { + cid, + conflict, + dispatch, + itemId, + version, + isYours + } + ); + }); + } else { + newData[ + key + ] = MergeEditorActionHelper.createConflictObject( + value, + { + cid, + conflict, + dispatch, + itemId, + version, + isYours + } + ); + } + break; + + case rules.FUNCTION: + let { args, functionName } = fieldRule; + newData[key] = MergeEditorActionHelper[ + functionName + ](data, { + cid, + conflict, + dispatch, + version, + fieldName: key, + isYours, + itemId, + args + }); + break; + + default: + newData[key] = value; + break; + } + } else { + newData[key] = value; + } + } + } + + return newData; + }, + + getNamesFromIDs( + data, + { version, cid, dispatch, itemId, fieldName, isYours, args } + ) { + let idList = data[fieldName] || []; + let { fetchFunction, fetchField } = args; + + let promises = idList.map( + id => + new Promise(resolve => + MergeEditorActionHelper[fetchFunction](dispatch, { + licenseModelId: itemId, + [fetchField]: id, + version + }).then(item => resolve(item.name)) + ) + ); + + Promise.all(promises).then(fetchedItems => { + let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; + dispatch({ + type: actionTypes.DATA_PROCESSED, + data: { + cid, + [yoursOrTheirs]: { name: fieldName, value: fetchedItems } + } + }); + }); + + return idList; + }, + + getFeatureGroups( + data, + { version, cid, dispatch, itemId, fieldName, isYours } + ) { + let featureGroups = data[fieldName] || []; + if (!(featureGroups instanceof Array)) { + featureGroups = [featureGroups]; + } + + let promises = featureGroups.map( + featureGroupId => + new Promise(resolve => + FeatureGroupsActionHelper.fetchFeatureGroup(dispatch, { + licenseModelId: itemId, + featureGroupId, + version + }) + .then(featureGroup => resolve(featureGroup.name)) + .catch(reason => + console.log( + `getFeatureGroups Promise rejected ('${reason}')` + ) + ) + ) + ); + + Promise.all(promises).then(fetchedGroups => { + let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; + dispatch({ + type: actionTypes.DATA_PROCESSED, + data: { + cid, + [yoursOrTheirs]: { name: fieldName, value: fetchedGroups } + } + }); + }); + + return featureGroups; + }, + + getLicenseAgreements( + data, + { version, cid, dispatch, itemId, fieldName, isYours } + ) { + let licenseAgreements = data[fieldName] || []; + if (!(licenseAgreements instanceof Array)) { + licenseAgreements = [licenseAgreements]; + } + + let promises = licenseAgreements.map( + licenseAgreementId => + new Promise(resolve => + LicenseAgreementActionHelper.fetchLicenseAgreement( + dispatch, + { + licenseModelId: itemId, + licenseAgreementId, + version + } + ) + .then(licenseAgreement => + resolve(licenseAgreement.name) + ) + .catch(reason => + console.log( + `getLicenseAgreements Promise rejected ('${reason}')` + ) + ) + ) + ); + + Promise.all(promises).then(fetchedAgreements => { + let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; + dispatch({ + type: actionTypes.DATA_PROCESSED, + data: { + cid, + [yoursOrTheirs]: { + name: fieldName, + value: fetchedAgreements + } + } + }); + }); + + return licenseAgreements; + }, + + processConflict(dispatch, { conflict, cid, version, itemId }) { + let { id, type, yours, theirs } = conflict; + + let newYours = MergeEditorActionHelper.createConflictObject( + cloneDeep(yours), + { cid, conflict, dispatch, itemId, version, isYours: true } + ); + let newTheirs = MergeEditorActionHelper.createConflictObject( + cloneDeep(theirs), + { cid, conflict, dispatch, itemId, version, isYours: false } + ); + + return { + id, + type, + yours: newYours, + theirs: newTheirs + }; + }, + + reduceList(data, { fieldName, args }) { + let { subField } = args; + return data[fieldName].map(el => el[subField]); + }, + + getEnumList({ fieldName }) { + const enumLists = { + licenseTerm: laOptionsValues.LICENSE_MODEL_TYPE, + operationalScope: epOptionsValues.OPERATIONAL_SCOPE, + processType: processOptionValues.PROCESS_TYPE, + limitType: [ + { title: 'Service Provider', enum: 'ServiceProvider' }, + { title: 'Vendor', enum: 'Vendor' } + ], + limitUnit: limitSelectValues.UNIT + }; + + return enumLists[fieldName]; + }, + + getEnumValue(data, { fieldName, args = {} }) { + let value = data[fieldName]; + let enumValues = MergeEditorActionHelper.getEnumList({ + fieldName: args.listName || fieldName + }); + let enumValue = enumValues.find(el => el.enum === value); + + return (enumValue && enumValue.title) || value; + }, + + processChoice(data, { fieldName, args = {} }) { + let value = data[fieldName]; + let enumValues = MergeEditorActionHelper.getEnumList({ + fieldName: args.listName || fieldName + }); + let newValue = + value.other || + (enumValues && + enumValues.find(el => el.enum === value.choice).title) || + value.choice; + + return newValue; + }, + + processChoices(data, { fieldName, args = {} }) { + let value = data[fieldName]; + let enumValues = MergeEditorActionHelper.getEnumList({ + fieldName: args.listName || fieldName + }); + let newValue = + value.other || + getEnumValues({ enums: enumValues, list: value.choices }) || + value.choices; + + return newValue; + }, + + convertArrayToObject(data, { fieldName }) { + let value = data[fieldName]; + let newValue = {}; + value.forEach((el, index) => { + newValue[index] = el; + }); + return newValue; + }, + + fetchCategory(data, { cid, isYours, fieldName, dispatch }) { + fetchCategories().then(categories => { + let value = createCategoryStr(data, { categories }); + let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; + + dispatch({ + type: actionTypes.DATA_PROCESSED, + data: { + cid, + [yoursOrTheirs]: { name: fieldName, value } + } + }); + }); + }, + + fetchLMVersion(data, { cid, dispatch, isYours }) { + let { licensingVersion, vendorId } = data; + let yoursOrTheirs = isYours ? 'yoursField' : 'theirsField'; + + if (licensingVersion) { + fetchVersion({ licensingVersion, vendorId }).then(response => { + dispatch({ + type: actionTypes.DATA_PROCESSED, + data: { + cid, + [yoursOrTheirs]: { + name: 'licensingVersion', + value: response.name + } + } + }); + }); + } + }, + + parseDate(data, { fieldName }) { + let date = data[fieldName]; + return date && moment(date, DATE_FORMAT).format(DATE_FORMAT); + } }; export default MergeEditorActionHelper; diff --git a/openecomp-ui/src/sdc-app/common/merge/MergeEditorConstants.js b/openecomp-ui/src/sdc-app/common/merge/MergeEditorConstants.js index f7f6d4195e..b82d08683f 100644 --- a/openecomp-ui/src/sdc-app/common/merge/MergeEditorConstants.js +++ b/openecomp-ui/src/sdc-app/common/merge/MergeEditorConstants.js @@ -17,208 +17,205 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - LOAD_CONFLICTS: null, - ADD_ACTIONS: null, - LOAD_CONFLICT: null, - DATA_PROCESSED: null + LOAD_CONFLICTS: null, + ADD_ACTIONS: null, + LOAD_CONFLICT: null, + DATA_PROCESSED: null }); export const rules = { - SKIP: 'skip', - PARSE: 'parse', - FUNCTION: 'function', - BOOLEAN: 'boolean' + SKIP: 'skip', + PARSE: 'parse', + FUNCTION: 'function', + BOOLEAN: 'boolean' }; export const SyncStates = { - MERGE : 'Merging', - OUT_OF_SYNC: 'OutOfSync', - UP_TO_DATE: 'UpToDate' + MERGE: 'Merging', + OUT_OF_SYNC: 'OutOfSync', + UP_TO_DATE: 'UpToDate' }; export const ResolutionTypes = { - YOURS: 'YOURS', - THEIRS: 'THEIRS' + YOURS: 'YOURS', + THEIRS: 'THEIRS' }; export const fileTypes = { - LKG : 'LicenseKeyGroup', - VLM : 'VendorLicenseModel', - EP : 'EntitlementPool', - FG : 'FeatureGroup', - LA : 'LicenseAgreement', - VSP : 'VendorSoftwareProduct', - LIMIT : 'Limit', - VSP_Q : 'VSPQuestionnaire', - COMPONENT : 'Component', - COMPONENT_Q : 'ComponentQuestionnaire', - COMPONENT_DEP : 'ComponentDependencies', - COMPUTE_Q : 'ComputeQuestionnaire', - COMPUTE : 'Compute', - COMPUTE_FLAVOR: 'ComputeFlavor', - NIC : 'Nic', - NIC_Q : 'NicQuestionnaire', - IMAGE : 'Image', - IMAGE_Q : 'ImageQuestionnaire', - PROCESS : 'Process', - DEPLOYMENT_FLAVOR : 'DeploymentFlavor', - VENDOR : 'Vendor', - NETWORK : 'Network', - ORCHESTRATION_TEMPLATE_CANDIDATE : 'OrchestrationTemplateCandidate' + LKG: 'LicenseKeyGroup', + VLM: 'VendorLicenseModel', + EP: 'EntitlementPool', + FG: 'FeatureGroup', + LA: 'LicenseAgreement', + VSP: 'VendorSoftwareProduct', + LIMIT: 'Limit', + VSP_Q: 'VSPQuestionnaire', + COMPONENT: 'Component', + COMPONENT_Q: 'ComponentQuestionnaire', + COMPONENT_DEP: 'ComponentDependencies', + COMPUTE_Q: 'ComputeQuestionnaire', + COMPUTE: 'Compute', + COMPUTE_FLAVOR: 'ComputeFlavor', + NIC: 'Nic', + NIC_Q: 'NicQuestionnaire', + IMAGE: 'Image', + IMAGE_Q: 'ImageQuestionnaire', + PROCESS: 'Process', + DEPLOYMENT_FLAVOR: 'DeploymentFlavor', + VENDOR: 'Vendor', + NETWORK: 'Network', + ORCHESTRATION_TEMPLATE_CANDIDATE: 'OrchestrationTemplateCandidate' }; export const dataRules = { - general: { - id: { - rule: rules.SKIP - }, - questionareData: { - rule: rules.PARSE, - moveFields: true - }, - startDate: { - rule: rules.FUNCTION, - functionName: 'parseDate' - }, - expiryDate: { - rule: rules.FUNCTION, - functionName: 'parseDate' - }, - featureGroups: { - rule: rules.FUNCTION, - functionName: 'reduceList', - args: {subField: 'name'} - }, - licenseKeyGroups: { - rule: rules.FUNCTION, - functionName: 'reduceList', - args: {subField: 'name'} - }, - entitlementPools: { - rule: rules.FUNCTION, - functionName: 'reduceList', - args: {subField: 'name'} - }, - }, - [fileTypes.COMPONENT] : { - }, - [fileTypes.COMPUTE_FLAVOR] : { - associatedToDeploymentFlavor: { - rule: rules.BOOLEAN, - trueValue: 'true' - } - }, - [fileTypes.COMPUTE_Q] : { - }, - [fileTypes.COMPONENT_Q] : { - isComponentMandatory: { - rule: rules.BOOLEAN, - trueValue: 'YES', - falseValue: 'NO' - } - }, - [fileTypes.EP] : { - referencingFeatureGroups: { - rule: rules.SKIP, - functionName: 'getFeatureGroups' - }, - operationalScope: { - rule: rules.FUNCTION, - functionName: 'processChoices' - }, - }, - [fileTypes.FG] : { - referencingLicenseAgreements: { - rule: rules.SKIP, - functionName: 'getLicenseAgreements' - } - }, - [fileTypes.LA] : { - licenseTerm : { - rule: rules.FUNCTION, - functionName: 'processChoice' - } - }, - [fileTypes.LIMIT] : { - type: { - rule: rules.FUNCTION, - functionName: 'getEnumValue', - args: {listName: 'limitType'} - }, - unit: { - rule: rules.FUNCTION, - functionName: 'getEnumValue', - args: {listName: 'limitUnit'} - } - }, - [fileTypes.LKG] : { - operationalScope: { - rule: rules.FUNCTION, - functionName: 'processChoices' - }, - referencingFeatureGroups: { - rule: rules.SKIP, - functionName: 'getFeatureGroups' - }, - }, - [fileTypes.NIC] : { - networkId: { - rule: rules.SKIP - } - }, - [fileTypes.NIC_Q] : { - }, - [fileTypes.PROCESS] : { - type: { - rule: rules.FUNCTION, - functionName: 'getEnumValue', - args: {listName: 'processType'} - } - }, - [fileTypes.VLM] : { - iconRef: { - rule: rules.SKIP - } - }, - [fileTypes.VSP] : { - vendorId: { - rule: rules.SKIP - }, - onboardingMethod: { - rule: rules.SKIP - }, - validationData: { - rule: rules.SKIP - }, - isOldVersion: { - rule: rules.SKIP - }, - licensingVersion: { - rule: rules.FUNCTION, - functionName: 'fetchLMVersion' - }, - category: { - rule: rules.FUNCTION, - functionName: 'fetchCategory' - }, - subCategory: { - rule: rules.SKIP - }, - }, - [fileTypes.VSP_Q] : { - affinityData: { - rule: rules.SKIP - }, - storageReplicationAcrossRegion: { - rule: rules.BOOLEAN, - trueValue: 'true', - falseValue: 'false' - } - }, - [fileTypes.ORCHESTRATION_TEMPLATE_CANDIDATE] : { - modules: { - rule: rules.FUNCTION, - functionName: 'convertArrayToObject' - }, - }, + general: { + id: { + rule: rules.SKIP + }, + questionareData: { + rule: rules.PARSE, + moveFields: true + }, + startDate: { + rule: rules.FUNCTION, + functionName: 'parseDate' + }, + expiryDate: { + rule: rules.FUNCTION, + functionName: 'parseDate' + }, + featureGroups: { + rule: rules.FUNCTION, + functionName: 'reduceList', + args: { subField: 'name' } + }, + licenseKeyGroups: { + rule: rules.FUNCTION, + functionName: 'reduceList', + args: { subField: 'name' } + }, + entitlementPools: { + rule: rules.FUNCTION, + functionName: 'reduceList', + args: { subField: 'name' } + } + }, + [fileTypes.COMPONENT]: {}, + [fileTypes.COMPUTE_FLAVOR]: { + associatedToDeploymentFlavor: { + rule: rules.BOOLEAN, + trueValue: 'true' + } + }, + [fileTypes.COMPUTE_Q]: {}, + [fileTypes.COMPONENT_Q]: { + isComponentMandatory: { + rule: rules.BOOLEAN, + trueValue: 'YES', + falseValue: 'NO' + } + }, + [fileTypes.EP]: { + referencingFeatureGroups: { + rule: rules.SKIP, + functionName: 'getFeatureGroups' + }, + operationalScope: { + rule: rules.FUNCTION, + functionName: 'processChoices' + } + }, + [fileTypes.FG]: { + referencingLicenseAgreements: { + rule: rules.SKIP, + functionName: 'getLicenseAgreements' + } + }, + [fileTypes.LA]: { + licenseTerm: { + rule: rules.FUNCTION, + functionName: 'processChoice' + } + }, + [fileTypes.LIMIT]: { + type: { + rule: rules.FUNCTION, + functionName: 'getEnumValue', + args: { listName: 'limitType' } + }, + unit: { + rule: rules.FUNCTION, + functionName: 'getEnumValue', + args: { listName: 'limitUnit' } + } + }, + [fileTypes.LKG]: { + operationalScope: { + rule: rules.FUNCTION, + functionName: 'processChoices' + }, + referencingFeatureGroups: { + rule: rules.SKIP, + functionName: 'getFeatureGroups' + } + }, + [fileTypes.NIC]: { + networkId: { + rule: rules.SKIP + } + }, + [fileTypes.NIC_Q]: {}, + [fileTypes.PROCESS]: { + type: { + rule: rules.FUNCTION, + functionName: 'getEnumValue', + args: { listName: 'processType' } + } + }, + [fileTypes.VLM]: { + iconRef: { + rule: rules.SKIP + } + }, + [fileTypes.VSP]: { + vendorId: { + rule: rules.SKIP + }, + onboardingMethod: { + rule: rules.SKIP + }, + validationData: { + rule: rules.SKIP + }, + isOldVersion: { + rule: rules.SKIP + }, + licensingVersion: { + rule: rules.FUNCTION, + functionName: 'fetchLMVersion' + }, + category: { + rule: rules.FUNCTION, + functionName: 'fetchCategory' + }, + subCategory: { + rule: rules.SKIP + } + }, + [fileTypes.VSP_Q]: { + affinityData: { + rule: rules.SKIP + }, + storageReplicationAcrossRegion: { + rule: rules.BOOLEAN, + trueValue: 'true', + falseValue: 'false' + } + }, + [fileTypes.ORCHESTRATION_TEMPLATE_CANDIDATE]: { + modules: { + rule: rules.FUNCTION, + functionName: 'convertArrayToObject' + } + } }; diff --git a/openecomp-ui/src/sdc-app/common/merge/MergeEditorReducer.js b/openecomp-ui/src/sdc-app/common/merge/MergeEditorReducer.js index 6985fcfaca..1630849b64 100644 --- a/openecomp-ui/src/sdc-app/common/merge/MergeEditorReducer.js +++ b/openecomp-ui/src/sdc-app/common/merge/MergeEditorReducer.js @@ -13,54 +13,54 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './MergeEditorConstants.js'; +import { actionTypes } from './MergeEditorConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.LOAD_CONFLICT: { - let cdata = {...action.data}; - // let data = state.conflicts ? {...state.conflicts.data} : {} ; - // data[cdata.id] = cdata; - let conflicts = state.conflicts ? {...state.conflicts} : {}; - conflicts[cdata.id] = cdata; - return { - ...state, - conflicts - }; - } - case actionTypes.DATA_PROCESSED: { - let conflicts = {...state.conflicts}; - let {data} = action; - if (data && data.cid) { - let yours = {...conflicts[data.cid].yours}; - let theirs = {...conflicts[data.cid].theirs}; - let {yoursField, theirsField} = data; - if (yoursField) { - yours[yoursField.name] = yoursField.value; - conflicts[data.cid].yours = yours; - } - if (theirsField) { - theirs[theirsField.name] = theirsField.value; - conflicts[data.cid].theirs = theirs; - } - } - return { - ...state, - conflicts: { - ...conflicts - } - }; - } - case actionTypes.LOAD_CONFLICTS: - let conflictFiles = []; - if (action.data) { - conflictFiles = [...action.data.conflictInfoList]; - } - return { - inMerge: conflictFiles.length > 0, - conflictFiles - }; - default: - return state; - } + switch (action.type) { + case actionTypes.LOAD_CONFLICT: { + let cdata = { ...action.data }; + // let data = state.conflicts ? {...state.conflicts.data} : {} ; + // data[cdata.id] = cdata; + let conflicts = state.conflicts ? { ...state.conflicts } : {}; + conflicts[cdata.id] = cdata; + return { + ...state, + conflicts + }; + } + case actionTypes.DATA_PROCESSED: { + let conflicts = { ...state.conflicts }; + let { data } = action; + if (data && data.cid) { + let yours = { ...conflicts[data.cid].yours }; + let theirs = { ...conflicts[data.cid].theirs }; + let { yoursField, theirsField } = data; + if (yoursField) { + yours[yoursField.name] = yoursField.value; + conflicts[data.cid].yours = yours; + } + if (theirsField) { + theirs[theirsField.name] = theirsField.value; + conflicts[data.cid].theirs = theirs; + } + } + return { + ...state, + conflicts: { + ...conflicts + } + }; + } + case actionTypes.LOAD_CONFLICTS: + let conflictFiles = []; + if (action.data) { + conflictFiles = [...action.data.conflictInfoList]; + } + return { + inMerge: conflictFiles.length > 0, + conflictFiles + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/common/merge/MergeEditorView.jsx b/openecomp-ui/src/sdc-app/common/merge/MergeEditorView.jsx index 34d86419e7..a7e36a39fc 100644 --- a/openecomp-ui/src/sdc-app/common/merge/MergeEditorView.jsx +++ b/openecomp-ui/src/sdc-app/common/merge/MergeEditorView.jsx @@ -24,233 +24,389 @@ import GridItem from 'nfvo-components/grid/GridItem.jsx'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Radio from 'sdc-ui/lib/react/Radio.js'; import equal from 'deep-equal'; -import {ResolutionTypes} from './MergeEditorConstants.js'; +import { ResolutionTypes } from './MergeEditorConstants.js'; -class ConflictCategory extends React.Component { - state = { - resolution: ResolutionTypes.YOURS - }; +class ConflictCategory extends React.Component { + state = { + resolution: ResolutionTypes.YOURS + }; - getTitle(conflictType, conflictName) { - if (typeof conflictName === 'undefined' || conflictType === conflictName) { - return i18n(conflictType); - } else { - return `${i18n(conflictType)}: ${conflictName}`; - } - } + getTitle(conflictType, conflictName) { + if ( + typeof conflictName === 'undefined' || + conflictType === conflictName + ) { + return i18n(conflictType); + } else { + return `${i18n(conflictType)}: ${conflictName}`; + } + } - render() { - let {collapseExpand, conflict: {id: conflictId, type, name}, isCollapsed, item: {id: itemId, version}, onResolveConflict} = this.props; - let {resolution} = this.state; - const iconClass = isCollapsed ? 'merge-chevron' : 'merge-chevron right'; + render() { + let { + collapseExpand, + conflict: { id: conflictId, type, name }, + isCollapsed, + item: { id: itemId, version }, + onResolveConflict + } = this.props; + let { resolution } = this.state; + const iconClass = isCollapsed ? 'merge-chevron' : 'merge-chevron right'; - return ( - <div key={'conflictCategory_' + conflictId} > - <GridSection className='conflict-section'> - <GridItem > - <div className='collapsible-section' onClick={collapseExpand}> - <SVGIcon name={isCollapsed ? 'chevronDown' : 'chevronUp'} iconClassName={iconClass} /> - <div className='conflict-title'>{this.getTitle(type, name)}</div> - </div> - </GridItem> - <GridItem className='yours'> - <Radio name={'radio_' + conflictId} checked={resolution === ResolutionTypes.YOURS} value='yours' - onChange={() => this.setState({resolution: ResolutionTypes.YOURS})} data-test-id={'radio_' + conflictId + '_yours'} /> - </GridItem> - <GridItem className='theirs'> - <Radio name={'radio_' + conflictId} checked={resolution === ResolutionTypes.THEIRS} value='theirs' - onChange={() => this.setState({resolution: ResolutionTypes.THEIRS})} data-test-id={'radio_' + conflictId + '_theirs'} /></GridItem> - <GridItem className='resolve'> - <Button className='conflict-resolve-btn' btnType='outline' color='gray' - onClick={() => onResolveConflict({conflictId, resolution, itemId, version})}> - {i18n('Resolve')} - </Button> - </GridItem> - </GridSection> - <div> - {isCollapsed && this.props.children} - </div> - </div> - ); - } - -}; - -class TextCompare extends React.Component { - render() { - // let rand = Math.random() * (3000 - 1) + 1; - let {yours, theirs, field, type, isObjName, conflictsOnly} = this.props; - let typeYours = typeof yours; - let typeTheirs = typeof theirs; + return ( + <div key={'conflictCategory_' + conflictId}> + <GridSection className="conflict-section"> + <GridItem> + <div + className="collapsible-section" + onClick={collapseExpand}> + <SVGIcon + name={isCollapsed ? 'chevronDown' : 'chevronUp'} + iconClassName={iconClass} + /> + <div className="conflict-title"> + {this.getTitle(type, name)} + </div> + </div> + </GridItem> + <GridItem className="yours"> + <Radio + name={'radio_' + conflictId} + checked={resolution === ResolutionTypes.YOURS} + value="yours" + onChange={() => + this.setState({ + resolution: ResolutionTypes.YOURS + }) + } + data-test-id={'radio_' + conflictId + '_yours'} + /> + </GridItem> + <GridItem className="theirs"> + <Radio + name={'radio_' + conflictId} + checked={resolution === ResolutionTypes.THEIRS} + value="theirs" + onChange={() => + this.setState({ + resolution: ResolutionTypes.THEIRS + }) + } + data-test-id={'radio_' + conflictId + '_theirs'} + /> + </GridItem> + <GridItem className="resolve"> + <Button + className="conflict-resolve-btn" + btnType="outline" + color="gray" + onClick={() => + onResolveConflict({ + conflictId, + resolution, + itemId, + version + }) + }> + {i18n('Resolve')} + </Button> + </GridItem> + </GridSection> + <div>{isCollapsed && this.props.children}</div> + </div> + ); + } +} - let parsedType = `${type}/${field}`.replace(/\/[0-9]+/g,'/index'); - let level = type.split('/').length; +class TextCompare extends React.Component { + render() { + // let rand = Math.random() * (3000 - 1) + 1; + let { + yours, + theirs, + field, + type, + isObjName, + conflictsOnly + } = this.props; + let typeYours = typeof yours; + let typeTheirs = typeof theirs; - if (typeYours === 'boolean' || typeTheirs === 'boolean') { - yours = yours ? i18n('Yes') : i18n('No'); - theirs = theirs ? i18n('Yes') : i18n('No'); - } + let parsedType = `${type}/${field}`.replace(/\/[0-9]+/g, '/index'); + let level = type.split('/').length; + if (typeYours === 'boolean' || typeTheirs === 'boolean') { + yours = yours ? i18n('Yes') : i18n('No'); + theirs = theirs ? i18n('Yes') : i18n('No'); + } - /*if ((typeYours !== 'string' && typeYours !== 'undefined') || (typeTheirs !== 'string' && typeTheirs !== 'undefined')) { + /*if ((typeYours !== 'string' && typeYours !== 'undefined') || (typeTheirs !== 'string' && typeTheirs !== 'undefined')) { return (<div className='merge-editor-text-field field-error'>{field} cannot be parsed for display</div>); }*/ - let isDiff = yours !== theirs; - if (!isObjName && - ((!isDiff && conflictsOnly) || - (yours === '' && theirs === '') || - (typeYours === 'undefined' && typeTheirs === 'undefined') - ) - ) { - return null; - } + let isDiff = yours !== theirs; + if ( + !isObjName && + ((!isDiff && conflictsOnly) || + (yours === '' && theirs === '') || + (typeYours === 'undefined' && typeTheirs === 'undefined')) + ) { + return null; + } - return ( - <GridSection className={isDiff ? 'merge-editor-text-field diff' : 'merge-editor-text-field'}> - <GridItem className='field-col grid-col-title' stretch> - <div className={`field ${isDiff ? 'diff' : ''} field-name level-${level} ${isObjName ? 'field-object-name' : ''}`}> - {i18n(parsedType)} - </div> - </GridItem> - <GridItem className='field-col grid-col-yours' stretch> - <div className={`field field-yours ${!yours ? 'empty-field' : ''}`} >{yours || (isObjName ? '' : '━━')}</div> - </GridItem> - <GridItem className='field-col grid-col-theirs' stretch> - <div className={`field field-theirs ${!theirs ? 'empty-field' : ''}`}>{theirs || (isObjName ? '' : '━━')}</div> - </GridItem> - <GridItem stretch/> - </GridSection> - ); - } -}; + return ( + <GridSection + className={ + isDiff + ? 'merge-editor-text-field diff' + : 'merge-editor-text-field' + }> + <GridItem className="field-col grid-col-title" stretch> + <div + className={`field ${ + isDiff ? 'diff' : '' + } field-name level-${level} ${ + isObjName ? 'field-object-name' : '' + }`}> + {i18n(parsedType)} + </div> + </GridItem> + <GridItem className="field-col grid-col-yours" stretch> + <div + className={`field field-yours ${ + !yours ? 'empty-field' : '' + }`}> + {yours || (isObjName ? '' : '━━')} + </div> + </GridItem> + <GridItem className="field-col grid-col-theirs" stretch> + <div + className={`field field-theirs ${ + !theirs ? 'empty-field' : '' + }`}> + {theirs || (isObjName ? '' : '━━')} + </div> + </GridItem> + <GridItem stretch /> + </GridSection> + ); + } +} class MergeEditorView extends React.Component { - state = { - collapsingSections: {}, - conflictsOnly: false - }; + state = { + collapsingSections: {}, + conflictsOnly: false + }; - render() { - let {conflicts, item, conflictFiles, onResolveConflict, currentScreen, resolution} = this.props; + render() { + let { + conflicts, + item, + conflictFiles, + onResolveConflict, + currentScreen, + resolution + } = this.props; - return ( - <div className='merge-editor'> - {conflictFiles && this.renderConflictTableTitles()} - <div className='merge-editor-body'> - {conflictFiles && conflictFiles.sort((a, b) => a.type > b.type).map(file => ( - <ConflictCategory key={'conflict_' + file.id} conflict={file} item={item} isCollapsed={this.state.collapsingSections[file.id]} - collapseExpand={()=>{this.updateCollapseState(file.id);}} - onResolveConflict={cDetails => onResolveConflict({...cDetails, currentScreen})}> - {(conflicts && conflicts[file.id]) && - this.getUnion(conflicts[file.id].yours, conflicts[file.id].theirs).map(field => { - return this.renderField(field, file, conflicts[file.id].yours[field], conflicts[file.id].theirs[field], resolution); - })} - </ConflictCategory>))} - </div> - </div>); - } + return ( + <div className="merge-editor"> + {conflictFiles && this.renderConflictTableTitles()} + <div className="merge-editor-body"> + {conflictFiles && + conflictFiles + .sort((a, b) => a.type > b.type) + .map(file => ( + <ConflictCategory + key={'conflict_' + file.id} + conflict={file} + item={item} + isCollapsed={ + this.state.collapsingSections[file.id] + } + collapseExpand={() => { + this.updateCollapseState(file.id); + }} + onResolveConflict={cDetails => + onResolveConflict({ + ...cDetails, + currentScreen + }) + }> + {conflicts && + conflicts[file.id] && + this.getUnion( + conflicts[file.id].yours, + conflicts[file.id].theirs + ).map(field => { + return this.renderField( + field, + file, + conflicts[file.id].yours[field], + conflicts[file.id].theirs[ + field + ], + resolution + ); + })} + </ConflictCategory> + ))} + </div> + </div> + ); + } - renderConflictTableTitles() - { - return (<GridSection className='conflict-titles-section'> - <GridItem> - {i18n('Page')} - </GridItem> - <GridItem className='yours'> - {i18n('Local (Me)')} - </GridItem> - <GridItem className='theirs'> - {i18n('Last Committed')} - </GridItem> - <GridItem className='resolve'> - <Input - label={i18n('Show Conflicts Only')} - type='checkbox' - value={this.state.conflictsOnly} - onChange={e => this.setState({conflictsOnly: e}) } /> - </GridItem> - </GridSection>); - } - // <Checkbox - // label={i18n('Show Conflicts Only')} - // value={this.state.conflictsOnly} - // checked={this.state.conflictsOnly} - // onChange={checked => this.setState({conflictsOnly: checked})} /> + renderConflictTableTitles() { + return ( + <GridSection className="conflict-titles-section"> + <GridItem>{i18n('Page')}</GridItem> + <GridItem className="yours">{i18n('Local (Me)')}</GridItem> + <GridItem className="theirs">{i18n('Last Committed')}</GridItem> + <GridItem className="resolve"> + <Input + label={i18n('Show Conflicts Only')} + type="checkbox" + value={this.state.conflictsOnly} + onChange={e => this.setState({ conflictsOnly: e })} + /> + </GridItem> + </GridSection> + ); + } + // <Checkbox + // label={i18n('Show Conflicts Only')} + // value={this.state.conflictsOnly} + // checked={this.state.conflictsOnly} + // onChange={checked => this.setState({conflictsOnly: checked})} /> - renderObjects(yours, theirs, fileType, field, id, resolution) { - if (equal(yours, theirs)) { - return; - } - let {conflictsOnly} = this.state; - return ( - <div key={`obj_${fileType}/${field}_${id}`}> - <TextCompare field={field} type={fileType} conflictsOnly={conflictsOnly} yours='' theirs='' isObjName resolution={resolution} /> - <div className='field-objects'> - <div> - {this.getUnion(yours, theirs).map(key => - this.renderField( - key, - {type: `${fileType}/${field}`, id}, - yours && yours[key], - theirs && theirs[key] - ) - )} - </div> - </div> - </div> - ); - } + renderObjects(yours, theirs, fileType, field, id, resolution) { + if (equal(yours, theirs)) { + return; + } + let { conflictsOnly } = this.state; + return ( + <div key={`obj_${fileType}/${field}_${id}`}> + <TextCompare + field={field} + type={fileType} + conflictsOnly={conflictsOnly} + yours="" + theirs="" + isObjName + resolution={resolution} + /> + <div className="field-objects"> + <div> + {this.getUnion(yours, theirs).map(key => + this.renderField( + key, + { type: `${fileType}/${field}`, id }, + yours && yours[key], + theirs && theirs[key] + ) + )} + </div> + </div> + </div> + ); + } - renderList(yours = [], theirs = [], type, field, id, resolution) { - let theirsList = theirs.join(', '); - let yoursList = yours.join(', '); - let {conflictsOnly} = this.state; - return (<TextCompare key={'text_' + id + '_' + field} - field={field} type={type} yours={yoursList} theirs={theirsList} conflictsOnly={conflictsOnly} resolution={resolution} />); - } + renderList(yours = [], theirs = [], type, field, id, resolution) { + let theirsList = theirs.join(', '); + let yoursList = yours.join(', '); + let { conflictsOnly } = this.state; + return ( + <TextCompare + key={'text_' + id + '_' + field} + field={field} + type={type} + yours={yoursList} + theirs={theirsList} + conflictsOnly={conflictsOnly} + resolution={resolution} + /> + ); + } - renderField(field, file, yours, theirs, resolution) { - if (yours) { - if (Array.isArray(yours)) { - return this.renderList(yours, theirs, file.type, field, file.id, resolution); - } - else if (typeof yours === 'object') { - return this.renderObjects(yours, theirs, file.type, field, file.id, resolution); - } - } else if (theirs) { - if (Array.isArray(theirs)) { - return this.renderList(yours, theirs, file.type, field, file.id, resolution); - } - else if (typeof theirs === 'object') { - return this.renderObjects(yours, theirs, file.type, field, file.id, resolution); - } - } - let {conflictsOnly} = this.state; - return (<TextCompare key={'text_' + file.id + '_' + field} resolution={resolution} - field={field} type={file.type} yours={yours} theirs={theirs} conflictsOnly={conflictsOnly} />); - } + renderField(field, file, yours, theirs, resolution) { + if (yours) { + if (Array.isArray(yours)) { + return this.renderList( + yours, + theirs, + file.type, + field, + file.id, + resolution + ); + } else if (typeof yours === 'object') { + return this.renderObjects( + yours, + theirs, + file.type, + field, + file.id, + resolution + ); + } + } else if (theirs) { + if (Array.isArray(theirs)) { + return this.renderList( + yours, + theirs, + file.type, + field, + file.id, + resolution + ); + } else if (typeof theirs === 'object') { + return this.renderObjects( + yours, + theirs, + file.type, + field, + file.id, + resolution + ); + } + } + let { conflictsOnly } = this.state; + return ( + <TextCompare + key={'text_' + file.id + '_' + field} + resolution={resolution} + field={field} + type={file.type} + yours={yours} + theirs={theirs} + conflictsOnly={conflictsOnly} + /> + ); + } - getUnion(yours = {},theirs = {}) { - let yoursKeys = Object.keys(yours); - let theirsKeys = Object.keys(theirs); - let myUn = union(yoursKeys, theirsKeys); - return myUn;//.sort((a, b) => a > b); - } + getUnion(yours = {}, theirs = {}) { + let yoursKeys = Object.keys(yours); + let theirsKeys = Object.keys(theirs); + let myUn = union(yoursKeys, theirsKeys); + return myUn; //.sort((a, b) => a > b); + } - updateCollapseState(conflictId) { - const {fetchConflict, item: {id: itemId, version}, /*conflicts*/} = this.props; - let isCollapsed = this.state.collapsingSections[conflictId]; - // if (!isCollapsed && !(conflicts && conflictId in conflicts)) { - if (!isCollapsed) { - fetchConflict({cid: conflictId, itemId, version}); - } - this.setState({ - collapsingSections: { - ...this.state.collapsingSections, - [conflictId]: !isCollapsed - } - }); - } + updateCollapseState(conflictId) { + const { + fetchConflict, + item: { id: itemId, version } /*conflicts*/ + } = this.props; + let isCollapsed = this.state.collapsingSections[conflictId]; + // if (!isCollapsed && !(conflicts && conflictId in conflicts)) { + if (!isCollapsed) { + fetchConflict({ cid: conflictId, itemId, version }); + } + this.setState({ + collapsingSections: { + ...this.state.collapsingSections, + [conflictId]: !isCollapsed + } + }); + } } export default MergeEditorView; diff --git a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js index b17536f446..5b28c5d7fa 100644 --- a/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js +++ b/openecomp-ui/src/sdc-app/common/modal/ModalContentMapper.js @@ -32,40 +32,40 @@ import Revisions from 'sdc-app/onboarding/revisions/Revisions.js'; import VendorSelector from 'sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsVendorSelector.jsx'; export const modalContentMapper = { - SOFTWARE_PRODUCT_CREATION: 'SOFTWARE_PRODUCT_CREATION', - LICENSE_MODEL_CREATION: 'LICENSE_MODEL_CREATION', - 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', - MANAGE_PERMISSIONS: 'MANAGE_PERMISSIONS', - VERSION_CREATION: 'VERSION_CREATION', - COMMIT_COMMENT: 'COMMIT_COMMENT', - VERSION_TREE: 'VERSION_TREE', - MERGE_EDITOR: 'MERGE_EDITOR', - REVISIONS_LIST: 'REVISIONS_LIST', - VENDOR_SELECTOR: 'VENDOR_SELECTOR' - + SOFTWARE_PRODUCT_CREATION: 'SOFTWARE_PRODUCT_CREATION', + LICENSE_MODEL_CREATION: 'LICENSE_MODEL_CREATION', + 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', + MANAGE_PERMISSIONS: 'MANAGE_PERMISSIONS', + VERSION_CREATION: 'VERSION_CREATION', + COMMIT_COMMENT: 'COMMIT_COMMENT', + VERSION_TREE: 'VERSION_TREE', + MERGE_EDITOR: 'MERGE_EDITOR', + REVISIONS_LIST: 'REVISIONS_LIST', + VENDOR_SELECTOR: 'VENDOR_SELECTOR' }; export const modalContentComponents = { - SUMBIT_ERROR_RESPONSE: SubmitErrorResponse, - SOFTWARE_PRODUCT_CREATION: SoftwareProductCreation, - VERSION_CREATION: VersionPageCreation, - LICENSE_MODEL_CREATION: LicenseModelCreation, - COMPONENT_COMPUTE_FLAVOR_EDITOR: ComputeFlavorEditor, - NIC_EDITOR: SoftwareProductComponentsNICEditor, - NIC_CREATION: NICCreation, - COMPONENT_CREATION: ComponentCreation, - SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR : SoftwareProductComponentImageEditor, - DEPLOYMENT_FLAVOR_EDITOR: SoftwareProductDeploymentEditor, - MANAGE_PERMISSIONS: PermissionsManager, - COMMIT_COMMENT: CommitCommentModal, - VERSION_TREE: Tree, - MERGE_EDITOR: MergeEditor, - REVISIONS_LIST: Revisions, - VENDOR_SELECTOR: VendorSelector + SUMBIT_ERROR_RESPONSE: SubmitErrorResponse, + SOFTWARE_PRODUCT_CREATION: SoftwareProductCreation, + VERSION_CREATION: VersionPageCreation, + LICENSE_MODEL_CREATION: LicenseModelCreation, + COMPONENT_COMPUTE_FLAVOR_EDITOR: ComputeFlavorEditor, + NIC_EDITOR: SoftwareProductComponentsNICEditor, + NIC_CREATION: NICCreation, + COMPONENT_CREATION: ComponentCreation, + SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR: SoftwareProductComponentImageEditor, + DEPLOYMENT_FLAVOR_EDITOR: SoftwareProductDeploymentEditor, + MANAGE_PERMISSIONS: PermissionsManager, + COMMIT_COMMENT: CommitCommentModal, + VERSION_TREE: Tree, + MERGE_EDITOR: MergeEditor, + REVISIONS_LIST: Revisions, + VENDOR_SELECTOR: VendorSelector }; diff --git a/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducer.js b/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducer.js index 916f724b40..6ac6d753d4 100644 --- a/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducer.js +++ b/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducer.js @@ -13,133 +13,185 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './JSONSchemaReducerConstants.js'; +import { actionTypes } from './JSONSchemaReducerConstants.js'; import Validator from 'nfvo-utils/Validator.js'; import JSONSchema from 'nfvo-utils/json/JSONSchema.js'; import JSONPointer from 'nfvo-utils/json/JSONPointer.js'; import forOwn from 'lodash/forOwn.js'; import isArray from 'lodash/isArray.js'; - function flattenData(data, result, pointer = '') { - let newPointer = pointer; - if (typeof data === 'object' && !isArray(data)) { - for (let i in data) { - newPointer = newPointer ? newPointer + '/' + i : i; - flattenData(data[i], result, newPointer); - newPointer = pointer; - } - } else { - result[newPointer] = data; - } + let newPointer = pointer; + if (typeof data === 'object' && !isArray(data)) { + for (let i in data) { + newPointer = newPointer ? newPointer + '/' + i : i; + flattenData(data[i], result, newPointer); + newPointer = pointer; + } + } else { + result[newPointer] = data; + } } -function updateSchemaDataAndValidateReducer (state = {}, action, questionnaireName) { - let genericFieldInfoClone; - switch (action.type) { - case actionTypes.DATA_LOADED: - if (questionnaireName !== action.qName) {return {...state};} - const schema = action.payload.qschema; - let schemaLoader = new JSONSchema(); - schemaLoader.setSchema(schema); - schemaLoader.setSupportedValidationFunctions(Object.keys(Validator.globalValidationFunctions)); - let {genericFieldInfo} = schemaLoader.flattenSchema(); - - let data = action.payload.qdata; - let dataMap = {}; - flattenData(data, dataMap); - - return { - ...state, - qdata: action.payload.qdata, // the original hierarchical data. to be used for submit and save - qgenericFieldInfo : genericFieldInfo, // information about the fields that the view will require and reducer will need, such as validations, enum to use, etc. - dataMap // flattened schema data for ease of use - }; - - case actionTypes.DATA_CHANGED: - let changedData = action.deltaData; - if (questionnaireName !== action.qName) {return {...state};} - - genericFieldInfoClone = {...state.qgenericFieldInfo}; - let qDataClone = {...state.qdata}; - let dataMapClone = {...state.dataMap}; - - forOwn(changedData,(value, key) => { - if (state.qgenericFieldInfo[key]) { - let result = Validator.validate(key, value, state.qgenericFieldInfo[key].validations, state, action.customValidations); - genericFieldInfoClone[key] = {...genericFieldInfoClone[key], isValid: result.isValid, errorText: result.errorText}; - qDataClone = JSONPointer.setValue(state.qdata, '/' + key, value); - dataMapClone[key] = value; - } - }); - - return { - ...state, - qdata: qDataClone, - dataMap: dataMapClone, - qgenericFieldInfo: genericFieldInfoClone - }; - - case actionTypes.VALIDATE_DATA: - let specificFields = action.data; - if (questionnaireName !== action.qName) {return {...state};} - genericFieldInfoClone = {...state.qgenericFieldInfo}; - forOwn(specificFields,(value, key) => { - let result = Validator.validate(key, value, state.qgenericFieldInfo[key].validations, state, action.customValidations); - genericFieldInfoClone[key] = {...genericFieldInfoClone[key], isValid: result.isValid, errorText: result.errorText}; - }); - return { - ...state, - formReady: null, - qgenericFieldInfo: genericFieldInfoClone - }; - - case actionTypes.VALIDATE_FORM: - if (questionnaireName !== action.qName) {return {...state};} - genericFieldInfoClone = {...state.qgenericFieldInfo}; - let formReady = true; - forOwn(state.qgenericFieldInfo,(value, key) => { - let val = state.dataMap[key] ? state.dataMap[key] : ''; - let result = Validator.validate(key, val, state.qgenericFieldInfo[key].validations, state, action.customValidations); - genericFieldInfoClone[key] = {...genericFieldInfoClone[key], isValid: result.isValid, errorText: result.errorText}; - if (!result.isValid) { - formReady = false; - } - }); - return { - ...state, - formReady, - qgenericFieldInfo: genericFieldInfoClone - }; - - default: - return state; - } -}; +function updateSchemaDataAndValidateReducer( + state = {}, + action, + questionnaireName +) { + let genericFieldInfoClone; + switch (action.type) { + case actionTypes.DATA_LOADED: + if (questionnaireName !== action.qName) { + return { ...state }; + } + const schema = action.payload.qschema; + let schemaLoader = new JSONSchema(); + schemaLoader.setSchema(schema); + schemaLoader.setSupportedValidationFunctions( + Object.keys(Validator.globalValidationFunctions) + ); + let { genericFieldInfo } = schemaLoader.flattenSchema(); + + let data = action.payload.qdata; + let dataMap = {}; + flattenData(data, dataMap); + + return { + ...state, + qdata: action.payload.qdata, // the original hierarchical data. to be used for submit and save + qgenericFieldInfo: genericFieldInfo, // information about the fields that the view will require and reducer will need, such as validations, enum to use, etc. + dataMap // flattened schema data for ease of use + }; + + case actionTypes.DATA_CHANGED: + let changedData = action.deltaData; + if (questionnaireName !== action.qName) { + return { ...state }; + } + + genericFieldInfoClone = { ...state.qgenericFieldInfo }; + let qDataClone = { ...state.qdata }; + let dataMapClone = { ...state.dataMap }; + + forOwn(changedData, (value, key) => { + if (state.qgenericFieldInfo[key]) { + let result = Validator.validate( + key, + value, + state.qgenericFieldInfo[key].validations, + state, + action.customValidations + ); + genericFieldInfoClone[key] = { + ...genericFieldInfoClone[key], + isValid: result.isValid, + errorText: result.errorText + }; + qDataClone = JSONPointer.setValue( + state.qdata, + '/' + key, + value + ); + dataMapClone[key] = value; + } + }); + + return { + ...state, + qdata: qDataClone, + dataMap: dataMapClone, + qgenericFieldInfo: genericFieldInfoClone + }; + + case actionTypes.VALIDATE_DATA: + let specificFields = action.data; + if (questionnaireName !== action.qName) { + return { ...state }; + } + genericFieldInfoClone = { ...state.qgenericFieldInfo }; + forOwn(specificFields, (value, key) => { + let result = Validator.validate( + key, + value, + state.qgenericFieldInfo[key].validations, + state, + action.customValidations + ); + genericFieldInfoClone[key] = { + ...genericFieldInfoClone[key], + isValid: result.isValid, + errorText: result.errorText + }; + }); + return { + ...state, + formReady: null, + qgenericFieldInfo: genericFieldInfoClone + }; + + case actionTypes.VALIDATE_FORM: + if (questionnaireName !== action.qName) { + return { ...state }; + } + genericFieldInfoClone = { ...state.qgenericFieldInfo }; + let formReady = true; + forOwn(state.qgenericFieldInfo, (value, key) => { + let val = state.dataMap[key] ? state.dataMap[key] : ''; + let result = Validator.validate( + key, + val, + state.qgenericFieldInfo[key].validations, + state, + action.customValidations + ); + genericFieldInfoClone[key] = { + ...genericFieldInfoClone[key], + isValid: result.isValid, + errorText: result.errorText + }; + if (!result.isValid) { + formReady = false; + } + }); + return { + ...state, + formReady, + qgenericFieldInfo: genericFieldInfoClone + }; + + default: + return state; + } +} export function createJSONSchemaReducer(questionnaireName) { - return (state = {}, action) => { - return updateSchemaDataAndValidateReducer(state, action, questionnaireName); - }; -}; - -export function createComposedJSONSchemaReducer(questionnaireName, additionalActionsReducer) { - return (state = {}, action) => { - if(action.type === actionTypes.VALIDATE_DATA || - action.type === actionTypes.VALIDATE_FORM || - action.type === actionTypes.DATA_CHANGED || - action.type === actionTypes.DATA_LOADED - ) { - return updateSchemaDataAndValidateReducer(state, action, questionnaireName); - } else { - return additionalActionsReducer(state, action); - } - }; -}; - - - - - - + return (state = {}, action) => { + return updateSchemaDataAndValidateReducer( + state, + action, + questionnaireName + ); + }; +} +export function createComposedJSONSchemaReducer( + questionnaireName, + additionalActionsReducer +) { + return (state = {}, action) => { + if ( + action.type === actionTypes.VALIDATE_DATA || + action.type === actionTypes.VALIDATE_FORM || + action.type === actionTypes.DATA_CHANGED || + action.type === actionTypes.DATA_LOADED + ) { + return updateSchemaDataAndValidateReducer( + state, + action, + questionnaireName + ); + } else { + return additionalActionsReducer(state, action); + } + }; +} diff --git a/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducerConstants.js b/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducerConstants.js index 6007b878dd..439613d949 100644 --- a/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducerConstants.js +++ b/openecomp-ui/src/sdc-app/common/reducers/JSONSchemaReducerConstants.js @@ -16,8 +16,8 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - DATA_LOADED: null, - DATA_CHANGED: null, - VALIDATE_FORM: null, - VALIDATE_DATA: null + DATA_LOADED: null, + DATA_CHANGED: null, + VALIDATE_FORM: null, + VALIDATE_DATA: null }); diff --git a/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducer.js b/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducer.js index 49f1e3d415..30497704b4 100644 --- a/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducer.js +++ b/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducer.js @@ -13,89 +13,135 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './PlainDataReducerConstants.js'; +import { actionTypes } from './PlainDataReducerConstants.js'; import Validator from 'nfvo-utils/Validator.js'; import forOwn from 'lodash/forOwn.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; function updateDataAndValidateReducer(state = {}, action) { - let genericFieldInfoCopy; - switch (action.type) { - case actionTypes.DATA_CHANGED: - let changed = action.deltaData; - if (!action.formName || (state.formName !== action.formName)) {return {...state};} - genericFieldInfoCopy = {...state.genericFieldInfo}; - forOwn(changed,(value, key) => { - if (state.genericFieldInfo[key]) { - let result = Validator.validate(key, value, state.genericFieldInfo[key].validations, state, action.customValidations); - genericFieldInfoCopy[key] = {...genericFieldInfoCopy[key], isValid: result.isValid, errorText: result.errorText}; - } - }); - return { - ...state, - formReady: null, - data: { - ...state.data, - ...action.deltaData - }, - genericFieldInfo: genericFieldInfoCopy - }; - case actionTypes.VALIDATE_FORM: - if (!action.formName || (state.formName !== action.formName)) {return {...state};} - genericFieldInfoCopy = {...state.genericFieldInfo}; - let formReady = true; - forOwn(state.genericFieldInfo,(value, key) => { - let val = state.data && state.data[key] ? state.data[key] : ''; - let result = Validator.validate(key, val, state.genericFieldInfo[key].validations, state, {}); - if(val.choice !== undefined) { - result = Validator.validate(key, val.choice, state.genericFieldInfo[key].validations, state, {}); - } - if(val.choice !== undefined && val.choice === optionInputOther.OTHER) { - result = Validator.validate(key, val.other, state.genericFieldInfo[key].validations, state, {}); - } - genericFieldInfoCopy[key] = {...genericFieldInfoCopy[key], isValid: result.isValid, errorText: result.errorText}; - if (!result.isValid) { - formReady = false; - } - }); - return { - ...state, - formReady, - genericFieldInfo: genericFieldInfoCopy - }; - case actionTypes.VALIDATE_DATA: - let specificFields = action.data; - if (!action.formName || (state.formName !== action.formName)) {return {...state};} - genericFieldInfoCopy = {...state.genericFieldInfo}; - forOwn(specificFields,(value, key) => { - let result = Validator.validate(key, value, state.genericFieldInfo[key].validations, state, action.customValidations); - genericFieldInfoCopy[key] = {...genericFieldInfoCopy[key], isValid: result.isValid, errorText: result.errorText}; - }); - return { - ...state, - formReady: null, - genericFieldInfo: genericFieldInfoCopy - }; - default: - return state; - } -}; + let genericFieldInfoCopy; + switch (action.type) { + case actionTypes.DATA_CHANGED: + let changed = action.deltaData; + if (!action.formName || state.formName !== action.formName) { + return { ...state }; + } + genericFieldInfoCopy = { ...state.genericFieldInfo }; + forOwn(changed, (value, key) => { + if (state.genericFieldInfo[key]) { + let result = Validator.validate( + key, + value, + state.genericFieldInfo[key].validations, + state, + action.customValidations + ); + genericFieldInfoCopy[key] = { + ...genericFieldInfoCopy[key], + isValid: result.isValid, + errorText: result.errorText + }; + } + }); + return { + ...state, + formReady: null, + data: { + ...state.data, + ...action.deltaData + }, + genericFieldInfo: genericFieldInfoCopy + }; + case actionTypes.VALIDATE_FORM: + if (!action.formName || state.formName !== action.formName) { + return { ...state }; + } + genericFieldInfoCopy = { ...state.genericFieldInfo }; + let formReady = true; + forOwn(state.genericFieldInfo, (value, key) => { + let val = state.data && state.data[key] ? state.data[key] : ''; + let result = Validator.validate( + key, + val, + state.genericFieldInfo[key].validations, + state, + {} + ); + if (val.choice !== undefined) { + result = Validator.validate( + key, + val.choice, + state.genericFieldInfo[key].validations, + state, + {} + ); + } + if ( + val.choice !== undefined && + val.choice === optionInputOther.OTHER + ) { + result = Validator.validate( + key, + val.other, + state.genericFieldInfo[key].validations, + state, + {} + ); + } + genericFieldInfoCopy[key] = { + ...genericFieldInfoCopy[key], + isValid: result.isValid, + errorText: result.errorText + }; + if (!result.isValid) { + formReady = false; + } + }); + return { + ...state, + formReady, + genericFieldInfo: genericFieldInfoCopy + }; + case actionTypes.VALIDATE_DATA: + let specificFields = action.data; + if (!action.formName || state.formName !== action.formName) { + return { ...state }; + } + genericFieldInfoCopy = { ...state.genericFieldInfo }; + forOwn(specificFields, (value, key) => { + let result = Validator.validate( + key, + value, + state.genericFieldInfo[key].validations, + state, + action.customValidations + ); + genericFieldInfoCopy[key] = { + ...genericFieldInfoCopy[key], + isValid: result.isValid, + errorText: result.errorText + }; + }); + return { + ...state, + formReady: null, + genericFieldInfo: genericFieldInfoCopy + }; + default: + return state; + } +} export function createPlainDataReducer(loadReducer) { - return (state = {}, action) => { - if(action.type === actionTypes.VALIDATE_DATA || - action.type === actionTypes.VALIDATE_FORM || - action.type === actionTypes.DATA_CHANGED - ) { - return updateDataAndValidateReducer(state, action); - } else { - return loadReducer(state, action); - } - }; -}; - - - - - - + return (state = {}, action) => { + if ( + action.type === actionTypes.VALIDATE_DATA || + action.type === actionTypes.VALIDATE_FORM || + action.type === actionTypes.DATA_CHANGED + ) { + return updateDataAndValidateReducer(state, action); + } else { + return loadReducer(state, action); + } + }; +} diff --git a/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducerConstants.js b/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducerConstants.js index 135361dd20..8c38483267 100644 --- a/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducerConstants.js +++ b/openecomp-ui/src/sdc-app/common/reducers/PlainDataReducerConstants.js @@ -16,7 +16,7 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - DATA_CHANGED: null, - VALIDATE_FORM: null, - VALIDATE_DATA: null + DATA_CHANGED: null, + VALIDATE_FORM: null, + VALIDATE_DATA: null }); diff --git a/openecomp-ui/src/sdc-app/config/Configuration.js b/openecomp-ui/src/sdc-app/config/Configuration.js index 8444e3fa61..b450d47352 100644 --- a/openecomp-ui/src/sdc-app/config/Configuration.js +++ b/openecomp-ui/src/sdc-app/config/Configuration.js @@ -16,47 +16,55 @@ import configData from './config.json'; class Configuration { + get(key) { + return configData[key]; + } - get(key) { - return configData[key]; - } + set(key, value) { + var prev = configData[key]; + configData[key] = value; + return prev; + } - set(key, value) { - var prev = configData[key]; - configData[key] = value; - return prev; - } + setCatalogApiRoot(CatalogApiRoot) { + let restCatalogPrefix = CatalogApiRoot, + restPrefix = CatalogApiRoot.replace( + /\/feProxy\b[^:]*$/, + '/feProxy/onboarding-api' + ); - setCatalogApiRoot(CatalogApiRoot) { - let restCatalogPrefix = CatalogApiRoot, - restPrefix = CatalogApiRoot.replace(/\/feProxy\b[^:]*$/, '/feProxy/onboarding-api'); + this.set('restPrefix', restPrefix); + this.set('restCatalogPrefix', restCatalogPrefix); + } - this.set('restPrefix', restPrefix); - this.set('restCatalogPrefix', restCatalogPrefix); - } + setCatalogApiHeaders(CatalogApiHeaders) { + this.set('CatalogApiHeaders', CatalogApiHeaders); - setCatalogApiHeaders(CatalogApiHeaders) { - this.set('CatalogApiHeaders', CatalogApiHeaders); - - let {userId: {value: UserID} = {}} = CatalogApiHeaders; - this.set('UserID', UserID); - } + let { userId: { value: UserID } = {} } = CatalogApiHeaders; + this.set('UserID', UserID); + } } const configuration = new Configuration(); (function setDefaultRestPrefixes(configuration) { - configuration.set('restPrefix', configuration.get('defaultRestPrefix')); - configuration.set('restCatalogPrefix', configuration.get('defaultRestCatalogPrefix')); - configuration.set('appContextPath', configuration.get('appContextPath')); + configuration.set('restPrefix', configuration.get('defaultRestPrefix')); + configuration.set( + 'restCatalogPrefix', + configuration.get('defaultRestCatalogPrefix') + ); + configuration.set('appContextPath', configuration.get('appContextPath')); })(configuration); (function setDefaultWebsocketConfig(configuration) { - let websocketPort = configuration.get('defaultWebsocketPort'); - if (DEBUG) { - websocketPort = configuration.get('defaultDebugWebsocketPort'); - } - configuration.set('websocketPort', websocketPort); - configuration.set('websocketPath', configuration.get('defaultWebsocketPath')); + let websocketPort = configuration.get('defaultWebsocketPort'); + if (DEBUG) { + websocketPort = configuration.get('defaultDebugWebsocketPort'); + } + configuration.set('websocketPort', websocketPort); + configuration.set( + 'websocketPath', + configuration.get('defaultWebsocketPath') + ); })(configuration); export default configuration; diff --git a/openecomp-ui/src/sdc-app/features/FeaturesActionHelper.js b/openecomp-ui/src/sdc-app/features/FeaturesActionHelper.js index 5bb911d090..5ab5480167 100644 --- a/openecomp-ui/src/sdc-app/features/FeaturesActionHelper.js +++ b/openecomp-ui/src/sdc-app/features/FeaturesActionHelper.js @@ -15,26 +15,30 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './FeaturesConstants.js'; - +import { actionTypes } from './FeaturesConstants.js'; function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/togglz`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/togglz`; } function fetchList() { - return RestAPIUtil.fetch(baseUrl()); + return RestAPIUtil.fetch(baseUrl()); } export default { - getFeaturesList(dispatch) { - return fetchList().then(response => { - dispatch({ - type: actionTypes.FEATURES_LIST_LOADED, - features: response.features - }); - }).catch(() => console.error('An exception occured while trying to fetch the toggleZ features.') ); - } + getFeaturesList(dispatch) { + return fetchList() + .then(response => { + dispatch({ + type: actionTypes.FEATURES_LIST_LOADED, + features: response.features + }); + }) + .catch(() => + console.error( + 'An exception occured while trying to fetch the toggleZ features.' + ) + ); + } }; - diff --git a/openecomp-ui/src/sdc-app/features/FeaturesConstants.js b/openecomp-ui/src/sdc-app/features/FeaturesConstants.js index f962d243d5..314e86ad3d 100644 --- a/openecomp-ui/src/sdc-app/features/FeaturesConstants.js +++ b/openecomp-ui/src/sdc-app/features/FeaturesConstants.js @@ -16,10 +16,10 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FEATURES_LIST_LOADED: null + FEATURES_LIST_LOADED: null }); export const featureToggleNames = { - ARCHIVE_ITEM: 'ARCHIVE_ITEM', - FILTER: 'FILTER' -};
\ No newline at end of file + ARCHIVE_ITEM: 'ARCHIVE_ITEM', + FILTER: 'FILTER' +}; diff --git a/openecomp-ui/src/sdc-app/features/FeaturesReducer.js b/openecomp-ui/src/sdc-app/features/FeaturesReducer.js index d7c8624d54..064afe992d 100644 --- a/openecomp-ui/src/sdc-app/features/FeaturesReducer.js +++ b/openecomp-ui/src/sdc-app/features/FeaturesReducer.js @@ -14,13 +14,13 @@ * permissions and limitations under the License. */ - import {actionTypes} from './FeaturesConstants.js'; +import { actionTypes } from './FeaturesConstants.js'; - export default (state = [], action) => { - switch (action.type) { - case actionTypes.FEATURES_LIST_LOADED: - return [...action.features]; - default: - return state; - } - };
\ No newline at end of file +export default (state = [], action) => { + switch (action.type) { + case actionTypes.FEATURES_LIST_LOADED: + return [...action.features]; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/features/featureToggle.js b/openecomp-ui/src/sdc-app/features/featureToggle.js index 5e0df1448f..d33c76e523 100644 --- a/openecomp-ui/src/sdc-app/features/featureToggle.js +++ b/openecomp-ui/src/sdc-app/features/featureToggle.js @@ -14,47 +14,48 @@ * permissions and limitations under the License. */ - - /** +/** * Feature toggling decorator - * usage: - * + * usage: + * * @featureToggle('FeatureName') * class Example extends React.Component { * render() { * return (<div>test feature</div>); * } * } - * - * OR - * + * + * OR + * * const TestFeature = () => (<div>test feature</div>) * export default featureToggle('FeatureName')(TestFeature) - * + * */ import React from 'react'; import PropTypes from 'prop-types'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; + +export const FeatureComponent = props => { + const { features = [], featureName, InnerComponent, ...otherProps } = props; + const AComp = InnerComponent.AComp ? InnerComponent.AComp : InnerComponent; -export const FeatureComponent = (props) => { - const {features = [], featureName, InnerComponent, ...otherProps} = props; - const AComp = InnerComponent.AComp ? InnerComponent.AComp : InnerComponent; - - return !!features.find(el => el.name === featureName && el.active) ? - <AComp {...otherProps}/> - : InnerComponent.BComp ? <InnerComponent.BComp {...otherProps}/> : null; + return !!features.find(el => el.name === featureName && el.active) ? ( + <AComp {...otherProps} /> + ) : InnerComponent.BComp ? ( + <InnerComponent.BComp {...otherProps} /> + ) : null; }; FeatureComponent.propTypes = { - features: PropTypes.array, - featureName: PropTypes.string.isRequired + features: PropTypes.array, + featureName: PropTypes.string.isRequired }; - export default function featureToggle(featureName) { - return (InnerComponent) => { - return connect(({features}) => {return {features, featureName, InnerComponent};})(FeatureComponent); - }; + return InnerComponent => { + return connect(({ features }) => { + return { features, featureName, InnerComponent }; + })(FeatureComponent); + }; } - diff --git a/openecomp-ui/src/sdc-app/features/restToggle.js b/openecomp-ui/src/sdc-app/features/restToggle.js index c90521dd7e..505dace4e7 100644 --- a/openecomp-ui/src/sdc-app/features/restToggle.js +++ b/openecomp-ui/src/sdc-app/features/restToggle.js @@ -16,9 +16,9 @@ import store from 'sdc-app/AppStore.js'; - -export default ({featureName, restFunction, mockResult}) => { - const {features} = store.getState(); - return !!features.find(el => el.name === featureName && el.active) ? - restFunction() : Promise.resolve(mockResult); -};
\ No newline at end of file +export default ({ featureName, restFunction, mockResult }) => { + const { features } = store.getState(); + return !!features.find(el => el.name === featureName && el.active) + ? restFunction() + : Promise.resolve(mockResult); +}; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsActions.js b/openecomp-ui/src/sdc-app/flows/FlowsActions.js index 61a419b314..9fb65f37d4 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsActions.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsActions.js @@ -15,171 +15,204 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes, enums} from './FlowsConstants.js'; +import { actionTypes, enums } from './FlowsConstants.js'; import SequenceDiagramModelHelper from './SequenceDiagramModelHelper.js'; - function baseUrl(serviceId, artifactId = '') { - const restCatalogPrefix = Configuration.get('restCatalogPrefix'); - return `${restCatalogPrefix}/v1/catalog/services/${serviceId}/artifacts/${artifactId}`; + const restCatalogPrefix = Configuration.get('restCatalogPrefix'); + return `${restCatalogPrefix}/v1/catalog/services/${serviceId}/artifacts/${artifactId}`; } function encodeDataToBase64(dataAsString) { - return window.btoa(dataAsString); + return window.btoa(dataAsString); } function decodeDataToBase64(encodedData) { - return window.atob(encodedData); + return window.atob(encodedData); } function encodeContent(flowData) { - let data = { - VERSION: { - major: 1, - minor: 0 - }, - description: flowData.description, - sequenceDiagramModel: flowData.sequenceDiagramModel - }; - - return encodeDataToBase64(JSON.stringify(data)); + let data = { + VERSION: { + major: 1, + minor: 0 + }, + description: flowData.description, + sequenceDiagramModel: flowData.sequenceDiagramModel + }; + + return encodeDataToBase64(JSON.stringify(data)); } function decodeContent(base64Contents) { - let description, sequenceDiagramModel; - let payload = JSON.parse(decodeDataToBase64(base64Contents)); - - if (payload.VERSION === undefined) { - description = payload.description || 'Please, provide description...'; - sequenceDiagramModel = payload.data || payload; - sequenceDiagramModel = sequenceDiagramModel.model || sequenceDiagramModel; - - } - else if (payload.VERSION.major === 1) { - description = payload.description; - sequenceDiagramModel = payload.sequenceDiagramModel; - } - - return { - description, - sequenceDiagramModel - }; + let description, sequenceDiagramModel; + let payload = JSON.parse(decodeDataToBase64(base64Contents)); + + if (payload.VERSION === undefined) { + description = payload.description || 'Please, provide description...'; + sequenceDiagramModel = payload.data || payload; + sequenceDiagramModel = + sequenceDiagramModel.model || sequenceDiagramModel; + } else if (payload.VERSION.major === 1) { + description = payload.description; + sequenceDiagramModel = payload.sequenceDiagramModel; + } + + return { + description, + sequenceDiagramModel + }; } function createOrUpdate(flowData) { - let createOrUpdateRequest = { - payloadData: encodeContent(flowData), - artifactLabel: flowData.artifactLabel || flowData.artifactName, - artifactName: flowData.artifactName, - artifactType: flowData.artifactType, - artifactGroupType: enums.INFORMATIONAL, - description: flowData.description - }; - - return RestAPIUtil.post( - baseUrl(flowData.serviceID, flowData.uniqueId), - createOrUpdateRequest, - {md5: true} - ); + let createOrUpdateRequest = { + payloadData: encodeContent(flowData), + artifactLabel: flowData.artifactLabel || flowData.artifactName, + artifactName: flowData.artifactName, + artifactType: flowData.artifactType, + artifactGroupType: enums.INFORMATIONAL, + description: flowData.description + }; + + return RestAPIUtil.post( + baseUrl(flowData.serviceID, flowData.uniqueId), + createOrUpdateRequest, + { md5: true } + ); } const FlowsActions = Object.freeze({ - - fetchFlowArtifacts(dispatch, {artifacts, diagramType, participants, serviceID, readonly}) { - let results = []; - if (!Object.keys(artifacts).length) { - dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType, readonly}); - if (!readonly) { - FlowsActions.openFlowDetailsEditor(dispatch); - } - } - else { - Object.keys(artifacts).forEach(artifact => results.push({ - artifactType: diagramType, - participants, - serviceID, - ...artifacts[artifact] - })); - dispatch({type: actionTypes.FLOW_LIST_LOADED, results, participants, serviceID, diagramType, readonly}); - } - }, - - fetchArtifact(dispatch, {flow}){ - let {serviceID, uniqueId, participants} = flow; - return RestAPIUtil.fetch(baseUrl(serviceID, uniqueId)).then(response => { - - let {artifactName, base64Contents} = response; - let {sequenceDiagramModel, ...other} = decodeContent(base64Contents); - - if (!sequenceDiagramModel) { - sequenceDiagramModel = SequenceDiagramModelHelper.createModel({ - id: uniqueId, - name: artifactName, - lifelines: participants - }); - } - else { - sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(sequenceDiagramModel, { - name: artifactName, - lifelines: participants - }); - } - - flow = { - ...flow, - ...other, - uniqueId, - artifactName, - sequenceDiagramModel - }; - - dispatch({type: actionTypes.ARTIFACT_LOADED, flow}); - FlowsActions.openFlowDiagramEditor(dispatch, {flow}); - }); - }, - - createOrUpdateFlow(dispatch, {flow}, isNew) { - if (!isNew && flow.sequenceDiagramModel) { - flow.sequenceDiagramModel = SequenceDiagramModelHelper.updateModel(flow.sequenceDiagramModel, { - name: flow.artifactName - }); - } - return createOrUpdate(flow).then(response => { - let {uniqueId, artifactLabel} = response; - flow = {...flow, uniqueId, artifactLabel}; - if (isNew) { - flow.sequenceDiagramModel = SequenceDiagramModelHelper.createModel({id: uniqueId, name: flow.artifactName}); - } - dispatch({type: actionTypes.ADD_OR_UPDATE_FLOW, flow}); - }); - }, - - deleteFlow(dispatch, {flow}) { - return RestAPIUtil.destroy(baseUrl(flow.serviceID, flow.uniqueId)).then(() => dispatch({ - type: actionTypes.DELETE_FLOW, - flow - })); - }, - - openFlowDetailsEditor(dispatch, flow) { - dispatch({type: actionTypes.OPEN_FLOW_DETAILS_EDITOR, flow}); - }, - - closeFlowDetailsEditor(dispatch) { - dispatch({type: actionTypes.CLOSE_FLOW_DETAILS_EDITOR}); - }, - - openFlowDiagramEditor(dispatch, {flow}) { - dispatch({type: actionTypes.OPEN_FLOW_DIAGRAM_EDITOR, flow}); - }, - - closeFlowDiagramEditor(dispatch) { - dispatch({type: actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR}); - }, - - reset(dispatch) { - dispatch({type: actionTypes.RESET}); - } + fetchFlowArtifacts( + dispatch, + { artifacts, diagramType, participants, serviceID, readonly } + ) { + let results = []; + if (!Object.keys(artifacts).length) { + dispatch({ + type: actionTypes.FLOW_LIST_LOADED, + results, + participants, + serviceID, + diagramType, + readonly + }); + if (!readonly) { + FlowsActions.openFlowDetailsEditor(dispatch); + } + } else { + Object.keys(artifacts).forEach(artifact => + results.push({ + artifactType: diagramType, + participants, + serviceID, + ...artifacts[artifact] + }) + ); + dispatch({ + type: actionTypes.FLOW_LIST_LOADED, + results, + participants, + serviceID, + diagramType, + readonly + }); + } + }, + + fetchArtifact(dispatch, { flow }) { + let { serviceID, uniqueId, participants } = flow; + return RestAPIUtil.fetch(baseUrl(serviceID, uniqueId)).then( + response => { + let { artifactName, base64Contents } = response; + let { sequenceDiagramModel, ...other } = decodeContent( + base64Contents + ); + + if (!sequenceDiagramModel) { + sequenceDiagramModel = SequenceDiagramModelHelper.createModel( + { + id: uniqueId, + name: artifactName, + lifelines: participants + } + ); + } else { + sequenceDiagramModel = SequenceDiagramModelHelper.updateModel( + sequenceDiagramModel, + { + name: artifactName, + lifelines: participants + } + ); + } + + flow = { + ...flow, + ...other, + uniqueId, + artifactName, + sequenceDiagramModel + }; + + dispatch({ type: actionTypes.ARTIFACT_LOADED, flow }); + FlowsActions.openFlowDiagramEditor(dispatch, { flow }); + } + ); + }, + + createOrUpdateFlow(dispatch, { flow }, isNew) { + if (!isNew && flow.sequenceDiagramModel) { + flow.sequenceDiagramModel = SequenceDiagramModelHelper.updateModel( + flow.sequenceDiagramModel, + { + name: flow.artifactName + } + ); + } + return createOrUpdate(flow).then(response => { + let { uniqueId, artifactLabel } = response; + flow = { ...flow, uniqueId, artifactLabel }; + if (isNew) { + flow.sequenceDiagramModel = SequenceDiagramModelHelper.createModel( + { + id: uniqueId, + name: flow.artifactName + } + ); + } + dispatch({ type: actionTypes.ADD_OR_UPDATE_FLOW, flow }); + }); + }, + + deleteFlow(dispatch, { flow }) { + return RestAPIUtil.destroy(baseUrl(flow.serviceID, flow.uniqueId)).then( + () => + dispatch({ + type: actionTypes.DELETE_FLOW, + flow + }) + ); + }, + + openFlowDetailsEditor(dispatch, flow) { + dispatch({ type: actionTypes.OPEN_FLOW_DETAILS_EDITOR, flow }); + }, + + closeFlowDetailsEditor(dispatch) { + dispatch({ type: actionTypes.CLOSE_FLOW_DETAILS_EDITOR }); + }, + + openFlowDiagramEditor(dispatch, { flow }) { + dispatch({ type: actionTypes.OPEN_FLOW_DIAGRAM_EDITOR, flow }); + }, + + closeFlowDiagramEditor(dispatch) { + dispatch({ type: actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR }); + }, + + reset(dispatch) { + dispatch({ type: actionTypes.RESET }); + } }); export default FlowsActions; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsConstants.js b/openecomp-ui/src/sdc-app/flows/FlowsConstants.js index 2b3d86bae2..4dcd840ff3 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsConstants.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsConstants.js @@ -16,30 +16,28 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ + OPEN_FLOW_DETAILS_EDITOR: null, + CLOSE_FLOW_DETAILS_EDITOR: null, - OPEN_FLOW_DETAILS_EDITOR: null, - CLOSE_FLOW_DETAILS_EDITOR: null, + OPEN_FLOW_DIAGRAM_EDITOR: null, + CLOSE_FLOW_DIAGRAM_EDITOR: null, - OPEN_FLOW_DIAGRAM_EDITOR: null, - CLOSE_FLOW_DIAGRAM_EDITOR: null, + FLOW_LIST_LOADED: null, + ADD_OR_UPDATE_FLOW: null, + ARTIFACT_LOADED: null, + DELETE_FLOW: null, - FLOW_LIST_LOADED: null, - ADD_OR_UPDATE_FLOW: null, - ARTIFACT_LOADED: null, - DELETE_FLOW: null, - - CURRENT_FLOW_DATA_CHANGED: null, - - RESET: null + CURRENT_FLOW_DATA_CHANGED: null, + RESET: null }); export const enums = { - WORKFLOW: 'WORKFLOW', - NETWORK: 'NETWORK_CALL_FLOW', - INFORMATIONAL: 'INFORMATIONAL', - INSTANTIATION_FLOWS: 'instantiationflows', - MESSAGE_FLOWS: 'messageflows' + WORKFLOW: 'WORKFLOW', + NETWORK: 'NETWORK_CALL_FLOW', + INFORMATIONAL: 'INFORMATIONAL', + INSTANTIATION_FLOWS: 'instantiationflows', + MESSAGE_FLOWS: 'messageflows' }; export const FLOWS_EDITOR_FORM = 'FLOWS_FORM'; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js b/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js index f9585f985f..b45a9fc54e 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsEditorModal.js @@ -13,44 +13,57 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import FlowsEditorModalView from './FlowsEditorModalView.jsx'; import FlowsActions from './FlowsActions.js'; -import {FLOWS_EDITOR_FORM} from './FlowsConstants.js'; +import { FLOWS_EDITOR_FORM } from './FlowsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -export const mapStateToProps = ({flows}) => { +export const mapStateToProps = ({ flows }) => { + let { + data = { artifactName: '', description: '' }, + serviceID, + diagramType, + flowParticipants, + genericFieldInfo, + formReady + } = flows; + if (!data.serviceID) { + data.serviceID = serviceID; + } + if (!data.artifactType) { + data.artifactType = diagramType; + } + if (!data.participants) { + data.participants = flowParticipants; + } + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let {data = {artifactName: '', description: ''}, serviceID, diagramType, flowParticipants, genericFieldInfo, formReady} = flows; - if(!data.serviceID){ - data.serviceID = serviceID; - } - if(!data.artifactType){ - data.artifactType = diagramType; - } - if(!data.participants){ - data.participants = flowParticipants; - } - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - - return { - currentFlow: data, - genericFieldInfo, - isFormValid, - formReady - }; + return { + currentFlow: data, + genericFieldInfo, + isFormValid, + formReady + }; }; -const mapActionsToProps = (dispatch, {isNewArtifact}) => { - return { - onSubmit: flow => { - FlowsActions.closeFlowDetailsEditor(dispatch); - FlowsActions.createOrUpdateFlow(dispatch, {flow}, isNewArtifact); - }, - onCancel: () => FlowsActions.closeFlowDetailsEditor(dispatch), - onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: FLOWS_EDITOR_FORM}), - onValidateForm: () => ValidationHelper.validateForm(dispatch, FLOWS_EDITOR_FORM) - }; +const mapActionsToProps = (dispatch, { isNewArtifact }) => { + return { + onSubmit: flow => { + FlowsActions.closeFlowDetailsEditor(dispatch); + FlowsActions.createOrUpdateFlow(dispatch, { flow }, isNewArtifact); + }, + onCancel: () => FlowsActions.closeFlowDetailsEditor(dispatch), + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: FLOWS_EDITOR_FORM + }), + onValidateForm: () => + ValidationHelper.validateForm(dispatch, FLOWS_EDITOR_FORM) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(FlowsEditorModalView); +export default connect(mapStateToProps, mapActionsToProps)( + FlowsEditorModalView +); diff --git a/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx b/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx index 1250a0b58e..8c805cca9c 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx +++ b/openecomp-ui/src/sdc-app/flows/FlowsEditorModalView.jsx @@ -13,52 +13,73 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } 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'; class FlowsEditorModalView extends Component { + render() { + let { + onCancel, + onDataChanged, + currentFlow, + genericFieldInfo, + formReady, + isFormValid, + onValidateForm + } = this.props; + let { artifactName, description } = currentFlow; + return ( + <div> + {genericFieldInfo && ( + <Form + onSubmit={() => this.onSaveClicked()} + onReset={onCancel} + formReady={formReady} + isValid={isFormValid} + onValidateForm={() => onValidateForm()}> + <Input + type="text" + name="name" + label={i18n('Name')} + isValid={genericFieldInfo['artifactName'].isValid} + errorText={ + genericFieldInfo['artifactName'].errorText + } + isRequired={true} + value={artifactName} + onChange={artifactName => + onDataChanged({ artifactName }) + } + /> + <Input + type="textarea" + name="description" + label={i18n('Description')} + isValid={genericFieldInfo['description'].isValid} + errorText={ + genericFieldInfo['description'].errorText + } + isRequired={true} + value={description} + overlayPos="bottom" + onChange={description => + onDataChanged({ description }) + } + /> + </Form> + )} + </div> + ); + } - render() { - let {onCancel, onDataChanged, currentFlow, genericFieldInfo, formReady, isFormValid, onValidateForm} = this.props; - let {artifactName, description} = currentFlow; - return ( - <div> - {genericFieldInfo && <Form - onSubmit={() => this.onSaveClicked()} - onReset={onCancel} formReady={formReady} isValid={isFormValid} onValidateForm={() => onValidateForm()} > - <Input - type='text' - name='name' - label={i18n('Name')} - isValid={genericFieldInfo['artifactName'].isValid} - errorText={genericFieldInfo['artifactName'].errorText} - isRequired={true} - value={artifactName} - onChange={artifactName => onDataChanged({artifactName})}/> - <Input - type='textarea' - name='description' - label={i18n('Description')} - isValid={genericFieldInfo['description'].isValid} - errorText={genericFieldInfo['description'].errorText} - isRequired={true} - value={description} - overlayPos='bottom' - onChange={description => onDataChanged({description})}/> - </Form> } - </div> - ); - } - - onSaveClicked() { - let {currentFlow, onSubmit} = this.props; - if (onSubmit) { - onSubmit(currentFlow); - } - } - + onSaveClicked() { + let { currentFlow, onSubmit } = this.props; + if (onSubmit) { + onSubmit(currentFlow); + } + } } export default FlowsEditorModalView; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js b/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js index 642c578eb7..2718c19aaa 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsListEditor.js @@ -13,40 +13,50 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import FlowsActions from './FlowsActions.js'; import FlowsListEditorView from './FlowsListEditorView.jsx'; -export const mapStateToProps = ({flows}) => { - let {flowList = [], isDisplayModal, isModalInEditMode, shouldShowWorkflowsEditor = true, data = undefined, readonly} = flows; - let isCheckedOut = !readonly; - if(data && data.readonly){ - isCheckedOut = !data.readonly; - } +export const mapStateToProps = ({ flows }) => { + let { + flowList = [], + isDisplayModal, + isModalInEditMode, + shouldShowWorkflowsEditor = true, + data = undefined, + readonly + } = flows; + let isCheckedOut = !readonly; + if (data && data.readonly) { + isCheckedOut = !data.readonly; + } - return { - flowList, - isDisplayModal, - isCheckedOut, - isModalInEditMode, - shouldShowWorkflowsEditor, - currentFlow: data, - readonly - }; + return { + flowList, + isDisplayModal, + isCheckedOut, + isModalInEditMode, + shouldShowWorkflowsEditor, + currentFlow: data, + readonly + }; }; -const mapActionsToProps = (dispatch) => { - return { - onAddWorkflowClick: () => FlowsActions.openFlowDetailsEditor(dispatch), - onEditFlowDetailsClick: flow => FlowsActions.openFlowDetailsEditor(dispatch, flow), - onEditFlowDiagramClick: flow => FlowsActions.fetchArtifact(dispatch, {flow}), - onDeleteFlowClick: flow => FlowsActions.deleteFlow(dispatch, {flow}), - onSequenceDiagramSaveClick: flow => { - FlowsActions.closeFlowDiagramEditor(dispatch); - FlowsActions.createOrUpdateFlow(dispatch, {flow}); - }, - onSequenceDiagramCloseClick: () => FlowsActions.closeFlowDiagramEditor(dispatch) - }; +const mapActionsToProps = dispatch => { + return { + onAddWorkflowClick: () => FlowsActions.openFlowDetailsEditor(dispatch), + onEditFlowDetailsClick: flow => + FlowsActions.openFlowDetailsEditor(dispatch, flow), + onEditFlowDiagramClick: flow => + FlowsActions.fetchArtifact(dispatch, { flow }), + onDeleteFlowClick: flow => FlowsActions.deleteFlow(dispatch, { flow }), + onSequenceDiagramSaveClick: flow => { + FlowsActions.closeFlowDiagramEditor(dispatch); + FlowsActions.createOrUpdateFlow(dispatch, { flow }); + }, + onSequenceDiagramCloseClick: () => + FlowsActions.closeFlowDiagramEditor(dispatch) + }; }; export default connect(mapStateToProps, mapActionsToProps)(FlowsListEditorView); diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx b/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx index 365b7f1bdf..3b2ff0619c 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/flows/FlowsListEditorView.jsx @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Modal from 'nfvo-components/modal/Modal.jsx'; @@ -25,125 +25,146 @@ import FlowsEditorModal from './FlowsEditorModal.js'; import SequenceDiagram from './SequenceDiagram.jsx'; class FlowsListEditorView extends Component { - - static propTypes = { - flowList: PropTypes.array, - currentFlow: PropTypes.object, - isDisplayModal: PropTypes.bool, - isModalInEditMode: PropTypes.bool, - isCheckedOut: PropTypes.bool, - shouldShowWorkflowsEditor: PropTypes.bool, - readonly: PropTypes.bool, - - onAddWorkflowClick: PropTypes.func, - onEditFlowDetailsClick: PropTypes.func, - onEditFlowDiagramClick: PropTypes.func, - onDeleteFlowClick: PropTypes.func, - onSequenceDiagramSaveClick: PropTypes.func, - onSequenceDiagramCloseClick: PropTypes.func - }; - - state = { - localFilter: '' - }; - - render() { - let CurrentView = null; - if (this.props.shouldShowWorkflowsEditor) { - CurrentView = this.renderWorkflowsEditor(); - } - else { - CurrentView = this.renderSequenceDiagramTool(); - } - - return CurrentView; - } - - renderWorkflowsEditor() { - let {isDisplayModal, onAddWorkflowClick, isCheckedOut} = this.props; - const {localFilter} = this.state; - - return ( - <div className='workflows license-agreement-list-editor'> - <FlowRelatedView display={localFilter}/> - <ListEditorView - plusButtonTitle={i18n('Add Workflow')} - onAdd={onAddWorkflowClick} - filterValue={localFilter} - onFilter={filter => this.setState({localFilter: filter})} - isReadOnlyMode={!isCheckedOut}> - {this.filterList().map(flow => this.renderWorkflowListItem(flow, isCheckedOut))} - </ListEditorView> - - {isDisplayModal && this.renderWorkflowEditorModal()} - - </div> - ); - } - - renderWorkflowEditorModal() { - let { isDisplayModal, isModalInEditMode} = this.props; - return ( - <Modal show={isDisplayModal} animation={true} className='onborading-modal workflows-editor-modal'> - <Modal.Header> - <Modal.Title> - {`${isModalInEditMode ? i18n('Edit Workflow') : i18n('Create New Workflow')}`} - </Modal.Title> - </Modal.Header> - <Modal.Body> - <FlowsEditorModal isNewArtifact={!isModalInEditMode}/> - </Modal.Body> - </Modal> - ); - } - - renderSequenceDiagramTool() { - let {onSequenceDiagramSaveClick, onSequenceDiagramCloseClick, currentFlow} = this.props; - return ( - <SequenceDiagram - onSave={sequenceDiagramModel => onSequenceDiagramSaveClick({...currentFlow, sequenceDiagramModel})} - onClose={onSequenceDiagramCloseClick} - model={currentFlow.sequenceDiagramModel}/> - ); - } - - filterList() { - let {flowList} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return flowList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return flowList; - } - } - - renderWorkflowListItem(flow, isCheckedOut) { - let {uniqueId, artifactName, description} = flow; - let {onEditFlowDetailsClick, onEditFlowDiagramClick, onDeleteFlowClick} = this.props; - return ( - <ListEditorItemView - key={uniqueId} - onSelect={() => onEditFlowDetailsClick(flow)} - onDelete={() => onDeleteFlowClick(flow)} - onEdit={() => onEditFlowDiagramClick(flow)} - className='list-editor-item-view' - isCheckedOut={isCheckedOut}> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Name')}</div> - <div className='text name'>{artifactName}</div> - </div> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Description')}</div> - <div className='text description'>{description}</div> - </div> - </ListEditorItemView> - ); - } - + static propTypes = { + flowList: PropTypes.array, + currentFlow: PropTypes.object, + isDisplayModal: PropTypes.bool, + isModalInEditMode: PropTypes.bool, + isCheckedOut: PropTypes.bool, + shouldShowWorkflowsEditor: PropTypes.bool, + readonly: PropTypes.bool, + + onAddWorkflowClick: PropTypes.func, + onEditFlowDetailsClick: PropTypes.func, + onEditFlowDiagramClick: PropTypes.func, + onDeleteFlowClick: PropTypes.func, + onSequenceDiagramSaveClick: PropTypes.func, + onSequenceDiagramCloseClick: PropTypes.func + }; + + state = { + localFilter: '' + }; + + render() { + let CurrentView = null; + if (this.props.shouldShowWorkflowsEditor) { + CurrentView = this.renderWorkflowsEditor(); + } else { + CurrentView = this.renderSequenceDiagramTool(); + } + + return CurrentView; + } + + renderWorkflowsEditor() { + let { isDisplayModal, onAddWorkflowClick, isCheckedOut } = this.props; + const { localFilter } = this.state; + + return ( + <div className="workflows license-agreement-list-editor"> + <FlowRelatedView display={localFilter} /> + <ListEditorView + plusButtonTitle={i18n('Add Workflow')} + onAdd={onAddWorkflowClick} + filterValue={localFilter} + onFilter={filter => this.setState({ localFilter: filter })} + isReadOnlyMode={!isCheckedOut}> + {this.filterList().map(flow => + this.renderWorkflowListItem(flow, isCheckedOut) + )} + </ListEditorView> + + {isDisplayModal && this.renderWorkflowEditorModal()} + </div> + ); + } + + renderWorkflowEditorModal() { + let { isDisplayModal, isModalInEditMode } = this.props; + return ( + <Modal + show={isDisplayModal} + animation={true} + className="onborading-modal workflows-editor-modal"> + <Modal.Header> + <Modal.Title> + {`${ + isModalInEditMode + ? i18n('Edit Workflow') + : i18n('Create New Workflow') + }`} + </Modal.Title> + </Modal.Header> + <Modal.Body> + <FlowsEditorModal isNewArtifact={!isModalInEditMode} /> + </Modal.Body> + </Modal> + ); + } + + renderSequenceDiagramTool() { + let { + onSequenceDiagramSaveClick, + onSequenceDiagramCloseClick, + currentFlow + } = this.props; + return ( + <SequenceDiagram + onSave={sequenceDiagramModel => + onSequenceDiagramSaveClick({ + ...currentFlow, + sequenceDiagramModel + }) + } + onClose={onSequenceDiagramCloseClick} + model={currentFlow.sequenceDiagramModel} + /> + ); + } + + filterList() { + let { flowList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return flowList.filter(({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + }); + } else { + return flowList; + } + } + + renderWorkflowListItem(flow, isCheckedOut) { + let { uniqueId, artifactName, description } = flow; + let { + onEditFlowDetailsClick, + onEditFlowDiagramClick, + onDeleteFlowClick + } = this.props; + return ( + <ListEditorItemView + key={uniqueId} + onSelect={() => onEditFlowDetailsClick(flow)} + onDelete={() => onDeleteFlowClick(flow)} + onEdit={() => onEditFlowDiagramClick(flow)} + className="list-editor-item-view" + isCheckedOut={isCheckedOut}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div className="text name">{artifactName}</div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Description')}</div> + <div className="text description">{description}</div> + </div> + </ListEditorItemView> + ); + } } export default FlowsListEditorView; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js b/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js index 14bf595050..0279824ac4 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsListReducer.js @@ -13,87 +13,91 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, FLOWS_EDITOR_FORM} from './FlowsConstants.js'; +import { actionTypes, FLOWS_EDITOR_FORM } from './FlowsConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.FLOW_LIST_LOADED: - return { - ...state, - flowList: action.results, - flowParticipants: action.participants, - serviceID: action.serviceID, - diagramType: action.diagramType, - readonly: action.readonly - }; - case actionTypes.ADD_OR_UPDATE_FLOW: - case actionTypes.ARTIFACT_LOADED: - let flowList = state.flowList || []; - let index = flowList.findIndex(flow => flow.uniqueId === action.flow.uniqueId); - if (index === -1) { - index = flowList.length; - } - let flowToBeUpdated = flowList[index]; - flowList = [ - ...flowList.slice(0, index), - {...flowToBeUpdated, ...action.flow}, - ...flowList.slice(index + 1) - ]; - return { - ...state, - flowList, - serviceID: action.flow.serviceID, - diagramType: action.flow.artifactType || state.diagramType - }; - case actionTypes.DELETE_FLOW: - return { - ...state, - flowList: state.flowList.filter(flow => flow.uniqueId !== action.flow.uniqueId) - }; - case actionTypes.OPEN_FLOW_DETAILS_EDITOR: - return { - ...state, - formName: FLOWS_EDITOR_FORM, - formReady: null, - genericFieldInfo: { - artifactName : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - description: { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - } - }, - data: action.flow, - isDisplayModal: true, - isModalInEditMode: Boolean(action.flow && action.flow.uniqueId) - }; + switch (action.type) { + case actionTypes.FLOW_LIST_LOADED: + return { + ...state, + flowList: action.results, + flowParticipants: action.participants, + serviceID: action.serviceID, + diagramType: action.diagramType, + readonly: action.readonly + }; + case actionTypes.ADD_OR_UPDATE_FLOW: + case actionTypes.ARTIFACT_LOADED: + let flowList = state.flowList || []; + let index = flowList.findIndex( + flow => flow.uniqueId === action.flow.uniqueId + ); + if (index === -1) { + index = flowList.length; + } + let flowToBeUpdated = flowList[index]; + flowList = [ + ...flowList.slice(0, index), + { ...flowToBeUpdated, ...action.flow }, + ...flowList.slice(index + 1) + ]; + return { + ...state, + flowList, + serviceID: action.flow.serviceID, + diagramType: action.flow.artifactType || state.diagramType + }; + case actionTypes.DELETE_FLOW: + return { + ...state, + flowList: state.flowList.filter( + flow => flow.uniqueId !== action.flow.uniqueId + ) + }; + case actionTypes.OPEN_FLOW_DETAILS_EDITOR: + return { + ...state, + formName: FLOWS_EDITOR_FORM, + formReady: null, + genericFieldInfo: { + artifactName: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + description: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + } + }, + data: action.flow, + isDisplayModal: true, + isModalInEditMode: Boolean(action.flow && action.flow.uniqueId) + }; - case actionTypes.CLOSE_FLOW_DETAILS_EDITOR: - return { - ...state, - data: undefined, - isDisplayModal: false, - isModalInEditMode: false - }; - case actionTypes.OPEN_FLOW_DIAGRAM_EDITOR: - return { - ...state, - data: action.flow, - shouldShowWorkflowsEditor: false - }; - case actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR: - return { - ...state, - data: undefined, - shouldShowWorkflowsEditor: true - }; - case actionTypes.RESET: - return {}; - } + case actionTypes.CLOSE_FLOW_DETAILS_EDITOR: + return { + ...state, + data: undefined, + isDisplayModal: false, + isModalInEditMode: false + }; + case actionTypes.OPEN_FLOW_DIAGRAM_EDITOR: + return { + ...state, + data: action.flow, + shouldShowWorkflowsEditor: false + }; + case actionTypes.CLOSE_FLOW_DIAGRAM_EDITOR: + return { + ...state, + data: undefined, + shouldShowWorkflowsEditor: true + }; + case actionTypes.RESET: + return {}; + } - return state; + return state; }; diff --git a/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx b/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx index a2a5554203..7d302444e4 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx +++ b/openecomp-ui/src/sdc-app/flows/FlowsPunchOut.jsx @@ -22,57 +22,66 @@ import FlowsListEditor from './FlowsListEditor.js'; import FlowsActions from './FlowsActions.js'; class FlowsListEditorPunchOutWrapper extends React.Component { + componentDidMount() { + let element = ReactDOM.findDOMNode(this); + element.addEventListener('click', event => { + if (event.target.tagName === 'A') { + event.preventDefault(); + } + }); + ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => + element.addEventListener(eventType, event => + event.stopPropagation() + ) + ); + } - componentDidMount() { - let element = ReactDOM.findDOMNode(this); - element.addEventListener('click', event => { - if (event.target.tagName === 'A') { - event.preventDefault(); - } - }); - ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => - element.addEventListener(eventType, event => event.stopPropagation()) - ); - } - - render() { - return <FlowsListEditor/>; - } + render() { + return <FlowsListEditor />; + } } export default class DiagramPunchOut { + render({ options: { data, apiRoot, apiHeaders }, onEvent }, element) { + if (!this.isConfigSet) { + Configuration.setCatalogApiRoot(apiRoot); + Configuration.setCatalogApiHeaders(apiHeaders); + this.isConfigSet = true; + } - render({options: {data, apiRoot, apiHeaders}, onEvent}, element) { - - if (!this.isConfigSet) { - Configuration.setCatalogApiRoot(apiRoot); - Configuration.setCatalogApiHeaders(apiHeaders); - this.isConfigSet = true; - } - - this.onEvent = onEvent; - this.handleData(data); + this.onEvent = onEvent; + this.handleData(data); - if (!this.rendered) { - ReactDOM.render(<Application><div className='dox-ui'><FlowsListEditorPunchOutWrapper/></div></Application>, element); - this.rendered = true; - } - } + if (!this.rendered) { + ReactDOM.render( + <Application> + <div className="dox-ui"> + <FlowsListEditorPunchOutWrapper /> + </div> + </Application>, + element + ); + this.rendered = true; + } + } - unmount(element) { - let dispatch = action => store.dispatch(action); - ReactDOM.unmountComponentAtNode(element); - FlowsActions.reset(dispatch); - } + unmount(element) { + let dispatch = action => store.dispatch(action); + ReactDOM.unmountComponentAtNode(element); + FlowsActions.reset(dispatch); + } - handleData(data) { - let {serviceID, diagramType} = data; - let dispatch = action => store.dispatch(action); + handleData(data) { + let { serviceID, diagramType } = data; + let dispatch = action => store.dispatch(action); - if (serviceID !== this.prevServiceID || diagramType !== this.prevDiagramType) { - this.prevServiceID = serviceID; - this.prevDiagramType = diagramType; - FlowsActions.fetchFlowArtifacts(dispatch, {...data}); - } - } + if ( + serviceID !== this.prevServiceID || + diagramType !== this.prevDiagramType + ) { + this.prevServiceID = serviceID; + this.prevDiagramType = diagramType; + FlowsActions.fetchFlowArtifacts(dispatch, { ...data }); + } + } } diff --git a/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js b/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js index 54043498f0..c037f3eefd 100644 --- a/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js +++ b/openecomp-ui/src/sdc-app/flows/FlowsReducersMap.js @@ -15,8 +15,8 @@ */ import flowListReducer from './FlowsListReducer.js'; -import {createPlainDataReducer} from 'sdc-app/common/reducers/PlainDataReducer.js'; +import { createPlainDataReducer } from 'sdc-app/common/reducers/PlainDataReducer.js'; export default { - flows: createPlainDataReducer(flowListReducer) + flows: createPlainDataReducer(flowListReducer) }; diff --git a/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx b/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx index d0a5bf3251..8a634915ac 100644 --- a/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx +++ b/openecomp-ui/src/sdc-app/flows/ImportantLogic.jsx @@ -13,27 +13,31 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import md5 from 'md5'; class ImportantLogic extends Component { + state = { + whatToDisplay: false + }; - state = { - whatToDisplay: false - }; + componentWillReceiveProps(nextProps) { + this.setState({ + whatToDisplay: + md5(nextProps.display) === 'a55899b341525123628776dbf5755d51' + }); + } - componentWillReceiveProps(nextProps) { - this.setState({whatToDisplay: md5(nextProps.display) === 'a55899b341525123628776dbf5755d51'}); - } + render() { + if (this.state.whatToDisplay) { + setTimeout(() => this.setState({ whatToDisplay: false }), 5000); + } - render() { - if (this.state.whatToDisplay) { - setTimeout(() => this.setState({whatToDisplay: false}), 5000); - } - - return ( - <div> - <style>{'\.easter-wrapper {\ + return ( + <div> + <style> + { + '.easter-wrapper {\ position: fixed;\ width: 70px;\ height: 70px;\ @@ -96,16 +100,20 @@ class ImportantLogic extends Component { @keyframes yo-yo {\ from { transform: rotate(-0deg); top: 0 }\ to { transform: rotate(-360deg); top:120px }\ - }'}</style> - <div - className='easter-wrapper' - style={{display: this.state.whatToDisplay ? 'block' : 'none'}}> - <span className='string'>{}</span> - <span className='yo-yo'>{}</span> - </div> - </div> - ); - } + }' + } + </style> + <div + className="easter-wrapper" + style={{ + display: this.state.whatToDisplay ? 'block' : 'none' + }}> + <span className="string">{}</span> + <span className="yo-yo">{}</span> + </div> + </div> + ); + } } export default ImportantLogic; diff --git a/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx index c128083774..ca24964472 100644 --- a/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx +++ b/openecomp-ui/src/sdc-app/flows/SequenceDiagram.jsx @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Button from 'sdc-ui/lib/react/Button.js'; import Sequencer from 'dox-sequence-diagram-ui'; @@ -21,31 +21,37 @@ import Sequencer from 'dox-sequence-diagram-ui'; import i18n from 'nfvo-utils/i18n/i18n.js'; class SequenceDiagram extends Component { + static propTypes = { + onSave: PropTypes.func.isRequired, + onClose: PropTypes.func, + model: PropTypes.object.isRequired + }; - static propTypes = { - onSave: PropTypes.func.isRequired, - onClose: PropTypes.func, - model: PropTypes.object.isRequired - }; - - onSave() { - this.props.onSave(this.refs.sequencer.getModel()); - } - - render() { - return ( - <div className='sequence-diagram'> - <div className='sequence-diagram-sequencer'> - <Sequencer ref='sequencer' options={{useHtmlSelect: true}} model={this.props.model} /> - </div> - <div className='sequence-diagram-action-buttons'> - <Button onClick={() => this.onSave()}>{i18n('Save')}</Button> - <Button onClick={this.props.onClose}>{i18n('Close')}</Button> - </div> - </div> - ); - } + onSave() { + this.props.onSave(this.refs.sequencer.getModel()); + } + render() { + return ( + <div className="sequence-diagram"> + <div className="sequence-diagram-sequencer"> + <Sequencer + ref="sequencer" + options={{ useHtmlSelect: true }} + model={this.props.model} + /> + </div> + <div className="sequence-diagram-action-buttons"> + <Button onClick={() => this.onSave()}> + {i18n('Save')} + </Button> + <Button onClick={this.props.onClose}> + {i18n('Close')} + </Button> + </div> + </div> + ); + } } export default SequenceDiagram; diff --git a/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js b/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js index c83fdc91f0..23723dc91d 100644 --- a/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js +++ b/openecomp-ui/src/sdc-app/flows/SequenceDiagramModelHelper.js @@ -16,51 +16,54 @@ import emptyModel from './emptyModel.json'; function mergeLifelines(oldLifelines, newLifelines) { - let oldLifelinesMap = new Map(oldLifelines.map(lifeline => [lifeline.id, lifeline])); - let newLifelinesMap = new Map(newLifelines.map(lifeline => [lifeline.id, lifeline])); + let oldLifelinesMap = new Map( + oldLifelines.map(lifeline => [lifeline.id, lifeline]) + ); + let newLifelinesMap = new Map( + newLifelines.map(lifeline => [lifeline.id, lifeline]) + ); - let updatedLifelines = oldLifelines.map(lifeline => { - let newLifeline = newLifelinesMap.get(lifeline.id); - return { - ...lifeline, - name: newLifeline ? newLifeline.name : lifeline.name - }; - }); + let updatedLifelines = oldLifelines.map(lifeline => { + let newLifeline = newLifelinesMap.get(lifeline.id); + return { + ...lifeline, + name: newLifeline ? newLifeline.name : lifeline.name + }; + }); - let addedLifelines = newLifelines.filter(lifeline => !oldLifelinesMap.has(lifeline.id)); + let addedLifelines = newLifelines.filter( + lifeline => !oldLifelinesMap.has(lifeline.id) + ); - return [ - ...updatedLifelines, - ...addedLifelines - ]; + return [...updatedLifelines, ...addedLifelines]; } - const SequenceDiagramModelHelper = Object.freeze({ + createModel(options) { + return SequenceDiagramModelHelper.updateModel(emptyModel, options); + }, - createModel(options) { - return SequenceDiagramModelHelper.updateModel(emptyModel, options); - }, - - updateModel(model, options) { - const diagram = model.diagram; - const metadata = diagram.metadata || model.metadata; - const id = options.id || metadata.id; - const name = options.name || metadata.name; - const lifelines = options.lifelines ? mergeLifelines(diagram.lifelines, options.lifelines) : diagram.lifelines; + updateModel(model, options) { + const diagram = model.diagram; + const metadata = diagram.metadata || model.metadata; + const id = options.id || metadata.id; + const name = options.name || metadata.name; + const lifelines = options.lifelines + ? mergeLifelines(diagram.lifelines, options.lifelines) + : diagram.lifelines; - return { - diagram: { - ...diagram, - metadata: { - ...metadata, - id, - name - }, - lifelines - } - }; - } + return { + diagram: { + ...diagram, + metadata: { + ...metadata, + id, + name + }, + lifelines + } + }; + } }); export default SequenceDiagramModelHelper; diff --git a/openecomp-ui/src/sdc-app/heatValidation.app.jsx b/openecomp-ui/src/sdc-app/heatValidation.app.jsx index 5abe3091b3..bb9a4bbe9b 100644 --- a/openecomp-ui/src/sdc-app/heatValidation.app.jsx +++ b/openecomp-ui/src/sdc-app/heatValidation.app.jsx @@ -23,5 +23,9 @@ import ReactDOM from 'react-dom'; import UploadScreen from './heatvalidation/UploadScreen.jsx'; import Application from './Application.jsx'; - -ReactDOM.render(<Application openSocket={false}><UploadScreen/></Application>, document.getElementById('heat-validation-app')); +ReactDOM.render( + <Application openSocket={false}> + <UploadScreen /> + </Application>, + document.getElementById('heat-validation-app') +); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/Attachments.js b/openecomp-ui/src/sdc-app/heatvalidation/Attachments.js index d3e30b0df8..4532c0a7d2 100644 --- a/openecomp-ui/src/sdc-app/heatvalidation/Attachments.js +++ b/openecomp-ui/src/sdc-app/heatvalidation/Attachments.js @@ -13,32 +13,53 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; -import {mapStateToProps as attachmentsMapStateToProps, mapActionsToProps as attachmentsMapActionsToProps} from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js'; +import { + mapStateToProps as attachmentsMapStateToProps, + mapActionsToProps as attachmentsMapActionsToProps +} from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js'; // import AttachmentsView from './AttachmentsView.jsx'; import AttachmentsView from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx'; import UploadScreenActionHelper from './UploadScreenActionHelper.js'; import HeatSetup from './HeatSetup'; -export const mapStateToProps = (state) => { - let original = attachmentsMapStateToProps(state); - return { - ...original, - HeatSetupComponent: HeatSetup, - isReadOnlyMode: false - }; +export const mapStateToProps = state => { + let original = attachmentsMapStateToProps(state); + return { + ...original, + HeatSetupComponent: HeatSetup, + isReadOnlyMode: false + }; }; -const mapActionsToProps = (dispatch, {softwareProductId}) => { - let original = attachmentsMapActionsToProps(dispatch, {softwareProductId}); - return { - ...original, - onDownload: heatCandidate => UploadScreenActionHelper.downloadHeatFile(dispatch, heatCandidate), - onUpload: formData => UploadScreenActionHelper.uploadFile(dispatch, formData), - onSave: (heatCandidate) => SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate}), - onProcessAndValidate: (heatData, heatDataCache) => UploadScreenActionHelper.processAndValidateHeat(dispatch, heatData, heatDataCache) - }; +const mapActionsToProps = (dispatch, { softwareProductId }) => { + let original = attachmentsMapActionsToProps(dispatch, { + softwareProductId + }); + return { + ...original, + onDownload: heatCandidate => + UploadScreenActionHelper.downloadHeatFile(dispatch, heatCandidate), + onUpload: formData => + UploadScreenActionHelper.uploadFile(dispatch, formData), + onSave: heatCandidate => + SoftwareProductActionHelper.updateSoftwareProductHeatCandidate( + dispatch, + { + softwareProductId, + heatCandidate + } + ), + onProcessAndValidate: (heatData, heatDataCache) => + UploadScreenActionHelper.processAndValidateHeat( + dispatch, + heatData, + heatDataCache + ) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(AttachmentsView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(AttachmentsView); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/HeatSetup.js b/openecomp-ui/src/sdc-app/heatvalidation/HeatSetup.js index 925b0095ba..a94cfd9f81 100644 --- a/openecomp-ui/src/sdc-app/heatvalidation/HeatSetup.js +++ b/openecomp-ui/src/sdc-app/heatvalidation/HeatSetup.js @@ -13,16 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; -import HeatSetupView from '../onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx'; +import { connect } from 'react-redux'; +import HeatSetupView from '../onboarding/softwareProduct/attachments/setup/HeatSetupView.jsx'; import UploadScreenActionHelper from './UploadScreenActionHelper.js'; -import {mapStateToProps, mapActionsToProps} from '../onboarding/softwareProduct/attachments/setup/HeatSetup.js'; +import { + mapStateToProps, + mapActionsToProps +} from '../onboarding/softwareProduct/attachments/setup/HeatSetup.js'; -const mapActionsToPropsExt = (dispatch) => { - return { - ...mapActionsToProps(dispatch,{}), - onProcessAndValidate: (heatData, heatDataCache) => UploadScreenActionHelper.processAndValidateHeat(dispatch, heatData, heatDataCache) - }; +const mapActionsToPropsExt = dispatch => { + return { + ...mapActionsToProps(dispatch, {}), + onProcessAndValidate: (heatData, heatDataCache) => + UploadScreenActionHelper.processAndValidateHeat( + dispatch, + heatData, + heatDataCache + ) + }; }; -export default connect(mapStateToProps, mapActionsToPropsExt, null, {withRef: true})(HeatSetupView); +export default connect(mapStateToProps, mapActionsToPropsExt, null, { + withRef: true +})(HeatSetupView); diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx index 2d99c0f497..6d3d54b5cb 100644 --- a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreen.jsx @@ -16,17 +16,14 @@ import React from 'react'; import SoftwareProductAttachmentsView from './Attachments.js'; - - class UploadScreen extends React.Component { - - render() { - return( - <div className='heat-validation-stand-alone'> - <SoftwareProductAttachmentsView /> - </div> - ); - } + render() { + return ( + <div className="heat-validation-stand-alone"> + <SoftwareProductAttachmentsView /> + </div> + ); + } } -export default UploadScreen; +export default UploadScreen; diff --git a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js index fa2d4695ae..f5d9abd6d2 100644 --- a/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js +++ b/openecomp-ui/src/sdc-app/heatvalidation/UploadScreenActionHelper.js @@ -18,155 +18,197 @@ import showFileSaveDialog from 'nfvo-utils/ShowFileSaveDialog.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import isEqual from 'lodash/isEqual.js'; import cloneDeep from 'lodash/cloneDeep.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes as softwareProductsActionTypes} from '../onboarding/softwareProduct/SoftwareProductConstants.js'; -import {actionTypes as HeatSetupActions} from '../onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js'; - - +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes as softwareProductsActionTypes } from '../onboarding/softwareProduct/SoftwareProductConstants.js'; +import { actionTypes as HeatSetupActions } from '../onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js'; const options = { - headers: { - USER_ID: 'validationOnlyVspUser' - } + headers: { + USER_ID: 'validationOnlyVspUser' + } }; function fetchVspIdAndVersion() { - - let vspId = sessionStorage.getItem('validationAppVspId'); - let versionId = sessionStorage.getItem('validationAppVersionId'); - if (vspId) { - return Promise.resolve({value: vspId, versionId}); - }else { - return RestAPIUtil.fetch('/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/validation-vsp', options) - .then(response => { - sessionStorage.setItem('validationAppVspId', response.itemId); - sessionStorage.setItem('validationAppVersionId', response.version.id); - return Promise.resolve({value: response.itemId, versionId: response.version.id}); - }); - } - + let vspId = sessionStorage.getItem('validationAppVspId'); + let versionId = sessionStorage.getItem('validationAppVersionId'); + if (vspId) { + return Promise.resolve({ value: vspId, versionId }); + } else { + return RestAPIUtil.fetch( + '/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/validation-vsp', + options + ).then(response => { + sessionStorage.setItem('validationAppVspId', response.itemId); + sessionStorage.setItem( + 'validationAppVersionId', + response.version.id + ); + return Promise.resolve({ + value: response.itemId, + versionId: response.version.id + }); + }); + } } - function uploadFile(formData) { - return fetchVspIdAndVersion() - .then(response => { - return RestAPIUtil.post(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}/orchestration-template-candidate`, formData, options); - }); + return fetchVspIdAndVersion().then(response => { + return RestAPIUtil.post( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${response.versionId}/orchestration-template-candidate`, + formData, + options + ); + }); } -function loadSoftwareProductHeatCandidate(dispatch){ - return fetchVspIdAndVersion() - .then(response => { - return RestAPIUtil.fetch(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}/orchestration-template-candidate/manifest`, options) - .then(response => dispatch({ - type: HeatSetupActions.MANIFEST_LOADED, - response - })); - }); +function loadSoftwareProductHeatCandidate(dispatch) { + return fetchVspIdAndVersion().then(response => { + return RestAPIUtil.fetch( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${ + response.versionId + }/orchestration-template-candidate/manifest`, + options + ).then(response => + dispatch({ + type: HeatSetupActions.MANIFEST_LOADED, + response + }) + ); + }); } function updateHeatCandidate(dispatch, heatCandidate) { - return fetchVspIdAndVersion() - .then(response => { - return RestAPIUtil.put(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}/orchestration-template-candidate/manifest`, - heatCandidate.heatData, options) - .then(null, error => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Save Failed'), - modalComponentName: modalContentMapper.SUMBIT_ERROR_RESPONSE, - modalComponentProps: { - validationResponse: error.responseJSON - }, - cancelButtonText: i18n('Ok') - } - }); - return Promise.reject(error); - }); - }); + return fetchVspIdAndVersion().then(response => { + return RestAPIUtil.put( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${ + response.versionId + }/orchestration-template-candidate/manifest`, + heatCandidate.heatData, + options + ).then(null, error => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Save Failed'), + modalComponentName: + modalContentMapper.SUMBIT_ERROR_RESPONSE, + modalComponentProps: { + validationResponse: error.responseJSON + }, + cancelButtonText: i18n('Ok') + } + }); + return Promise.reject(error); + }); + }); } function fetchSoftwareProduct() { - return fetchVspIdAndVersion() - .then(response => { - return RestAPIUtil.fetch(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}`, options); - }); + return fetchVspIdAndVersion().then(response => { + return RestAPIUtil.fetch( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${response.versionId}`, + options + ); + }); } function downloadHeatFile() { - return fetchVspIdAndVersion() - .then(response => { - RestAPIUtil.fetch(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}/orchestration-template-candidate`, { - ...options, - dataType: 'binary' - }) - .done((response) => showFileSaveDialog({ - blob: response.blob, - headers: response.headers, - defaultFilename: 'HEAT_file.zip', - addTimestamp: true - })); - }); + return fetchVspIdAndVersion().then(response => { + RestAPIUtil.fetch( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${response.versionId}/orchestration-template-candidate`, + { + ...options, + dataType: 'binary' + } + ).done(response => + showFileSaveDialog({ + blob: response.blob, + headers: response.headers, + defaultFilename: 'HEAT_file.zip', + addTimestamp: true + }) + ); + }); } function processAndValidateHeatCandidate(dispatch) { - return fetchVspIdAndVersion() - .then(response => { - return RestAPIUtil.put(`/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${response.value}/versions/${response.versionId}/orchestration-template-candidate/process`, {}, options) - .then(response => { - if (response.status === 'Success') { - fetchSoftwareProduct().then(response => { - dispatch({ - type: softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED, - response - }); - }); - } - }); - }); + return fetchVspIdAndVersion().then(response => { + return RestAPIUtil.put( + `/sdc1/feProxy/onboarding-api/v1.0/vendor-software-products/${ + response.value + }/versions/${ + response.versionId + }/orchestration-template-candidate/process`, + {}, + options + ).then(response => { + if (response.status === 'Success') { + fetchSoftwareProduct().then(response => { + dispatch({ + type: + softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED, + response + }); + }); + } + }); + }); } const UploadScreenActionHelper = { - uploadFile(dispatch, formData) { - - return Promise.resolve() - .then(() => uploadFile(formData)) - .then(response => { - dispatch({ - type: softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED, - response - }); - dispatch({ - type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, - payload:{} - }); - loadSoftwareProductHeatCandidate(dispatch); - }) - .catch(error => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('File Upload Failed'), - msg: error.responseJSON.message, - cancelButtonText: i18n('Ok') - } - }); - }); - }, - - processAndValidateHeat(dispatch, heatData, heatDataCache){ - return isEqual(heatData, heatDataCache) ? Promise.resolve() : - updateHeatCandidate(dispatch, heatData) - .then(() => processAndValidateHeatCandidate(dispatch)) - .then(() => dispatch({type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, payload: cloneDeep(heatData)})); - }, - - downloadHeatFile(){ - return downloadHeatFile(); - }, + uploadFile(dispatch, formData) { + return Promise.resolve() + .then(() => uploadFile(formData)) + .then(response => { + dispatch({ + type: softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED, + response + }); + dispatch({ + type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, + payload: {} + }); + loadSoftwareProductHeatCandidate(dispatch); + }) + .catch(error => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('File Upload Failed'), + msg: error.responseJSON.message, + cancelButtonText: i18n('Ok') + } + }); + }); + }, + + processAndValidateHeat(dispatch, heatData, heatDataCache) { + return isEqual(heatData, heatDataCache) + ? Promise.resolve() + : updateHeatCandidate(dispatch, heatData) + .then(() => processAndValidateHeatCandidate(dispatch)) + .then(() => + dispatch({ + type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, + payload: cloneDeep(heatData) + }) + ); + }, + + downloadHeatFile() { + return downloadHeatFile(); + } }; export default UploadScreenActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/GridStyling.stories.js b/openecomp-ui/src/sdc-app/onboarding/GridStyling.stories.js index 81a29cf046..7b8c87e62c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/GridStyling.stories.js +++ b/openecomp-ui/src/sdc-app/onboarding/GridStyling.stories.js @@ -1,221 +1,151 @@ import React from 'react'; -import {storiesOf} from '@kadira/storybook'; -import {withKnobs} from '@kadira/storybook-addon-knobs'; +import { storiesOf } from '@kadira/storybook'; +import { withKnobs } from '@kadira/storybook-addon-knobs'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; - const stories = storiesOf('GridColumns', module); stories.addDecorator(withKnobs); var divStyle = { - 'border-style': 'solid', - 'border-size': 1 + 'border-style': 'solid', + 'border-size': 1 }; -const myDiv = (<div style={divStyle}>Text Text Text</div>); +const myDiv = <div style={divStyle}>Text Text Text</div>; stories - .add('Grid Options', () => ( - <div> - <GridSection title='No last column set on item'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - </GridSection> - - <GridSection hasLastColSet={true} title='With last column set on item and gridsection'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - - <GridSection title='With last column set on item and NOT on gridsection'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> + .add('Grid Options', () => ( + <div> + <GridSection title="No last column set on item"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2}>{myDiv}</GridItem> + </GridSection> - </div> - )) - .add('Last Column', () => ( + <GridSection + hasLastColSet={true} + title="With last column set on item and gridsection"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> - <div> - <GridSection hasLastColSet={true} title='Testing different configurations with all settings'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={4} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={3}> - {myDiv} - </GridItem> - <GridItem colSpan={1} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={3} lastColInRow={true}> - {myDiv} - </GridItem> - </GridSection> - </div> - )) - .add('No Last Column', () => ( - <div> - <GridSection title='Testing different configurations'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={4}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={3}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - </GridSection> - <GridSection> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={3}> - {myDiv} - </GridItem> - </GridSection> - </div> - )) .add('Test LKG form', () => ( - <div> - <GridSection title='Testing VLM LKG configurations'> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - <GridItem colSpan={2}> - {myDiv} - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1}> - {myDiv} - </GridItem> - <GridItem colSpan={1} lastColInRow={true}> - {myDiv} - </GridItem> - <GridItem colSpan={2}> - <div style={divStyle}>1</div> - </GridItem> - </GridSection> - </div> -));
\ No newline at end of file + <GridSection title="With last column set on item and NOT on gridsection"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + </div> + )) + .add('Last Column', () => ( + <div> + <GridSection + hasLastColSet={true} + title="Testing different configurations with all settings"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={4} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={3}>{myDiv}</GridItem> + <GridItem colSpan={1} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={3} lastColInRow={true}> + {myDiv} + </GridItem> + </GridSection> + </div> + )) + .add('No Last Column', () => ( + <div> + <GridSection title="Testing different configurations"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={2}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={4}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={3}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + </GridSection> + <GridSection> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={3}>{myDiv}</GridItem> + </GridSection> + </div> + )) + .add('Test LKG form', () => ( + <div> + <GridSection title="Testing VLM LKG configurations"> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + <GridItem colSpan={2}>{myDiv}</GridItem> + <GridItem colSpan={2} lastColInRow={true}> + {myDiv} + </GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1}>{myDiv}</GridItem> + <GridItem colSpan={1} lastColInRow={true}> + {myDiv} + </GridItem> + <GridItem colSpan={2}> + <div style={divStyle}>1</div> + </GridItem> + </GridSection> + </div> + )); diff --git a/openecomp-ui/src/sdc-app/onboarding/Onboarding.js b/openecomp-ui/src/sdc-app/onboarding/Onboarding.js index faec816d42..b894e3f031 100644 --- a/openecomp-ui/src/sdc-app/onboarding/Onboarding.js +++ b/openecomp-ui/src/sdc-app/onboarding/Onboarding.js @@ -15,8 +15,8 @@ */ import OnboardingView from './OnboardingView.jsx'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; -const mapStateToProps = ({currentScreen}) => ({currentScreen}); +const mapStateToProps = ({ currentScreen }) => ({ currentScreen }); const Onboarding = connect(mapStateToProps, null)(OnboardingView); export default Onboarding; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js index d75c234caf..2fccfcbd2a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingActionHelper.js @@ -34,289 +34,591 @@ import ComputeFlavorActionHelper from './softwareProduct/components/compute/Comp import OnboardActionHelper from './onboard/OnboardActionHelper.js'; import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js'; import SoftwareProductComponentsMonitoringAction from './softwareProduct/components/monitoring/SoftwareProductComponentsMonitoringActionHelper.js'; -import {actionTypes, enums} from './OnboardingConstants.js'; -import {actionTypes as SoftwareProductActionTypes, onboardingOriginTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { actionTypes, enums } from './OnboardingConstants.js'; +import { + actionTypes as SoftwareProductActionTypes, + onboardingOriginTypes +} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import ActivityLogActionHelper from 'sdc-app/common/activity-log/ActivityLogActionHelper.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; import SoftwareProductComponentsImageActionHelper from './softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js'; import licenseModelOverviewActionHelper from 'sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js'; -import {tabsMapping as attachmentsTabsMapping} from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js'; +import { tabsMapping as attachmentsTabsMapping } from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js'; import SoftwareProductAttachmentsActionHelper from 'sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js'; function setCurrentScreen(dispatch, screen, props = {}) { - dispatch({ - type: actionTypes.SET_CURRENT_SCREEN, - currentScreen: { - screen, - props, - forceBreadCrumbsUpdate: true - } - }); + dispatch({ + type: actionTypes.SET_CURRENT_SCREEN, + currentScreen: { + screen, + props, + forceBreadCrumbsUpdate: true + } + }); } export function updateCurrentScreenProps(dispatch, props = {}) { - dispatch({ - type: actionTypes.UPDATE_CURRENT_SCREEN_PROPS, - props - }); + dispatch({ + type: actionTypes.UPDATE_CURRENT_SCREEN_PROPS, + props + }); } const OnboardingActionHelper = { - - loadItemsLists(dispatch) { - LicenseModelActionHelper.fetchLicenseModels(dispatch); - LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch); - LicenseModelActionHelper.fetchArchivedLicenseModels(dispatch); - SoftwareProductActionHelper.fetchSoftwareProductList(dispatch); - SoftwareProductActionHelper.fetchFinalizedSoftwareProductList(dispatch); - SoftwareProductActionHelper.fetchArchivedSoftwareProductList(dispatch); - }, - - navigateToOnboardingCatalog(dispatch) { - UsersActionHelper.fetchUsersList(dispatch); - this.loadItemsLists(dispatch); - OnboardActionHelper.resetOnboardStore(dispatch); - setCurrentScreen(dispatch, enums.SCREEN.ONBOARDING_CATALOG); - }, - - autoSaveBeforeNavigate(dispatch, {softwareProductId, version, vspComponentId, dataToSave}) { - if(softwareProductId) { - if(vspComponentId) { - return SoftwareProductComponentsActionHelper.updateSoftwareProductComponent(dispatch, { - softwareProductId, version, vspComponentId, - componentData: dataToSave.componentData, - qdata: dataToSave.qdata - }); - } - return SoftwareProductActionHelper.updateSoftwareProduct(dispatch, { - softwareProduct: dataToSave.softwareProduct, - version, - qdata: dataToSave.qdata - }); - } - return Promise.resolve(); - }, - - navigateToLicenseModelOverview(dispatch, {licenseModelId, version, status}) { - - /** - * TODO change to specific rest - */ - - LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { - LicenseModelActionHelper.fetchLicenseModelItems(dispatch, {licenseModelId, version}).then(() => { - setCurrentScreen(dispatch, enums.SCREEN.LICENSE_MODEL_OVERVIEW, {licenseModelId, version, status}); - }); - licenseModelOverviewActionHelper.selectVLMListView(dispatch, {buttonTab: null}); - }); - }, - navigateToLicenseAgreements(dispatch, {licenseModelId, version, status}) { - LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId, version}); - LicenseModelActionHelper.fetchLicenseModelById(dispatch, {licenseModelId, version}).then(() => { - setCurrentScreen(dispatch, enums.SCREEN.LICENSE_AGREEMENTS, {licenseModelId, version, status}); - }); - }, - - navigateToFeatureGroups(dispatch, {licenseModelId, version, status}) { - FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version}); - setCurrentScreen(dispatch, enums.SCREEN.FEATURE_GROUPS, {licenseModelId, version, status}); - }, - - navigateToEntitlementPools(dispatch, {licenseModelId, version, status}) { - EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}); - setCurrentScreen(dispatch, enums.SCREEN.ENTITLEMENT_POOLS, {licenseModelId, version, status}); - }, - - navigateToLicenseKeyGroups(dispatch, {licenseModelId, version, status}) { - LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}); - setCurrentScreen(dispatch, enums.SCREEN.LICENSE_KEY_GROUPS, {licenseModelId, version, status}); - }, - - navigateToLicenseModelActivityLog(dispatch, {licenseModelId, version, status}){ - ActivityLogActionHelper.fetchActivityLog(dispatch, {itemId: licenseModelId, versionId: version.id}); - setCurrentScreen(dispatch, enums.SCREEN.ACTIVITY_LOG, {licenseModelId, version, status}); - }, - - navigateToSoftwareProductLandingPage(dispatch, {softwareProductId, version, status}) { - SoftwareProductComponentsActionHelper.clearComponentsStore(dispatch); - SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version}).then(response => { - let {vendorId: licenseModelId, licensingVersion} = response[0]; - SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}); - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version: version}); - if(response[0].onboardingOrigin === onboardingOriginTypes.ZIP) { - SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version: version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, {softwareProductId, licenseModelId, version, status}); - }); - }, - - navigateToSoftwareProductDetails(dispatch, {softwareProductId, version, status}) { - SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version}).then(response => { - let {vendorId: licenseModelId, licensingVersion} = response[0]; - SoftwareProductActionHelper.loadLicensingVersionsList(dispatch, {licenseModelId}); - SoftwareProductActionHelper.loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, {softwareProductId, version, status}); - }); - }, - - navigateToSoftwareProductAttachmentsSetupTab(dispatch, {softwareProductId, version, status}) { - SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version}); - SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab: attachmentsTabsMapping.SETUP}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, {softwareProductId, version, status}); - }, - navigateToSoftwareProductAttachmentsValidationTab(dispatch, {softwareProductId, version, status}) { - SoftwareProductActionHelper.processAndValidateHeatCandidate(dispatch, {softwareProductId, version}).then(() => { - SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab: attachmentsTabsMapping.VALIDATION}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, {softwareProductId, version, status}); - }); - }, - - navigateToSoftwareProductProcesses(dispatch, {softwareProductId, version, status}) { - if (softwareProductId) { - SoftwareProductProcessesActionHelper.fetchProcessesList(dispatch, {softwareProductId, version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES, {softwareProductId, version, status}); - }, - - navigateToSoftwareProductNetworks(dispatch, {softwareProductId, version, status}) { - if (softwareProductId) { - SoftwareProductNetworksActionHelper.fetchNetworksList(dispatch, {softwareProductId, version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS, {softwareProductId, version, status}); - }, - - navigateToSoftwareProductDependencies(dispatch, {softwareProductId, version, status}) { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}).then(result => { - if(result.listCount >= 2) { - SoftwareProductDependenciesActionHelper.fetchDependencies(dispatch, {softwareProductId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES, {softwareProductId, version, status}); - } - else { - this.navigateToSoftwareProductLandingPage(dispatch, {softwareProductId, version, status}); - } - }); - }, - - navigateToSoftwareProductComponents(dispatch, {softwareProductId, version, status}) { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, {softwareProductId, version, status}); - }, - navigateToSoftwareProductDeployment(dispatch, {softwareProductId, version, status}) { - SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList(dispatch, {softwareProductId, version}); - ComputeFlavorActionHelper.fetchComputesListForVSP(dispatch, {softwareProductId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, {softwareProductId, version, status}); - }, - navigateToSoftwareProductActivityLog(dispatch, {softwareProductId, version, status}){ - ActivityLogActionHelper.fetchActivityLog(dispatch, {itemId: softwareProductId, versionId: version.id}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, {softwareProductId, version, status}); - }, - - navigateToSoftwareProductComponentProcesses(dispatch, {softwareProductId, componentId, version, status}) { - if (componentId && softwareProductId) { - SoftwareProductComponentProcessesActionHelper.fetchProcessesList(dispatch, {componentId, softwareProductId, version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, {softwareProductId, componentId, version, status}); - }, - - navigateToSoftwareProductComponentMonitoring(dispatch, {softwareProductId, version, componentId, status}){ - if (componentId && softwareProductId && version) { - SoftwareProductComponentsMonitoringAction.fetchExistingFiles(dispatch, {componentId, softwareProductId, version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING, {softwareProductId, componentId, version, status}); - }, - - navigateToComponentStorage(dispatch, {softwareProductId, componentId, version, status}) { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE, {softwareProductId, version, componentId, status}); - }, - - navigateToComponentCompute(dispatch, {softwareProductId, componentId, version, status}) { - 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, status}); - }, - - navigateToComponentNetwork(dispatch, {softwareProductId, componentId, version, status}) { - SoftwareProductComponentsNetworkActionHelper.fetchNICsList(dispatch, {softwareProductId, componentId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK, {softwareProductId, version, componentId, status}); - }, - - navigateToSoftwareProductComponentGeneral(dispatch, {softwareProductId, componentId, version, status}) { - if (componentId && softwareProductId) { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version}); - } - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL, {softwareProductId, version, componentId, status}); - }, - - navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel(dispatch, {softwareProductId, componentId, version, status}) { - this.navigateToSoftwareProductComponentGeneral(dispatch, {softwareProductId, componentId, version, status}); - dispatch({ - type: SoftwareProductActionTypes.TOGGLE_NAVIGATION_ITEM, - mapOfExpandedIds: { - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: true, - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + '|' + componentId]: true - } - }); - }, - - navigateToComponentLoadBalancing(dispatch, {softwareProductId, componentId, version, status}) { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent(dispatch, {softwareProductId, vspComponentId: componentId, version}); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, {softwareProductId, version, componentId, status}); - }, - - navigateToComponentImages(dispatch, {softwareProductId, componentId, version, status}) { - SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, { - softwareProductId, - componentId, - version - }); - setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES, {softwareProductId, version, componentId, status}); - }, - - navigateToVersionsPage(dispatch, {itemType, itemId, itemName, additionalProps, users}) { - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId, allUsers: users}); - VersionsPageActionHelper.selectNone(dispatch); - VersionsPageActionHelper.fetchVersions(dispatch, {itemType, itemId}).then(() => { - ItemsHelper.fetchItem(itemId).then(result => { - setCurrentScreen(dispatch, enums.SCREEN.VERSIONS_PAGE, {status: result.status, itemType, itemId, itemName, additionalProps}); - }); - - }); - - }, - - checkMergeStatus(dispatch, {itemId, versionId, version}) { - return ItemsHelper.fetchVersion({itemId, versionId}).then(response => { - let state = response && response.state || {}; - let {synchronizationState} = state; - // let inMerge = synchronizationState === SyncStates.MERGE; - MergeEditorActionHelper.fetchConflicts(dispatch, {itemId, version}).then(data => { - dispatch({ - type: actionTypes.CHECK_MERGE_STATUS, - synchronizationState, - conflictInfoList: data.conflictInfoList - }); - }); - }); - }, - - forceBreadCrumbsUpdate(dispatch) { - dispatch({ - type: actionTypes.SET_CURRENT_SCREEN, - currentScreen: { - forceBreadCrumbsUpdate: true - } - }); - }, - - updateCurrentScreenVersion(dispatch, version) { - dispatch({ - type: actionTypes.SET_CURRENT_SCREEN_VERSION, - version - }); - } + loadItemsLists(dispatch) { + LicenseModelActionHelper.fetchLicenseModels(dispatch); + LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch); + LicenseModelActionHelper.fetchArchivedLicenseModels(dispatch); + SoftwareProductActionHelper.fetchSoftwareProductList(dispatch); + SoftwareProductActionHelper.fetchFinalizedSoftwareProductList(dispatch); + SoftwareProductActionHelper.fetchArchivedSoftwareProductList(dispatch); + }, + + navigateToOnboardingCatalog(dispatch) { + UsersActionHelper.fetchUsersList(dispatch); + this.loadItemsLists(dispatch); + OnboardActionHelper.resetOnboardStore(dispatch); + setCurrentScreen(dispatch, enums.SCREEN.ONBOARDING_CATALOG); + }, + + autoSaveBeforeNavigate( + dispatch, + { softwareProductId, version, vspComponentId, dataToSave } + ) { + if (softwareProductId) { + if (vspComponentId) { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponent( + dispatch, + { + softwareProductId, + version, + vspComponentId, + componentData: dataToSave.componentData, + qdata: dataToSave.qdata + } + ); + } + return SoftwareProductActionHelper.updateSoftwareProduct(dispatch, { + softwareProduct: dataToSave.softwareProduct, + version, + qdata: dataToSave.qdata + }); + } + return Promise.resolve(); + }, + + navigateToLicenseModelOverview( + dispatch, + { licenseModelId, version, status } + ) { + /** + * TODO change to specific rest + */ + + LicenseModelActionHelper.fetchLicenseModelById(dispatch, { + licenseModelId, + version + }).then(() => { + LicenseModelActionHelper.fetchLicenseModelItems(dispatch, { + licenseModelId, + version + }).then(() => { + setCurrentScreen( + dispatch, + enums.SCREEN.LICENSE_MODEL_OVERVIEW, + { licenseModelId, version, status } + ); + }); + licenseModelOverviewActionHelper.selectVLMListView(dispatch, { + buttonTab: null + }); + }); + }, + navigateToLicenseAgreements(dispatch, { licenseModelId, version, status }) { + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, { + licenseModelId, + version + }); + LicenseModelActionHelper.fetchLicenseModelById(dispatch, { + licenseModelId, + version + }).then(() => { + setCurrentScreen(dispatch, enums.SCREEN.LICENSE_AGREEMENTS, { + licenseModelId, + version, + status + }); + }); + }, + + navigateToFeatureGroups(dispatch, { licenseModelId, version, status }) { + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId, + version + }); + setCurrentScreen(dispatch, enums.SCREEN.FEATURE_GROUPS, { + licenseModelId, + version, + status + }); + }, + + navigateToEntitlementPools(dispatch, { licenseModelId, version, status }) { + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, { + licenseModelId, + version + }); + setCurrentScreen(dispatch, enums.SCREEN.ENTITLEMENT_POOLS, { + licenseModelId, + version, + status + }); + }, + + navigateToLicenseKeyGroups(dispatch, { licenseModelId, version, status }) { + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, { + licenseModelId, + version + }); + setCurrentScreen(dispatch, enums.SCREEN.LICENSE_KEY_GROUPS, { + licenseModelId, + version, + status + }); + }, + + navigateToLicenseModelActivityLog( + dispatch, + { licenseModelId, version, status } + ) { + ActivityLogActionHelper.fetchActivityLog(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + setCurrentScreen(dispatch, enums.SCREEN.ACTIVITY_LOG, { + licenseModelId, + version, + status + }); + }, + + navigateToSoftwareProductLandingPage( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductComponentsActionHelper.clearComponentsStore(dispatch); + SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, { + softwareProductId, + version + }).then(response => { + let { vendorId: licenseModelId, licensingVersion } = response[0]; + SoftwareProductActionHelper.loadSoftwareProductDetailsData( + dispatch, + { licenseModelId, licensingVersion } + ); + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents( + dispatch, + { softwareProductId, version: version } + ); + if (response[0].onboardingOrigin === onboardingOriginTypes.ZIP) { + SoftwareProductActionHelper.loadSoftwareProductHeatCandidate( + dispatch, + { softwareProductId, version: version } + ); + } + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + { softwareProductId, licenseModelId, version, status } + ); + }); + }, + + navigateToSoftwareProductDetails( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, { + softwareProductId, + version + }).then(response => { + let { vendorId: licenseModelId, licensingVersion } = response[0]; + SoftwareProductActionHelper.loadLicensingVersionsList(dispatch, { + licenseModelId + }); + SoftwareProductActionHelper.loadSoftwareProductDetailsData( + dispatch, + { licenseModelId, licensingVersion } + ); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, { + softwareProductId, + version, + status + }); + }); + }, + + navigateToSoftwareProductAttachmentsSetupTab( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductActionHelper.loadSoftwareProductHeatCandidate(dispatch, { + softwareProductId, + version + }); + SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, { + activeTab: attachmentsTabsMapping.SETUP + }); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, { + softwareProductId, + version, + status + }); + }, + navigateToSoftwareProductAttachmentsValidationTab( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductActionHelper.processAndValidateHeatCandidate(dispatch, { + softwareProductId, + version + }).then(() => { + SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, { + activeTab: attachmentsTabsMapping.VALIDATION + }); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, + { softwareProductId, version, status } + ); + }); + }, + + navigateToSoftwareProductProcesses( + dispatch, + { softwareProductId, version, status } + ) { + if (softwareProductId) { + SoftwareProductProcessesActionHelper.fetchProcessesList(dispatch, { + softwareProductId, + version + }); + } + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES, { + softwareProductId, + version, + status + }); + }, + + navigateToSoftwareProductNetworks( + dispatch, + { softwareProductId, version, status } + ) { + if (softwareProductId) { + SoftwareProductNetworksActionHelper.fetchNetworksList(dispatch, { + softwareProductId, + version + }); + } + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS, { + softwareProductId, + version, + status + }); + }, + + navigateToSoftwareProductDependencies( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents( + dispatch, + { softwareProductId, version } + ).then(result => { + if (result.listCount >= 2) { + SoftwareProductDependenciesActionHelper.fetchDependencies( + dispatch, + { softwareProductId, version } + ); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES, + { softwareProductId, version, status } + ); + } else { + this.navigateToSoftwareProductLandingPage(dispatch, { + softwareProductId, + version, + status + }); + } + }); + }, + + navigateToSoftwareProductComponents( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents( + dispatch, + { softwareProductId, version } + ); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, { + softwareProductId, + version, + status + }); + }, + navigateToSoftwareProductDeployment( + dispatch, + { softwareProductId, version, status } + ) { + SoftwareProductDeploymentActionHelper.fetchDeploymentFlavorsList( + dispatch, + { softwareProductId, version } + ); + ComputeFlavorActionHelper.fetchComputesListForVSP(dispatch, { + softwareProductId, + version + }); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, { + softwareProductId, + version, + status + }); + }, + navigateToSoftwareProductActivityLog( + dispatch, + { softwareProductId, version, status } + ) { + ActivityLogActionHelper.fetchActivityLog(dispatch, { + itemId: softwareProductId, + versionId: version.id + }); + setCurrentScreen(dispatch, enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, { + softwareProductId, + version, + status + }); + }, + + navigateToSoftwareProductComponentProcesses( + dispatch, + { softwareProductId, componentId, version, status } + ) { + if (componentId && softwareProductId) { + SoftwareProductComponentProcessesActionHelper.fetchProcessesList( + dispatch, + { componentId, softwareProductId, version } + ); + } + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, + { softwareProductId, componentId, version, status } + ); + }, + + navigateToSoftwareProductComponentMonitoring( + dispatch, + { softwareProductId, version, componentId, status } + ) { + if (componentId && softwareProductId && version) { + SoftwareProductComponentsMonitoringAction.fetchExistingFiles( + dispatch, + { componentId, softwareProductId, version } + ); + } + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING, + { softwareProductId, componentId, version, status } + ); + }, + + navigateToComponentStorage( + dispatch, + { softwareProductId, componentId, version, status } + ) { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent( + dispatch, + { softwareProductId, vspComponentId: componentId, version } + ); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE, + { softwareProductId, version, componentId, status } + ); + }, + + navigateToComponentCompute( + dispatch, + { softwareProductId, componentId, version, status } + ) { + 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, status } + ); + }, + + navigateToComponentNetwork( + dispatch, + { softwareProductId, componentId, version, status } + ) { + SoftwareProductComponentsNetworkActionHelper.fetchNICsList(dispatch, { + softwareProductId, + componentId, + version + }); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK, + { softwareProductId, version, componentId, status } + ); + }, + + navigateToSoftwareProductComponentGeneral( + dispatch, + { softwareProductId, componentId, version, status } + ) { + if (componentId && softwareProductId) { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent( + dispatch, + { softwareProductId, vspComponentId: componentId, version } + ); + } + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL, + { softwareProductId, version, componentId, status } + ); + }, + + navigateToSoftwareProductComponentGeneralAndUpdateLeftPanel( + dispatch, + { softwareProductId, componentId, version, status } + ) { + this.navigateToSoftwareProductComponentGeneral(dispatch, { + softwareProductId, + componentId, + version, + status + }); + dispatch({ + type: SoftwareProductActionTypes.TOGGLE_NAVIGATION_ITEM, + mapOfExpandedIds: { + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS]: true, + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + + '|' + + componentId]: true + } + }); + }, + + navigateToComponentLoadBalancing( + dispatch, + { softwareProductId, componentId, version, status } + ) { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponent( + dispatch, + { softwareProductId, vspComponentId: componentId, version } + ); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, + { softwareProductId, version, componentId, status } + ); + }, + + navigateToComponentImages( + dispatch, + { softwareProductId, componentId, version, status } + ) { + SoftwareProductComponentsImageActionHelper.fetchImagesList(dispatch, { + softwareProductId, + componentId, + version + }); + setCurrentScreen( + dispatch, + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES, + { softwareProductId, version, componentId, status } + ); + }, + + navigateToVersionsPage( + dispatch, + { itemType, itemId, itemName, additionalProps, users } + ) { + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId, + allUsers: users + }); + VersionsPageActionHelper.selectNone(dispatch); + VersionsPageActionHelper.fetchVersions(dispatch, { + itemType, + itemId + }).then(() => { + ItemsHelper.fetchItem(itemId).then(result => { + setCurrentScreen(dispatch, enums.SCREEN.VERSIONS_PAGE, { + status: result.status, + itemType, + itemId, + itemName, + additionalProps + }); + }); + }); + }, + + checkMergeStatus(dispatch, { itemId, versionId, version }) { + return ItemsHelper.fetchVersion({ itemId, versionId }).then( + response => { + let state = (response && response.state) || {}; + let { synchronizationState } = state; + // let inMerge = synchronizationState === SyncStates.MERGE; + MergeEditorActionHelper.fetchConflicts(dispatch, { + itemId, + version + }).then(data => { + dispatch({ + type: actionTypes.CHECK_MERGE_STATUS, + synchronizationState, + conflictInfoList: data.conflictInfoList + }); + }); + } + ); + }, + + forceBreadCrumbsUpdate(dispatch) { + dispatch({ + type: actionTypes.SET_CURRENT_SCREEN, + currentScreen: { + forceBreadCrumbsUpdate: true + } + }); + }, + + updateCurrentScreenVersion(dispatch, version) { + dispatch({ + type: actionTypes.SET_CURRENT_SCREEN_VERSION, + version + }); + } }; export default OnboardingActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js index 699fe9e357..36054397d9 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingConstants.js @@ -18,83 +18,102 @@ 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, - SET_CURRENT_SCREEN_VERSION: null, - UPDATE_CURRENT_SCREEN_PROPS: null, - UPDATE_ITEM_STATUS: null + SET_CURRENT_SCREEN: null, + SET_CURRENT_LICENSE_MODEL: null, + SET_CURRENT_SCREEN_VERSION: null, + UPDATE_CURRENT_SCREEN_PROPS: null, + UPDATE_ITEM_STATUS: null }); export const screenTypes = keyMirror({ - LICENSE_MODEL: null, - SOFTWARE_PRODUCT: null, - SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL: null + LICENSE_MODEL: null, + SOFTWARE_PRODUCT: null, + SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL: null }); const breadcrumbsEnum = { - LICENSE_MODEL: 'LICENSE_MODEL', - VERSIONS_PAGE: 'VERSIONS_PAGE', - LICENSE_MODEL_OVERVIEW: 'LICENSE_MODEL_OVERVIEW', - LICENSE_AGREEMENTS: 'LICENSE_AGREEMENTS', - FEATURE_GROUPS: 'FEATURE_GROUPS', - ENTITLEMENT_POOLS: 'ENTITLEMENT_POOLS', - LICENSE_KEY_GROUPS: 'LICENSE_KEY_GROUPS', - ACTIVITY_LOG: 'ACTIVITY_LOG', + LICENSE_MODEL: 'LICENSE_MODEL', + VERSIONS_PAGE: 'VERSIONS_PAGE', + LICENSE_MODEL_OVERVIEW: 'LICENSE_MODEL_OVERVIEW', + LICENSE_AGREEMENTS: 'LICENSE_AGREEMENTS', + FEATURE_GROUPS: 'FEATURE_GROUPS', + ENTITLEMENT_POOLS: 'ENTITLEMENT_POOLS', + LICENSE_KEY_GROUPS: 'LICENSE_KEY_GROUPS', + ACTIVITY_LOG: 'ACTIVITY_LOG', - SOFTWARE_PRODUCT: 'SOFTWARE_PRODUCT', - SOFTWARE_PRODUCT_VERSIONS_PAGE: 'SOFTWARE_PRODUCT_VERSIONS_PAGE', - SOFTWARE_PRODUCT_LANDING_PAGE: 'SOFTWARE_PRODUCT_LANDING_PAGE', - 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', - SOFTWARE_PRODUCT_COMPONENTS: 'SOFTWARE_PRODUCT_COMPONENTS', - SOFTWARE_PRODUCT_COMPONENT_PROCESSES: 'SOFTWARE_PRODUCT_COMPONENT_PROCESSES', - SOFTWARE_PRODUCT_COMPONENT_NETWORK: 'SOFTWARE_PRODUCT_COMPONENT_NETWORK', - SOFTWARE_PRODUCT_COMPONENT_STORAGE: 'SOFTWARE_PRODUCT_COMPONENT_STORAGE', - 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_IMAGES: 'SOFTWARE_PRODUCT_COMPONENT_IMAGES' + SOFTWARE_PRODUCT: 'SOFTWARE_PRODUCT', + SOFTWARE_PRODUCT_VERSIONS_PAGE: 'SOFTWARE_PRODUCT_VERSIONS_PAGE', + SOFTWARE_PRODUCT_LANDING_PAGE: 'SOFTWARE_PRODUCT_LANDING_PAGE', + 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', + SOFTWARE_PRODUCT_COMPONENTS: 'SOFTWARE_PRODUCT_COMPONENTS', + SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + 'SOFTWARE_PRODUCT_COMPONENT_PROCESSES', + SOFTWARE_PRODUCT_COMPONENT_NETWORK: 'SOFTWARE_PRODUCT_COMPONENT_NETWORK', + SOFTWARE_PRODUCT_COMPONENT_STORAGE: 'SOFTWARE_PRODUCT_COMPONENT_STORAGE', + 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_IMAGES: 'SOFTWARE_PRODUCT_COMPONENT_IMAGES' }; export const enums = keyMirror({ + BREADCRUMS: { ...breadcrumbsEnum }, - BREADCRUMS: {...breadcrumbsEnum}, + SCREEN: { + ONBOARDING_CATALOG: 'ONBOARDING_CATALOG', + VERSIONS_PAGE: breadcrumbsEnum.VERSIONS_PAGE, + LICENSE_MODEL_OVERVIEW: breadcrumbsEnum.LICENSE_MODEL_OVERVIEW, + LICENSE_AGREEMENTS: breadcrumbsEnum.LICENSE_AGREEMENTS, + FEATURE_GROUPS: breadcrumbsEnum.FEATURE_GROUPS, + ENTITLEMENT_POOLS: breadcrumbsEnum.ENTITLEMENT_POOLS, + LICENSE_KEY_GROUPS: breadcrumbsEnum.LICENSE_KEY_GROUPS, + ACTIVITY_LOG: breadcrumbsEnum.ACTIVITY_LOG, - SCREEN: { - ONBOARDING_CATALOG: 'ONBOARDING_CATALOG', - VERSIONS_PAGE: breadcrumbsEnum.VERSIONS_PAGE, - LICENSE_MODEL_OVERVIEW: breadcrumbsEnum.LICENSE_MODEL_OVERVIEW, - LICENSE_AGREEMENTS: breadcrumbsEnum.LICENSE_AGREEMENTS, - FEATURE_GROUPS: breadcrumbsEnum.FEATURE_GROUPS, - ENTITLEMENT_POOLS: breadcrumbsEnum.ENTITLEMENT_POOLS, - LICENSE_KEY_GROUPS: breadcrumbsEnum.LICENSE_KEY_GROUPS, - ACTIVITY_LOG: breadcrumbsEnum.ACTIVITY_LOG, - - SOFTWARE_PRODUCT_VERSIONS_PAGE: breadcrumbsEnum.SOFTWARE_PRODUCT_VERSIONS_PAGE, - SOFTWARE_PRODUCT_LANDING_PAGE: breadcrumbsEnum.SOFTWARE_PRODUCT_LANDING_PAGE, - SOFTWARE_PRODUCT_DETAILS: breadcrumbsEnum.SOFTWARE_PRODUCT_DETAILS, - SOFTWARE_PRODUCT_ATTACHMENTS: breadcrumbsEnum.SOFTWARE_PRODUCT_ATTACHMENTS, - SOFTWARE_PRODUCT_ATTACHMENTS_SETUP: 'SOFTWARE_PRODUCT_ATTACHMENTS_SETUP', - SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION: 'SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION', - SOFTWARE_PRODUCT_PROCESSES: breadcrumbsEnum.SOFTWARE_PRODUCT_PROCESSES, - SOFTWARE_PRODUCT_DEPLOYMENT: breadcrumbsEnum.SOFTWARE_PRODUCT_DEPLOYMENT, - SOFTWARE_PRODUCT_NETWORKS: breadcrumbsEnum.SOFTWARE_PRODUCT_NETWORKS, - SOFTWARE_PRODUCT_DEPENDENCIES: breadcrumbsEnum.SOFTWARE_PRODUCT_DEPENDENCIES, - SOFTWARE_PRODUCT_ACTIVITY_LOG: breadcrumbsEnum.SOFTWARE_PRODUCT_ACTIVITY_LOG, - SOFTWARE_PRODUCT_COMPONENTS: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENTS, - SOFTWARE_PRODUCT_COMPONENT_PROCESSES: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, - SOFTWARE_PRODUCT_COMPONENT_COMPUTE: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, - SOFTWARE_PRODUCT_COMPONENT_STORAGE: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_STORAGE, - SOFTWARE_PRODUCT_COMPONENT_NETWORK: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_NETWORK, - SOFTWARE_PRODUCT_COMPONENT_GENERAL: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_GENERAL, - SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, - SOFTWARE_PRODUCT_COMPONENT_MONITORING: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_MONITORING, - SOFTWARE_PRODUCT_COMPONENT_IMAGES: breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_IMAGES - } + SOFTWARE_PRODUCT_VERSIONS_PAGE: + breadcrumbsEnum.SOFTWARE_PRODUCT_VERSIONS_PAGE, + SOFTWARE_PRODUCT_LANDING_PAGE: + breadcrumbsEnum.SOFTWARE_PRODUCT_LANDING_PAGE, + SOFTWARE_PRODUCT_DETAILS: breadcrumbsEnum.SOFTWARE_PRODUCT_DETAILS, + SOFTWARE_PRODUCT_ATTACHMENTS: + breadcrumbsEnum.SOFTWARE_PRODUCT_ATTACHMENTS, + SOFTWARE_PRODUCT_ATTACHMENTS_SETUP: + 'SOFTWARE_PRODUCT_ATTACHMENTS_SETUP', + SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION: + 'SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION', + SOFTWARE_PRODUCT_PROCESSES: breadcrumbsEnum.SOFTWARE_PRODUCT_PROCESSES, + SOFTWARE_PRODUCT_DEPLOYMENT: + breadcrumbsEnum.SOFTWARE_PRODUCT_DEPLOYMENT, + SOFTWARE_PRODUCT_NETWORKS: breadcrumbsEnum.SOFTWARE_PRODUCT_NETWORKS, + SOFTWARE_PRODUCT_DEPENDENCIES: + breadcrumbsEnum.SOFTWARE_PRODUCT_DEPENDENCIES, + SOFTWARE_PRODUCT_ACTIVITY_LOG: + breadcrumbsEnum.SOFTWARE_PRODUCT_ACTIVITY_LOG, + SOFTWARE_PRODUCT_COMPONENTS: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENTS, + SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, + SOFTWARE_PRODUCT_COMPONENT_COMPUTE: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, + SOFTWARE_PRODUCT_COMPONENT_STORAGE: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_STORAGE, + SOFTWARE_PRODUCT_COMPONENT_NETWORK: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_NETWORK, + SOFTWARE_PRODUCT_COMPONENT_GENERAL: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_GENERAL, + SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, + SOFTWARE_PRODUCT_COMPONENT_MONITORING: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_MONITORING, + SOFTWARE_PRODUCT_COMPONENT_IMAGES: + breadcrumbsEnum.SOFTWARE_PRODUCT_COMPONENT_IMAGES + } }); diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx index e04f9b7309..f462dd790b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingPunchOut.jsx @@ -16,7 +16,7 @@ import React from 'react'; -import {render} from 'react-dom'; +import { render } from 'react-dom'; import ReactDOM from 'react-dom'; import isEqual from 'lodash/isEqual.js'; @@ -29,460 +29,812 @@ import store from 'sdc-app/AppStore.js'; import Configuration from 'sdc-app/config/Configuration.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; +import { + onboardingMethod as onboardingMethodTypes, + onboardingOriginTypes +} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -import {onboardingMethod as onboardingMethodTypes, onboardingOriginTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { itemTypes } from './versionsPage/VersionsPageConstants.js'; -import {itemTypes} from './versionsPage/VersionsPageConstants.js'; - -import {AppContainer} from 'react-hot-loader'; +import { AppContainer } from 'react-hot-loader'; import HeatSetupActionHelper from './softwareProduct/attachments/setup/HeatSetupActionHelper.js'; -import {actionTypes, enums, screenTypes} from './OnboardingConstants.js'; +import { actionTypes, enums, screenTypes } from './OnboardingConstants.js'; import OnboardingActionHelper from './OnboardingActionHelper.js'; import Onboarding from './Onboarding.js'; export default class OnboardingPunchOut { - - render({options: {data, apiRoot, apiHeaders}, onEvent}, element) { - if (!this.unsubscribeFromStore) { - this.unsubscribeFromStore = store.subscribe(() => this.handleStoreChange()); - } - - if (!this.isConfigSet) { - Configuration.setCatalogApiRoot(apiRoot); - Configuration.setCatalogApiHeaders(apiHeaders); - this.isConfigSet = true; - } - - this.onEvent = (...args) => onEvent(...args); - this.handleData(data); - - if (!this.rendered) { - render( - <AppContainer> - <Application> - <Onboarding/> - </Application> - </AppContainer>, - element - ); - if (module.hot) { - module.hot.accept('sdc-app/onboarding/Onboarding.js', () => { - const NextOnboarding = require('sdc-app/onboarding/Onboarding.js').default; - render( - <AppContainer> - <Application> - <NextOnboarding/> - </Application> - </AppContainer>, - element - ); - }); - } - this.rendered = true; - } - } - - unmount(element) { - ReactDOM.unmountComponentAtNode(element); - this.rendered = false; - this.unsubscribeFromStore(); - this.unsubscribeFromStore = null; - } - - handleData(data) { - let {breadcrumbs: {selectedKeys = []} = {}} = data; - let dispatch = action => store.dispatch(action); - let {currentScreen, users: {usersList}, softwareProductList, finalizedSoftwareProductList, licenseModelList, finalizedLicenseModelList, - softwareProduct: {softwareProductEditor: {data: vspData = {}}, - softwareProductComponents = {}, softwareProductQuestionnaire = {}}, archivedLicenseModelList} = store.getState(); - const wholeSoftwareProductList = [...softwareProductList, ...finalizedSoftwareProductList]; - const wholeLicenseModelList = [...licenseModelList, ...finalizedLicenseModelList, ...archivedLicenseModelList]; - - let {props: {version, isReadOnlyMode}, screen} = currentScreen; - let {componentEditor: {data: componentData = {}, qdata: componentQData = {}}} = softwareProductComponents; - if (this.programmaticBreadcrumbsUpdate) { - this.prevSelectedKeys = selectedKeys; - this.programmaticBreadcrumbsUpdate = false; - return; - } - if (!isEqual(selectedKeys, this.prevSelectedKeys)) { - this.breadcrumbsPrefixSelected = isEqual(selectedKeys, this.prevSelectedKeys && this.prevSelectedKeys.slice(0, selectedKeys.length)); - - const [, screenType, prevVspId, , prevComponentId] = this.prevSelectedKeys || []; - let preNavigate = Promise.resolve(); - if(screenType === enums.BREADCRUMS.SOFTWARE_PRODUCT && screen !== 'VERSIONS_PAGE' && !isReadOnlyMode) { - let dataToSave = prevVspId ? prevComponentId ? {componentData, qdata: componentQData} : {softwareProduct: vspData, qdata: softwareProductQuestionnaire.qdata} : {}; - preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate(dispatch, { - softwareProductId: prevVspId, - version, - vspComponentId: prevComponentId, - dataToSave - }); - } - - let {currentScreen: {props: {softwareProductId}}, softwareProduct: {softwareProductAttachments: {heatSetup, heatSetupCache}}} = store.getState(); - let heatSetupPopupPromise = currentScreen.screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ? - HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) : - Promise.resolve(); - Promise.all([preNavigate, heatSetupPopupPromise]).then(() => { - this.prevSelectedKeys = selectedKeys; - if (selectedKeys.length === 0) { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.ONBOARDING_CATALOG}); - - } else if (selectedKeys.length === 1 || selectedKeys[1] === enums.BREADCRUMS.LICENSE_MODEL) { - let [licenseModelId, , licenseModelScreen] = selectedKeys; - let licenseModel = wholeLicenseModelList.find(vlm => vlm.id === licenseModelId); - ScreensHelper.loadScreen(dispatch, {screen: licenseModelScreen, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId, version, licenseModel, usersList}}); - - } else if (selectedKeys.length <= 4 && selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT) { - let [licenseModelId, , softwareProductId, softwareProductScreen] = selectedKeys; - let softwareProduct = softwareProductId ? - wholeSoftwareProductList.find(({id}) => id === softwareProductId) : - wholeSoftwareProductList.find(({vendorId}) => vendorId === licenseModelId); - if (!softwareProductId) { - softwareProductId = softwareProduct.id; - } - if (softwareProductScreen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS) { - softwareProduct = vspData; - //check current vsp fields to determine which file has uploaded - if(vspData.onboardingOrigin === onboardingOriginTypes.ZIP || vspData.candidateOnboardingOrigin === onboardingOriginTypes.ZIP) { - softwareProductScreen = enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP; - } - else if(vspData.onboardingOrigin === onboardingOriginTypes.CSAR) { - softwareProductScreen = enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION; - } - } - - ScreensHelper.loadScreen(dispatch, {screen: softwareProductScreen, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, softwareProduct, version, usersList}}); - - } else if (selectedKeys.length === 5 && selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT && selectedKeys[3] === enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS) { - let [licenseModelId, , softwareProductId, , componentId] = selectedKeys; - let softwareProduct = softwareProductId ? - wholeSoftwareProductList.find(({id}) => id === softwareProductId) : - wholeSoftwareProductList.find(({vendorId}) => vendorId === licenseModelId); - if (!softwareProductId) { - softwareProductId = softwareProduct.id; - } - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, softwareProduct, componentId, version, usersList}}); - - } else if (selectedKeys.length === 6 && selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT && selectedKeys[3] === enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS) { - let [licenseModelId, , softwareProductId, , componentId, componentScreen] = selectedKeys; - let softwareProduct = softwareProductId ? - wholeSoftwareProductList.find(({id}) => id === softwareProductId) : - wholeSoftwareProductList.find(({vendorId}) => vendorId === licenseModelId); - if (!softwareProductId) { - softwareProductId = softwareProduct.id; - } - ScreensHelper.loadScreen(dispatch, {screen: componentScreen, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, softwareProduct, componentId, version, usersList}}); - - } else { - console.error('Unknown breadcrumbs path: ', selectedKeys); - } - }).catch(() => { - store.dispatch({ - type: actionTypes.SET_CURRENT_SCREEN, - currentScreen: { - ...currentScreen, - forceBreadCrumbsUpdate: true - } - }); - }); - } - } - - handleStoreChange() { - let {currentScreen, licenseModelList, finalizedLicenseModelList, softwareProductList, finalizedSoftwareProductList, versionsPage: - {versionsList: {itemType, itemId}}, - softwareProduct: {softwareProductEditor: {data: currentSoftwareProduct = {onboardingMethod: ''}}, - softwareProductComponents: {componentsList}}, archivedLicenseModelList, archivedSoftwareProductList} = store.getState(); - const wholeSoftwareProductList = lodashUnionBy(softwareProductList, [...finalizedSoftwareProductList, ...archivedSoftwareProductList], 'id'); - const wholeLicenseModelList = lodashUnionBy(licenseModelList, [...finalizedLicenseModelList, ...archivedLicenseModelList], 'id'); - let breadcrumbsData = {itemType, itemId, currentScreen, wholeLicenseModelList, wholeSoftwareProductList, currentSoftwareProduct, componentsList}; - - if (currentScreen.forceBreadCrumbsUpdate || !isEqual(breadcrumbsData, this.prevBreadcrumbsData) || this.breadcrumbsPrefixSelected) { - this.prevBreadcrumbsData = breadcrumbsData; - this.breadcrumbsPrefixSelected = false; - this.programmaticBreadcrumbsUpdate = true; - let breadcrumbs = this.buildBreadcrumbs(breadcrumbsData); - this.onEvent('breadcrumbsupdated', breadcrumbs); - store.dispatch({ - type: actionTypes.SET_CURRENT_SCREEN, - currentScreen: { - ...currentScreen, - forceBreadCrumbsUpdate: false - } - }); - } - } - - buildBreadcrumbs({currentScreen: {screen, props}, itemType, itemId, currentSoftwareProduct, - wholeLicenseModelList, wholeSoftwareProductList, componentsList}) { - let {onboardingMethod, onboardingOrigin, candidateOnboardingOrigin} = currentSoftwareProduct; - let screenToBreadcrumb; - switch (screen) { - case enums.SCREEN.ONBOARDING_CATALOG: - return []; - - case enums.SCREEN.VERSIONS_PAGE: - let firstMenuItems = itemType === itemTypes.LICENSE_MODEL ? [ - { - selectedKey: itemId, - menuItems: wholeLicenseModelList.map(({id, name}) => ({ - key: id, - displayText: name - })) - }] : [ - { - selectedKey: props.additionalProps.licenseModelId || currentSoftwareProduct.vendorId, - menuItems: wholeLicenseModelList.map(({id, name}) => ({ - key: id, - displayText: name - })) - }, - { - selectedKey: enums.BREADCRUMS.SOFTWARE_PRODUCT, - menuItems: [{ - key: enums.BREADCRUMS.LICENSE_MODEL, - displayText: i18n('License Model') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT, - displayText: i18n('Software Products') - }] - }, - { - selectedKey: itemId, - menuItems: wholeSoftwareProductList - .filter(({id, vendorId}) => vendorId === currentSoftwareProduct.vendorId || id === itemId) - .map(({id, name}) => ({ - key: id, - displayText: name - })) - }, - ]; - return [ - ...firstMenuItems, - { - selectedKey: enums.BREADCRUMS.VERSIONS_PAGE, - menuItems: [{key: enums.BREADCRUMS.VERSIONS_PAGE, displayText: i18n('Versions Page')}] - } - ]; - - case enums.SCREEN.LICENSE_AGREEMENTS: - case enums.SCREEN.FEATURE_GROUPS: - case enums.SCREEN.ENTITLEMENT_POOLS: - case enums.SCREEN.LICENSE_KEY_GROUPS: - case enums.SCREEN.LICENSE_MODEL_OVERVIEW: - case enums.SCREEN.ACTIVITY_LOG: - screenToBreadcrumb = { - [enums.SCREEN.LICENSE_AGREEMENTS]: enums.BREADCRUMS.LICENSE_AGREEMENTS, - [enums.SCREEN.FEATURE_GROUPS]: enums.BREADCRUMS.FEATURE_GROUPS, - [enums.SCREEN.ENTITLEMENT_POOLS]: enums.BREADCRUMS.ENTITLEMENT_POOLS, - [enums.SCREEN.LICENSE_KEY_GROUPS]: enums.BREADCRUMS.LICENSE_KEY_GROUPS, - [enums.SCREEN.LICENSE_MODEL_OVERVIEW]: enums.BREADCRUMS.LICENSE_MODEL_OVERVIEW, - [enums.SCREEN.ACTIVITY_LOG]: enums.BREADCRUMS.ACTIVITY_LOG - }; - return [ - { - selectedKey: props.licenseModelId, - menuItems: wholeLicenseModelList.map(({id, name}) => ({ - key: id, - displayText: name - })) - }, - { - selectedKey: enums.BREADCRUMS.LICENSE_MODEL, - menuItems: [{ - key: enums.BREADCRUMS.LICENSE_MODEL, - displayText: i18n('License Model') - }, - ...(wholeSoftwareProductList.findIndex(({vendorId}) => vendorId === props.licenseModelId) === -1 ? [] : [{ - key: enums.BREADCRUMS.SOFTWARE_PRODUCT, - displayText: i18n('Software Products') - }])] - }, { - selectedKey: screenToBreadcrumb[screen], - menuItems: [{ - key: enums.BREADCRUMS.LICENSE_MODEL_OVERVIEW, - displayText: i18n('Overview') - },{ - key: enums.BREADCRUMS.LICENSE_AGREEMENTS, - displayText: i18n('License Agreements') - }, { - key: enums.BREADCRUMS.FEATURE_GROUPS, - displayText: i18n('Feature Groups') - }, { - key: enums.BREADCRUMS.ENTITLEMENT_POOLS, - displayText: i18n('Entitlement Pools') - }, { - key: enums.BREADCRUMS.LICENSE_KEY_GROUPS, - displayText: i18n('License Key Groups') - }, { - key: enums.BREADCRUMS.ACTIVITY_LOG, - displayText: i18n('Activity Log') - }] - } - ]; - - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - 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: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: - - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - 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_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, - [enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG]: enums.BREADCRUMS.SOFTWARE_PRODUCT_ACTIVITY_LOG - }; - let componentScreenToBreadcrumb = { - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, - [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE]: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE, - [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 = currentSoftwareProduct.vendorId; - let returnedBreadcrumb = [ - { - selectedKey: licenseModelId, - menuItems: wholeLicenseModelList.map(({id, name}) => ({ - key: id, - displayText: name - })) - }, - { - selectedKey: enums.BREADCRUMS.SOFTWARE_PRODUCT, - menuItems: [{ - key: enums.BREADCRUMS.LICENSE_MODEL, - displayText: i18n('License Model') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT, - displayText: i18n('Software Products') - }] - }, - { - selectedKey: props.softwareProductId, - menuItems: wholeSoftwareProductList - .filter(({vendorId, id}) => vendorId === licenseModelId || id === props.softwareProductId) - .map(({id, name}) => ({ - key: id, - displayText: name - })) - }, - ...(/*screen === enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE ? [] :*/ [{ - selectedKey: screenToBreadcrumb[screen] || enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS, - menuItems: [{ - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_LANDING_PAGE, - displayText: i18n('Overview') - }, { - 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') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_NETWORKS, - displayText: i18n('Networks') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES, - displayText: i18n('Components Dependencies') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS, - displayText: i18n('Attachments') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_ACTIVITY_LOG, - displayText: i18n('Activity Log') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS, - displayText: i18n('Components') - }].filter(item => { - switch (item.key) { - case enums.BREADCRUMS.SOFTWARE_PRODUCT_ATTACHMENTS: - let isHeatData = onboardingOrigin !== onboardingOriginTypes.NONE || candidateOnboardingOrigin === onboardingOriginTypes.ZIP; - return isHeatData; - case enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS: - return (componentsList.length > 0); - case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPLOYMENT: - let isManualMode = onboardingMethod === onboardingMethodTypes.MANUAL; - return isManualMode; - case enums.BREADCRUMS.SOFTWARE_PRODUCT_DEPENDENCIES: - return (componentsList.length > 1); - default: - return true; - } - }) - }]) - ]; - if(props.componentId) { - returnedBreadcrumb = [ - ...returnedBreadcrumb, { - selectedKey: props.componentId, - menuItems: componentsList - .map(({id, displayName}) => ({ - key: id, - displayText: displayName - })) - }, - ...[{ - selectedKey: componentScreenToBreadcrumb[screen], - menuItems: [{ - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_GENERAL, - displayText: i18n('General') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, - displayText: i18n('Compute') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, - displayText: i18n('High Availability & Load Balancing') - }, { - key: enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_NETWORK, - displayText: i18n('Networks') - }, { - 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') - }] - }] - ]; - } - return returnedBreadcrumb; - } - } + render({ options: { data, apiRoot, apiHeaders }, onEvent }, element) { + if (!this.unsubscribeFromStore) { + this.unsubscribeFromStore = store.subscribe(() => + this.handleStoreChange() + ); + } + + if (!this.isConfigSet) { + Configuration.setCatalogApiRoot(apiRoot); + Configuration.setCatalogApiHeaders(apiHeaders); + this.isConfigSet = true; + } + + this.onEvent = (...args) => onEvent(...args); + this.handleData(data); + + if (!this.rendered) { + render( + <AppContainer> + <Application> + <Onboarding /> + </Application> + </AppContainer>, + element + ); + if (module.hot) { + module.hot.accept('sdc-app/onboarding/Onboarding.js', () => { + const NextOnboarding = require('sdc-app/onboarding/Onboarding.js') + .default; + render( + <AppContainer> + <Application> + <NextOnboarding /> + </Application> + </AppContainer>, + element + ); + }); + } + this.rendered = true; + } + } + + unmount(element) { + ReactDOM.unmountComponentAtNode(element); + this.rendered = false; + this.unsubscribeFromStore(); + this.unsubscribeFromStore = null; + } + + handleData(data) { + let { breadcrumbs: { selectedKeys = [] } = {} } = data; + let dispatch = action => store.dispatch(action); + let { + currentScreen, + users: { usersList }, + softwareProductList, + finalizedSoftwareProductList, + licenseModelList, + finalizedLicenseModelList, + softwareProduct: { + softwareProductEditor: { data: vspData = {} }, + softwareProductComponents = {}, + softwareProductQuestionnaire = {} + }, + archivedLicenseModelList + } = store.getState(); + const wholeSoftwareProductList = [ + ...softwareProductList, + ...finalizedSoftwareProductList + ]; + const wholeLicenseModelList = [ + ...licenseModelList, + ...finalizedLicenseModelList, + ...archivedLicenseModelList + ]; + + let { props: { version, isReadOnlyMode }, screen } = currentScreen; + let { + componentEditor: { + data: componentData = {}, + qdata: componentQData = {} + } + } = softwareProductComponents; + if (this.programmaticBreadcrumbsUpdate) { + this.prevSelectedKeys = selectedKeys; + this.programmaticBreadcrumbsUpdate = false; + return; + } + if (!isEqual(selectedKeys, this.prevSelectedKeys)) { + this.breadcrumbsPrefixSelected = isEqual( + selectedKeys, + this.prevSelectedKeys && + this.prevSelectedKeys.slice(0, selectedKeys.length) + ); + + const [, screenType, prevVspId, , prevComponentId] = + this.prevSelectedKeys || []; + let preNavigate = Promise.resolve(); + if ( + screenType === enums.BREADCRUMS.SOFTWARE_PRODUCT && + screen !== 'VERSIONS_PAGE' && + !isReadOnlyMode + ) { + let dataToSave = prevVspId + ? prevComponentId + ? { componentData, qdata: componentQData } + : { + softwareProduct: vspData, + qdata: softwareProductQuestionnaire.qdata + } + : {}; + preNavigate = OnboardingActionHelper.autoSaveBeforeNavigate( + dispatch, + { + softwareProductId: prevVspId, + version, + vspComponentId: prevComponentId, + dataToSave + } + ); + } + + let { + currentScreen: { props: { softwareProductId } }, + softwareProduct: { + softwareProductAttachments: { heatSetup, heatSetupCache } + } + } = store.getState(); + let heatSetupPopupPromise = + currentScreen.screen === + enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS + ? HeatSetupActionHelper.heatSetupLeaveConfirmation( + dispatch, + { softwareProductId, heatSetup, heatSetupCache } + ) + : Promise.resolve(); + Promise.all([preNavigate, heatSetupPopupPromise]) + .then(() => { + this.prevSelectedKeys = selectedKeys; + if (selectedKeys.length === 0) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.ONBOARDING_CATALOG + }); + } else if ( + selectedKeys.length === 1 || + selectedKeys[1] === enums.BREADCRUMS.LICENSE_MODEL + ) { + let [ + licenseModelId, + , + licenseModelScreen + ] = selectedKeys; + let licenseModel = wholeLicenseModelList.find( + vlm => vlm.id === licenseModelId + ); + ScreensHelper.loadScreen(dispatch, { + screen: licenseModelScreen, + screenType: screenTypes.LICENSE_MODEL, + props: { + licenseModelId, + version, + licenseModel, + usersList + } + }); + } else if ( + selectedKeys.length <= 4 && + selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT + ) { + let [ + licenseModelId, + , + softwareProductId, + softwareProductScreen + ] = selectedKeys; + let softwareProduct = softwareProductId + ? wholeSoftwareProductList.find( + ({ id }) => id === softwareProductId + ) + : wholeSoftwareProductList.find( + ({ vendorId }) => vendorId === licenseModelId + ); + if (!softwareProductId) { + softwareProductId = softwareProduct.id; + } + if ( + softwareProductScreen === + enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS + ) { + softwareProduct = vspData; + //check current vsp fields to determine which file has uploaded + if ( + vspData.onboardingOrigin === + onboardingOriginTypes.ZIP || + vspData.candidateOnboardingOrigin === + onboardingOriginTypes.ZIP + ) { + softwareProductScreen = + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP; + } else if ( + vspData.onboardingOrigin === + onboardingOriginTypes.CSAR + ) { + softwareProductScreen = + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION; + } + } + + ScreensHelper.loadScreen(dispatch, { + screen: softwareProductScreen, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct, + version, + usersList + } + }); + } else if ( + selectedKeys.length === 5 && + selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT && + selectedKeys[3] === + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS + ) { + let [ + licenseModelId, + , + softwareProductId, + , + componentId + ] = selectedKeys; + let softwareProduct = softwareProductId + ? wholeSoftwareProductList.find( + ({ id }) => id === softwareProductId + ) + : wholeSoftwareProductList.find( + ({ vendorId }) => vendorId === licenseModelId + ); + if (!softwareProductId) { + softwareProductId = softwareProduct.id; + } + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct, + componentId, + version, + usersList + } + }); + } else if ( + selectedKeys.length === 6 && + selectedKeys[1] === enums.BREADCRUMS.SOFTWARE_PRODUCT && + selectedKeys[3] === + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS + ) { + let [ + licenseModelId, + , + softwareProductId, + , + componentId, + componentScreen + ] = selectedKeys; + let softwareProduct = softwareProductId + ? wholeSoftwareProductList.find( + ({ id }) => id === softwareProductId + ) + : wholeSoftwareProductList.find( + ({ vendorId }) => vendorId === licenseModelId + ); + if (!softwareProductId) { + softwareProductId = softwareProduct.id; + } + ScreensHelper.loadScreen(dispatch, { + screen: componentScreen, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct, + componentId, + version, + usersList + } + }); + } else { + console.error( + 'Unknown breadcrumbs path: ', + selectedKeys + ); + } + }) + .catch(() => { + store.dispatch({ + type: actionTypes.SET_CURRENT_SCREEN, + currentScreen: { + ...currentScreen, + forceBreadCrumbsUpdate: true + } + }); + }); + } + } + + handleStoreChange() { + let { + currentScreen, + licenseModelList, + finalizedLicenseModelList, + softwareProductList, + finalizedSoftwareProductList, + versionsPage: { versionsList: { itemType, itemId } }, + softwareProduct: { + softwareProductEditor: { + data: currentSoftwareProduct = { onboardingMethod: '' } + }, + softwareProductComponents: { componentsList } + }, + archivedLicenseModelList, + archivedSoftwareProductList + } = store.getState(); + const wholeSoftwareProductList = lodashUnionBy( + softwareProductList, + [...finalizedSoftwareProductList, ...archivedSoftwareProductList], + 'id' + ); + const wholeLicenseModelList = lodashUnionBy( + licenseModelList, + [...finalizedLicenseModelList, ...archivedLicenseModelList], + 'id' + ); + let breadcrumbsData = { + itemType, + itemId, + currentScreen, + wholeLicenseModelList, + wholeSoftwareProductList, + currentSoftwareProduct, + componentsList + }; + + if ( + currentScreen.forceBreadCrumbsUpdate || + !isEqual(breadcrumbsData, this.prevBreadcrumbsData) || + this.breadcrumbsPrefixSelected + ) { + this.prevBreadcrumbsData = breadcrumbsData; + this.breadcrumbsPrefixSelected = false; + this.programmaticBreadcrumbsUpdate = true; + let breadcrumbs = this.buildBreadcrumbs(breadcrumbsData); + this.onEvent('breadcrumbsupdated', breadcrumbs); + store.dispatch({ + type: actionTypes.SET_CURRENT_SCREEN, + currentScreen: { + ...currentScreen, + forceBreadCrumbsUpdate: false + } + }); + } + } + + buildBreadcrumbs({ + currentScreen: { screen, props }, + itemType, + itemId, + currentSoftwareProduct, + wholeLicenseModelList, + wholeSoftwareProductList, + componentsList + }) { + let { + onboardingMethod, + onboardingOrigin, + candidateOnboardingOrigin + } = currentSoftwareProduct; + let screenToBreadcrumb; + switch (screen) { + case enums.SCREEN.ONBOARDING_CATALOG: + return []; + + case enums.SCREEN.VERSIONS_PAGE: + let firstMenuItems = + itemType === itemTypes.LICENSE_MODEL + ? [ + { + selectedKey: itemId, + menuItems: wholeLicenseModelList.map( + ({ id, name }) => ({ + key: id, + displayText: name + }) + ) + } + ] + : [ + { + selectedKey: + props.additionalProps.licenseModelId || + currentSoftwareProduct.vendorId, + menuItems: wholeLicenseModelList.map( + ({ id, name }) => ({ + key: id, + displayText: name + }) + ) + }, + { + selectedKey: + enums.BREADCRUMS.SOFTWARE_PRODUCT, + menuItems: [ + { + key: enums.BREADCRUMS.LICENSE_MODEL, + displayText: i18n('License Model') + }, + { + key: + enums.BREADCRUMS.SOFTWARE_PRODUCT, + displayText: i18n('Software Products') + } + ] + }, + { + selectedKey: itemId, + menuItems: wholeSoftwareProductList + .filter( + ({ id, vendorId }) => + vendorId === + currentSoftwareProduct.vendorId || + id === itemId + ) + .map(({ id, name }) => ({ + key: id, + displayText: name + })) + } + ]; + return [ + ...firstMenuItems, + { + selectedKey: enums.BREADCRUMS.VERSIONS_PAGE, + menuItems: [ + { + key: enums.BREADCRUMS.VERSIONS_PAGE, + displayText: i18n('Versions Page') + } + ] + } + ]; + + case enums.SCREEN.LICENSE_AGREEMENTS: + case enums.SCREEN.FEATURE_GROUPS: + case enums.SCREEN.ENTITLEMENT_POOLS: + case enums.SCREEN.LICENSE_KEY_GROUPS: + case enums.SCREEN.LICENSE_MODEL_OVERVIEW: + case enums.SCREEN.ACTIVITY_LOG: + screenToBreadcrumb = { + [enums.SCREEN.LICENSE_AGREEMENTS]: + enums.BREADCRUMS.LICENSE_AGREEMENTS, + [enums.SCREEN.FEATURE_GROUPS]: + enums.BREADCRUMS.FEATURE_GROUPS, + [enums.SCREEN.ENTITLEMENT_POOLS]: + enums.BREADCRUMS.ENTITLEMENT_POOLS, + [enums.SCREEN.LICENSE_KEY_GROUPS]: + enums.BREADCRUMS.LICENSE_KEY_GROUPS, + [enums.SCREEN.LICENSE_MODEL_OVERVIEW]: + enums.BREADCRUMS.LICENSE_MODEL_OVERVIEW, + [enums.SCREEN.ACTIVITY_LOG]: enums.BREADCRUMS.ACTIVITY_LOG + }; + return [ + { + selectedKey: props.licenseModelId, + menuItems: wholeLicenseModelList.map( + ({ id, name }) => ({ + key: id, + displayText: name + }) + ) + }, + { + selectedKey: enums.BREADCRUMS.LICENSE_MODEL, + menuItems: [ + { + key: enums.BREADCRUMS.LICENSE_MODEL, + displayText: i18n('License Model') + }, + ...(wholeSoftwareProductList.findIndex( + ({ vendorId }) => + vendorId === props.licenseModelId + ) === -1 + ? [] + : [ + { + key: + enums.BREADCRUMS.SOFTWARE_PRODUCT, + displayText: i18n('Software Products') + } + ]) + ] + }, + { + selectedKey: screenToBreadcrumb[screen], + menuItems: [ + { + key: enums.BREADCRUMS.LICENSE_MODEL_OVERVIEW, + displayText: i18n('Overview') + }, + { + key: enums.BREADCRUMS.LICENSE_AGREEMENTS, + displayText: i18n('License Agreements') + }, + { + key: enums.BREADCRUMS.FEATURE_GROUPS, + displayText: i18n('Feature Groups') + }, + { + key: enums.BREADCRUMS.ENTITLEMENT_POOLS, + displayText: i18n('Entitlement Pools') + }, + { + key: enums.BREADCRUMS.LICENSE_KEY_GROUPS, + displayText: i18n('License Key Groups') + }, + { + key: enums.BREADCRUMS.ACTIVITY_LOG, + displayText: i18n('Activity Log') + } + ] + } + ]; + + case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: + 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: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: + + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + 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_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, + [enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG]: + enums.BREADCRUMS.SOFTWARE_PRODUCT_ACTIVITY_LOG + }; + let componentScreenToBreadcrumb = { + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES]: + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_PROCESSES, + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE]: + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_COMPUTE, + [enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE]: + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENT_STORAGE, + [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 = currentSoftwareProduct.vendorId; + let returnedBreadcrumb = [ + { + selectedKey: licenseModelId, + menuItems: wholeLicenseModelList.map( + ({ id, name }) => ({ + key: id, + displayText: name + }) + ) + }, + { + selectedKey: enums.BREADCRUMS.SOFTWARE_PRODUCT, + menuItems: [ + { + key: enums.BREADCRUMS.LICENSE_MODEL, + displayText: i18n('License Model') + }, + { + key: enums.BREADCRUMS.SOFTWARE_PRODUCT, + displayText: i18n('Software Products') + } + ] + }, + { + selectedKey: props.softwareProductId, + menuItems: wholeSoftwareProductList + .filter( + ({ vendorId, id }) => + vendorId === licenseModelId || + id === props.softwareProductId + ) + .map(({ id, name }) => ({ + key: id, + displayText: name + })) + }, + .../*screen === enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE ? [] :*/ [ + { + selectedKey: + screenToBreadcrumb[screen] || + enums.BREADCRUMS.SOFTWARE_PRODUCT_COMPONENTS, + menuItems: [ + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_LANDING_PAGE, + displayText: i18n('Overview') + }, + { + 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') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_NETWORKS, + displayText: i18n('Networks') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_DEPENDENCIES, + displayText: i18n('Components Dependencies') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_ATTACHMENTS, + displayText: i18n('Attachments') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_ACTIVITY_LOG, + displayText: i18n('Activity Log') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENTS, + displayText: i18n('Components') + } + ].filter(item => { + switch (item.key) { + case enums.BREADCRUMS + .SOFTWARE_PRODUCT_ATTACHMENTS: + let isHeatData = + onboardingOrigin !== + onboardingOriginTypes.NONE || + candidateOnboardingOrigin === + onboardingOriginTypes.ZIP; + return isHeatData; + case enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENTS: + return componentsList.length > 0; + case enums.BREADCRUMS + .SOFTWARE_PRODUCT_DEPLOYMENT: + let isManualMode = + onboardingMethod === + onboardingMethodTypes.MANUAL; + return isManualMode; + case enums.BREADCRUMS + .SOFTWARE_PRODUCT_DEPENDENCIES: + return componentsList.length > 1; + default: + return true; + } + }) + } + ] + ]; + if (props.componentId) { + returnedBreadcrumb = [ + ...returnedBreadcrumb, + { + selectedKey: props.componentId, + menuItems: componentsList.map( + ({ id, displayName }) => ({ + key: id, + displayText: displayName + }) + ) + }, + ...[ + { + selectedKey: + componentScreenToBreadcrumb[screen], + menuItems: [ + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENT_GENERAL, + displayText: i18n('General') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENT_COMPUTE, + displayText: i18n('Compute') + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING, + displayText: i18n( + 'High Availability & Load Balancing' + ) + }, + { + key: + enums.BREADCRUMS + .SOFTWARE_PRODUCT_COMPONENT_NETWORK, + displayText: i18n('Networks') + }, + { + 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') + } + ] + } + ] + ]; + } + return returnedBreadcrumb; + } + } } diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducers.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducers.js index 16c0e61491..9abae2d1c1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducers.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducers.js @@ -13,130 +13,159 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, enums} from './OnboardingConstants.js'; -import {actionTypes as permissionActionTypes} from './permissions/PermissionsConstants.js'; -import {actionTypes as licenseModelCreateActionTypes} from './licenseModel/creation/LicenseModelCreationConstants.js'; -import {actionTypes as softwareProductCreateActionTypes} from './softwareProduct/creation/SoftwareProductCreationConstants.js'; -import {actionTypes as versionCreateActionTypes} from './versionsPage/creation/VersionsPageCreationConstants.js'; -import {SyncStates} from 'sdc-app/common/merge/MergeEditorConstants.js'; - -import {catalogItemStatuses} from './onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { actionTypes, enums } from './OnboardingConstants.js'; +import { actionTypes as permissionActionTypes } from './permissions/PermissionsConstants.js'; +import { actionTypes as licenseModelCreateActionTypes } from './licenseModel/creation/LicenseModelCreationConstants.js'; +import { actionTypes as softwareProductCreateActionTypes } from './softwareProduct/creation/SoftwareProductCreationConstants.js'; +import { actionTypes as versionCreateActionTypes } from './versionsPage/creation/VersionsPageCreationConstants.js'; +import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js'; + +import { catalogItemStatuses } from './onboard/onboardingCatalog/OnboardingCatalogConstants.js'; import Configuration from 'sdc-app/config/Configuration.js'; -const checkReadOnly = ({isCollaborator = true, inMerge = false, isCertified = false, isArchived = false}) => !isCollaborator || inMerge || isCertified || isArchived; - -const currentScreen = (state = { - forceBreadCrumbsUpdate: false, - screen: enums.SCREEN.ONBOARDING_CATALOG, - itemPermission: {}, - props: {} -}, action) => { - - switch (action.type) { - - case actionTypes.SET_CURRENT_SCREEN: { - let itemPermission = {...state.itemPermission}; - let {currentScreen} = action; - itemPermission.isArchived = currentScreen.props.status === catalogItemStatuses.ARCHIVED; - - if (currentScreen.props.version) { - let {status} = currentScreen.props.version; - itemPermission.isCertified = itemPermission.isCertified && status === catalogItemStatuses.CERTIFIED; - } - - let isReadOnlyMode = checkReadOnly(itemPermission); - let props = {...currentScreen.props, isReadOnlyMode}; - - return { - ...state, - ...currentScreen, - itemPermission, - props - }; - } - - case actionTypes.UPDATE_CURRENT_SCREEN_PROPS: - return { - ...state, - props: { - ...state.props, - ...action.props, - isReadOnlyMode: checkReadOnly(state.itemPermission) - } - }; - - case actionTypes.SET_CURRENT_SCREEN_VERSION: - return { - ...state, - props: { - ...state.props, - version: action.version, - isReadOnlyMode: checkReadOnly({...state.itemPermission,itemStatus: state.props.status}) - } - }; - - case licenseModelCreateActionTypes.LICENSE_MODEL_CREATED: - case softwareProductCreateActionTypes.SOFTWARE_PRODUCT_CREATED: - case versionCreateActionTypes.VERSION_CREATED: - return { - ...state, - itemPermission: { - isCollaborator: true, - inMerge: false, - isCertified: false - }, - props: { - ...state.props, - isReadOnlyMode: false - } - }; - - case permissionActionTypes.ITEM_USERS_LOADED: { - let userId = Configuration.get('UserID'); - let isCollaborator = false; - - if (userId === action.owner.userId) { - isCollaborator = true; - } else { - isCollaborator = action.contributors.reduce( - (foundUser, contributor) => foundUser || contributor.userId === userId, false - ); - } - - let itemPermission = {...state.itemPermission, isCollaborator}; - let isReadOnlyMode = checkReadOnly(itemPermission); - let props = {...state.props, isReadOnlyMode}; - - return { - ...state, - itemPermission, - props - }; - } - - case actionTypes.UPDATE_ITEM_STATUS: { - const {itemState: {synchronizationState, dirty}, itemStatus, updatedVersion, archivedStatus} = action; - const inMerge = synchronizationState === SyncStates.MERGE; - const isOutOfSync = synchronizationState === SyncStates.OUT_OF_SYNC; - const isUpToDate = synchronizationState === SyncStates.UP_TO_DATE; - const isCertified = itemStatus === catalogItemStatuses.CERTIFIED; - const isArchived = archivedStatus === catalogItemStatuses.ARCHIVED; - const itemPermission = {...state.itemPermission, inMerge, isDirty: dirty, isOutOfSync, isUpToDate, isCertified, isArchived}; - const isReadOnlyMode = checkReadOnly(itemPermission); - const props = {...state.props, isReadOnlyMode, version: {...state.props.version, ...updatedVersion}}; - - return { - ...state, - itemPermission, - props - }; - } - - default: - return state; - - } - +const checkReadOnly = ({ + isCollaborator = true, + inMerge = false, + isCertified = false, + isArchived = false +}) => !isCollaborator || inMerge || isCertified || isArchived; + +const currentScreen = ( + state = { + forceBreadCrumbsUpdate: false, + screen: enums.SCREEN.ONBOARDING_CATALOG, + itemPermission: {}, + props: {} + }, + action +) => { + switch (action.type) { + case actionTypes.SET_CURRENT_SCREEN: { + let itemPermission = { ...state.itemPermission }; + let { currentScreen } = action; + itemPermission.isArchived = + currentScreen.props.status === catalogItemStatuses.ARCHIVED; + + if (currentScreen.props.version) { + let { status } = currentScreen.props.version; + itemPermission.isCertified = + itemPermission.isCertified && + status === catalogItemStatuses.CERTIFIED; + } + + let isReadOnlyMode = checkReadOnly(itemPermission); + let props = { ...currentScreen.props, isReadOnlyMode }; + + return { + ...state, + ...currentScreen, + itemPermission, + props + }; + } + + case actionTypes.UPDATE_CURRENT_SCREEN_PROPS: + return { + ...state, + props: { + ...state.props, + ...action.props, + isReadOnlyMode: checkReadOnly(state.itemPermission) + } + }; + + case actionTypes.SET_CURRENT_SCREEN_VERSION: + return { + ...state, + props: { + ...state.props, + version: action.version, + isReadOnlyMode: checkReadOnly({ + ...state.itemPermission, + itemStatus: state.props.status + }) + } + }; + + case licenseModelCreateActionTypes.LICENSE_MODEL_CREATED: + case softwareProductCreateActionTypes.SOFTWARE_PRODUCT_CREATED: + case versionCreateActionTypes.VERSION_CREATED: + return { + ...state, + itemPermission: { + isCollaborator: true, + inMerge: false, + isCertified: false + }, + props: { + ...state.props, + isReadOnlyMode: false + } + }; + + case permissionActionTypes.ITEM_USERS_LOADED: { + let userId = Configuration.get('UserID'); + let isCollaborator = false; + + if (userId === action.owner.userId) { + isCollaborator = true; + } else { + isCollaborator = action.contributors.reduce( + (foundUser, contributor) => + foundUser || contributor.userId === userId, + false + ); + } + + let itemPermission = { ...state.itemPermission, isCollaborator }; + let isReadOnlyMode = checkReadOnly(itemPermission); + let props = { ...state.props, isReadOnlyMode }; + + return { + ...state, + itemPermission, + props + }; + } + + case actionTypes.UPDATE_ITEM_STATUS: { + const { + itemState: { synchronizationState, dirty }, + itemStatus, + updatedVersion, + archivedStatus + } = action; + const inMerge = synchronizationState === SyncStates.MERGE; + const isOutOfSync = synchronizationState === SyncStates.OUT_OF_SYNC; + const isUpToDate = synchronizationState === SyncStates.UP_TO_DATE; + const isCertified = itemStatus === catalogItemStatuses.CERTIFIED; + const isArchived = archivedStatus === catalogItemStatuses.ARCHIVED; + const itemPermission = { + ...state.itemPermission, + inMerge, + isDirty: dirty, + isOutOfSync, + isUpToDate, + isCertified, + isArchived + }; + const isReadOnlyMode = checkReadOnly(itemPermission); + const props = { + ...state.props, + isReadOnlyMode, + version: { ...state.props.version, ...updatedVersion } + }; + + return { + ...state, + itemPermission, + props + }; + } + + default: + return state; + } }; export default currentScreen; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js index 5b678b1d43..3b526a67f6 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingReducersMap.js @@ -30,19 +30,19 @@ import revisionsReducer from './revisions/RevisionsReducer.js'; import featuresReducer from 'sdc-app/features/FeaturesReducer.js'; export default { - currentScreen: currentScreenReducer, - licenseModel: licenseModelReducer, - licenseModelList: licenseModelListReducer, - archivedLicenseModelList: archivedLicenseModelListReducer, - archivedSoftwareProductList: archivedSoftwareProductListReducer, - finalizedLicenseModelList: finalizedLicenseModelListReducer, - finalizedSoftwareProductList: finalizedSoftwareProductReducer, - mergeEditor: mergeEditorReducer, - onboard: onboardReducer, - softwareProduct: softwareProductReducer, - softwareProductList: softwareProductListReducer, - users: usersReducer, - versionsPage: versionsPageReducer, - revisions: revisionsReducer, - features: featuresReducer + currentScreen: currentScreenReducer, + licenseModel: licenseModelReducer, + licenseModelList: licenseModelListReducer, + archivedLicenseModelList: archivedLicenseModelListReducer, + archivedSoftwareProductList: archivedSoftwareProductListReducer, + finalizedLicenseModelList: finalizedLicenseModelListReducer, + finalizedSoftwareProductList: finalizedSoftwareProductReducer, + mergeEditor: mergeEditorReducer, + onboard: onboardReducer, + softwareProduct: softwareProductReducer, + softwareProductList: softwareProductListReducer, + users: usersReducer, + versionsPage: versionsPageReducer, + revisions: revisionsReducer, + features: featuresReducer }; diff --git a/openecomp-ui/src/sdc-app/onboarding/OnboardingView.jsx b/openecomp-ui/src/sdc-app/onboarding/OnboardingView.jsx index 7877085316..69e514bc6e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/OnboardingView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/OnboardingView.jsx @@ -25,8 +25,8 @@ import FeatureGroupListEditor from './licenseModel/featureGroups/FeatureGroupLis import LicenseKeyGroupsListEditor from './licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js'; import EntitlementPoolsListEditor from './licenseModel/entitlementPools/EntitlementPoolsListEditor.js'; import SoftwareProduct from './softwareProduct/SoftwareProduct.js'; -import SoftwareProductLandingPage from './softwareProduct/landingPage/SoftwareProductLandingPage.js'; -import SoftwareProductDetails from './softwareProduct/details/SoftwareProductDetails.js'; +import SoftwareProductLandingPage from './softwareProduct/landingPage/SoftwareProductLandingPage.js'; +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'; @@ -48,136 +48,243 @@ import PropTypes from 'prop-types'; import React from 'react'; import ReactDOM from 'react-dom'; -import {enums} from './OnboardingConstants.js'; +import { enums } from './OnboardingConstants.js'; export default class OnboardingView extends React.Component { - static propTypes = { - currentScreen: PropTypes.shape({ - screen: PropTypes.oneOf(objectValues(enums.SCREEN)).isRequired, - props: PropTypes.object.isRequired, - itemPermission: PropTypes.object - }).isRequired - }; + static propTypes = { + currentScreen: PropTypes.shape({ + screen: PropTypes.oneOf(objectValues(enums.SCREEN)).isRequired, + props: PropTypes.object.isRequired, + itemPermission: PropTypes.object + }).isRequired + }; - componentDidMount() { - let element = ReactDOM.findDOMNode(this); - element.addEventListener('click', event => { - if (event.target.tagName === 'A') { - event.preventDefault(); - } - }); - ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => - element.addEventListener(eventType, event => event.stopPropagation()) - ); - } + componentDidMount() { + let element = ReactDOM.findDOMNode(this); + element.addEventListener('click', event => { + if (event.target.tagName === 'A') { + event.preventDefault(); + } + }); + ['wheel', 'mousewheel', 'DOMMouseScroll'].forEach(eventType => + element.addEventListener(eventType, event => + event.stopPropagation() + ) + ); + } - render() { - let {currentScreen} = this.props; - let {screen, props} = currentScreen; + render() { + let { currentScreen } = this.props; + let { screen, props } = currentScreen; - return ( - <div className='dox-ui dox-ui-punch-out dox-ui-punch-out-full-page'> - {(() => { - switch (screen) { - case enums.SCREEN.ONBOARDING_CATALOG: - return <Onboard {...props}/>; - case enums.SCREEN.VERSIONS_PAGE: - return <VersionsPage {...props} />; + return ( + <div className="dox-ui dox-ui-punch-out dox-ui-punch-out-full-page"> + {(() => { + switch (screen) { + case enums.SCREEN.ONBOARDING_CATALOG: + return <Onboard {...props} />; + case enums.SCREEN.VERSIONS_PAGE: + return <VersionsPage {...props} />; - case enums.SCREEN.LICENSE_AGREEMENTS: - case enums.SCREEN.FEATURE_GROUPS: - case enums.SCREEN.ENTITLEMENT_POOLS: - case enums.SCREEN.LICENSE_KEY_GROUPS: - case enums.SCREEN.LICENSE_MODEL_OVERVIEW: - case enums.SCREEN.ACTIVITY_LOG: - return ( - <LicenseModel currentScreen={currentScreen}> - { - (()=>{ - switch(screen) { - case enums.SCREEN.LICENSE_MODEL_OVERVIEW: - return <LicenseModelOverview {...props}/>; - case enums.SCREEN.LICENSE_AGREEMENTS: - return <LicenseAgreementListEditor {...props}/>; - case enums.SCREEN.FEATURE_GROUPS: - return <FeatureGroupListEditor {...props}/>; - case enums.SCREEN.ENTITLEMENT_POOLS: - return <EntitlementPoolsListEditor {...props}/>; - case enums.SCREEN.LICENSE_KEY_GROUPS: - return <LicenseKeyGroupsListEditor {...props}/>; - case enums.SCREEN.ACTIVITY_LOG: - return <ActivityLog {...props}/>; - } - })() - } - </LicenseModel> - ); + case enums.SCREEN.LICENSE_AGREEMENTS: + case enums.SCREEN.FEATURE_GROUPS: + case enums.SCREEN.ENTITLEMENT_POOLS: + case enums.SCREEN.LICENSE_KEY_GROUPS: + case enums.SCREEN.LICENSE_MODEL_OVERVIEW: + case enums.SCREEN.ACTIVITY_LOG: + return ( + <LicenseModel currentScreen={currentScreen}> + {(() => { + switch (screen) { + case enums.SCREEN + .LICENSE_MODEL_OVERVIEW: + return ( + <LicenseModelOverview + {...props} + /> + ); + case enums.SCREEN + .LICENSE_AGREEMENTS: + return ( + <LicenseAgreementListEditor + {...props} + /> + ); + case enums.SCREEN.FEATURE_GROUPS: + return ( + <FeatureGroupListEditor + {...props} + /> + ); + case enums.SCREEN.ENTITLEMENT_POOLS: + return ( + <EntitlementPoolsListEditor + {...props} + /> + ); + case enums.SCREEN + .LICENSE_KEY_GROUPS: + return ( + <LicenseKeyGroupsListEditor + {...props} + /> + ); + case enums.SCREEN.ACTIVITY_LOG: + return ( + <ActivityLog {...props} /> + ); + } + })()} + </LicenseModel> + ); - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - 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: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: - 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 ( - <SoftwareProduct currentScreen={currentScreen}> - { - (()=>{ - switch(screen) { - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - return <SoftwareProductLandingPage {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: - return <SoftwareProductDetails {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: - 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: - return <SoftwareProductDependencies {...props} />; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS: - return <SoftwareProductComponentsList {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: - return <SoftwareProductComponentProcessesList {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: - return <SoftwareProductComponentStorage {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: - return <SoftwareProductComponentsNetworkList {...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: - return <SoftwareProductComponentsGeneral{...props}/>; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE: - 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: - return <ActivityLog {...props}/>; - } - })() - } - </SoftwareProduct> - ); - } - })()} - </div> - ); - } + case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: + 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: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE: + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK: + 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 ( + <SoftwareProduct currentScreen={currentScreen}> + {(() => { + switch (screen) { + case enums.SCREEN + .SOFTWARE_PRODUCT_LANDING_PAGE: + return ( + <SoftwareProductLandingPage + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_DETAILS: + return ( + <SoftwareProductDetails + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS: + 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: + return ( + <SoftwareProductDependencies + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENTS: + return ( + <SoftwareProductComponentsList + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENT_PROCESSES: + return ( + <SoftwareProductComponentProcessesList + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENT_STORAGE: + return ( + <SoftwareProductComponentStorage + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENT_NETWORK: + return ( + <SoftwareProductComponentsNetworkList + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENT_GENERAL: + return ( + <SoftwareProductComponentsGeneral + {...props} + /> + ); + case enums.SCREEN + .SOFTWARE_PRODUCT_COMPONENT_COMPUTE: + 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: + return ( + <ActivityLog {...props} /> + ); + } + })()} + </SoftwareProduct> + ); + } + })()} + </div> + ); + } } - diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/ArchivedLicenseModelListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/ArchivedLicenseModelListReducer.js index 8e4750e666..d5563f41ba 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/ArchivedLicenseModelListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/ArchivedLicenseModelListReducer.js @@ -13,13 +13,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {actionTypes} from './LicenseModelConstants.js'; +import { actionTypes } from './LicenseModelConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.ARCHIVED_LICENSE_MODELS_LIST_LOADED: - return [...action.response.results]; - default: - return state; - } + switch (action.type) { + case actionTypes.ARCHIVED_LICENSE_MODELS_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js index cc9d9c536d..b5c2bff4ba 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/FinalizedLicenseModelListReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './LicenseModelConstants.js'; +import { actionTypes } from './LicenseModelConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED: - return [...action.response.results]; - default: - return state; - } + switch (action.type) { + case actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js index c390ecc9b0..cea369d2ec 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModel.js @@ -4,173 +4,220 @@ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at - * + * * http://www.apache.org/licenses/LICENSE-2.0 - * + * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT 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 { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import PermissionsActionHelper from './../permissions/PermissionsActionHelper.js'; import RevisionsActionHelper from './../revisions/RevisionsActionHelper.js'; import LicenseModelActionHelper from './LicenseModelActionHelper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {CommitModalType} from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; const buildNavigationBarProps = (licenseModel, screen) => { - const {id, vendorName, version} = licenseModel; - const meta = {version}; - - const groups = [{ - id, - name: vendorName, - items: [ - { - id: enums.SCREEN.LICENSE_MODEL_OVERVIEW, - name: i18n('Overview'), - meta - }, - { - id: enums.SCREEN.LICENSE_AGREEMENTS, - name: i18n('License Agreements'), - meta - }, - { - id: enums.SCREEN.FEATURE_GROUPS, - name: i18n('Feature Groups'), - meta - }, - { - id: enums.SCREEN.ENTITLEMENT_POOLS, - name: i18n('Entitlement Pools'), - meta - }, - { - id: enums.SCREEN.LICENSE_KEY_GROUPS, - name: i18n('License Key Groups'), - meta - }, - { - id: enums.SCREEN.ACTIVITY_LOG, - name: i18n('Activity Log'), - meta - } - ] - }]; - - return { - activeItemId: screen, groups - }; + const { id, vendorName, version } = licenseModel; + const meta = { version }; + + const groups = [ + { + id, + name: vendorName, + items: [ + { + id: enums.SCREEN.LICENSE_MODEL_OVERVIEW, + name: i18n('Overview'), + meta + }, + { + id: enums.SCREEN.LICENSE_AGREEMENTS, + name: i18n('License Agreements'), + meta + }, + { + id: enums.SCREEN.FEATURE_GROUPS, + name: i18n('Feature Groups'), + meta + }, + { + id: enums.SCREEN.ENTITLEMENT_POOLS, + name: i18n('Entitlement Pools'), + meta + }, + { + id: enums.SCREEN.LICENSE_KEY_GROUPS, + name: i18n('License Key Groups'), + meta + }, + { + id: enums.SCREEN.ACTIVITY_LOG, + name: i18n('Activity Log'), + meta + } + ] + } + ]; + + return { + activeItemId: screen, + groups + }; }; - const buildVersionControllerProps = ({ - licenseModelEditor = {data: {}}, - versions, - currentVersion, - userInfo, - usersList, - permissions, - isArchived, - itemPermission, - isReadOnlyMode + licenseModelEditor = { data: {} }, + versions, + currentVersion, + userInfo, + usersList, + permissions, + isArchived, + itemPermission, + isReadOnlyMode }) => { - const {isValidityData = true} = licenseModelEditor; - return { - version: currentVersion, - viewableVersions: versions, - isFormDataValid: isValidityData, - permissions, - userInfo, - usersList, - isArchived, - itemName: licenseModelEditor.data.vendorName, - itemPermission, - isReadOnlyMode - }; + const { isValidityData = true } = licenseModelEditor; + return { + version: currentVersion, + viewableVersions: versions, + isFormDataValid: isValidityData, + permissions, + userInfo, + usersList, + isArchived, + itemName: licenseModelEditor.data.vendorName, + itemPermission, + isReadOnlyMode + }; }; - -const mapStateToProps = ({ - users: {userInfo, usersList}, - licenseModel: {licenseModelEditor}, - versionsPage: {permissions, versionsList: {versions, itemName}} -}, { - currentScreen: {screen, itemPermission, props: {isReadOnlyMode, version: currentVersion}} -}) => { - return { - versionControllerProps: buildVersionControllerProps({ - licenseModelEditor, - versions, - currentVersion, - userInfo, - permissions, - usersList, - isArchived: itemPermission.isArchived, - itemPermission, - isReadOnlyMode - }), - navigationBarProps: buildNavigationBarProps(licenseModelEditor.data, screen) - }; +const mapStateToProps = ( + { + users: { userInfo, usersList }, + licenseModel: { licenseModelEditor }, + versionsPage: { permissions, versionsList: { versions } } + }, + { + currentScreen: { + screen, + itemPermission, + props: { isReadOnlyMode, version: currentVersion } + } + } +) => { + return { + versionControllerProps: buildVersionControllerProps({ + licenseModelEditor, + versions, + currentVersion, + userInfo, + permissions, + usersList, + isArchived: itemPermission.isArchived, + itemPermission, + isReadOnlyMode + }), + navigationBarProps: buildNavigationBarProps( + licenseModelEditor.data, + screen + ) + }; }; - -const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {licenseModelId, version}}}) => { - - return { - onVersionControllerAction: (action, version, comment) => - LicenseModelActionHelper.performVCAction(dispatch, {licenseModelId, action, version, comment}).then(updatedVersion => { - ScreensHelper.loadScreen(dispatch, {screen, screenType: screenTypes.LICENSE_MODEL, props: {licenseModelId, version: updatedVersion}}); - }), - - onOpenCommentCommitModal: ({onCommit, title}) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.COMMIT_COMMENT, - modalComponentProps: { - onCommit, - type: CommitModalType.COMMIT - }, - title - } - }), - - onVersionSwitching: version => { - ScreensHelper.loadScreen(dispatch, {screen, screenType: screenTypes.LICENSE_MODEL, props: {licenseModelId, version}}); - }, - - onManagePermissions() { - PermissionsActionHelper.openPermissonsManager(dispatch, {itemId: licenseModelId, askForRights: false}); - }, - - onMoreVersionsClick: ({itemName, users}) => { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.VERSIONS_PAGE, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId, licenseModel: {name: itemName}, usersList: users}}); - }, - - onOpenPermissions: ({users}) => { - return PermissionsActionHelper.fetchItemUsers(dispatch, {itemId: licenseModelId, allUsers: users}); - }, - - onOpenRevisionsModal: () => { - return RevisionsActionHelper.openRevisionsView(dispatch, {itemId: licenseModelId, version: version, itemType: screenTypes.LICENSE_MODEL}); - }, - - onNavigate: ({id}) => { - ScreensHelper.loadScreen(dispatch, {screen: id, screenType: screenTypes.LICENSE_MODEL, props: {licenseModelId, version}}); - } - }; +const mapActionsToProps = ( + dispatch, + { currentScreen: { screen, props: { licenseModelId, version } } } +) => { + return { + onVersionControllerAction: (action, version, comment) => + LicenseModelActionHelper.performVCAction(dispatch, { + licenseModelId, + action, + version, + comment + }).then(updatedVersion => { + ScreensHelper.loadScreen(dispatch, { + screen, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId, version: updatedVersion } + }); + }), + + onOpenCommentCommitModal: ({ onCommit, title }) => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMMIT_COMMENT, + modalComponentProps: { + onCommit, + type: CommitModalType.COMMIT + }, + title + } + }), + + onVersionSwitching: version => { + ScreensHelper.loadScreen(dispatch, { + screen, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId, version } + }); + }, + + onManagePermissions() { + PermissionsActionHelper.openPermissonsManager(dispatch, { + itemId: licenseModelId, + askForRights: false + }); + }, + + onMoreVersionsClick: ({ itemName, users }) => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.VERSIONS_PAGE, + screenType: screenTypes.LICENSE_MODEL, + props: { + licenseModelId, + licenseModel: { name: itemName }, + usersList: users + } + }); + }, + + onOpenPermissions: ({ users }) => { + return PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId: licenseModelId, + allUsers: users + }); + }, + + onOpenRevisionsModal: () => { + return RevisionsActionHelper.openRevisionsView(dispatch, { + itemId: licenseModelId, + version: version, + itemType: screenTypes.LICENSE_MODEL + }); + }, + + onNavigate: ({ id }) => { + ScreensHelper.loadScreen(dispatch, { + screen: id, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId, version } + }); + } + }; }; export default connect(mapStateToProps, mapActionsToProps)(TabulatedEditor); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js index d1d3a77d92..cfff9f1fcd 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js @@ -15,195 +15,279 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './LicenseModelConstants.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {actionsEnum as vcActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import { actionTypes } from './LicenseModelConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionsEnum as vcActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import LicenseAgreementActionHelper from './licenseAgreement/LicenseAgreementActionHelper.js'; import FeatureGroupsActionHelper from './featureGroups/FeatureGroupsActionHelper.js'; import EntitlementPoolsActionHelper from './entitlementPools/EntitlementPoolsActionHelper.js'; import LicenseKeyGroupsActionHelper from './licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; -import {default as ItemsHelper} from 'sdc-app/common/helpers/ItemsHelper.js'; +import { default as ItemsHelper } from 'sdc-app/common/helpers/ItemsHelper.js'; import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {CommitModalType} from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import {itemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; -import {catalogItemStatuses} from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; -import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-license-models/`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/`; } function fetchLicenseModels() { - return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}`); + return RestAPIUtil.fetch( + `${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}` + ); } function fetchFinalizedLicenseModels() { - return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}`); + return RestAPIUtil.fetch( + `${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}` + ); } function fetchArchivedLicenseModels() { - return RestAPIUtil.fetch(`${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}`); + return RestAPIUtil.fetch( + `${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}` + ); } function fetchLicenseModelById(licenseModelId, version) { - const {id: versionId} = version; - return RestAPIUtil.fetch(`${baseUrl()}${licenseModelId}/versions/${versionId}`); + const { id: versionId } = version; + return RestAPIUtil.fetch( + `${baseUrl()}${licenseModelId}/versions/${versionId}` + ); } function putLicenseModel(licenseModel) { - let {id, vendorName, description, iconRef, version: {id: versionId}} = licenseModel; - return RestAPIUtil.put(`${baseUrl()}${id}/versions/${versionId}`, { - vendorName, - description, - iconRef - }); + let { + id, + vendorName, + description, + iconRef, + version: { id: versionId } + } = licenseModel; + return RestAPIUtil.put(`${baseUrl()}${id}/versions/${versionId}`, { + vendorName, + description, + iconRef + }); } -function putLicenseModelAction({itemId, action, version}) { - const {id: versionId} = version; - return RestAPIUtil.put(`${baseUrl()}${itemId}/versions/${versionId}/actions`, {action: action}); +function putLicenseModelAction({ itemId, action, version }) { + const { id: versionId } = version; + return RestAPIUtil.put( + `${baseUrl()}${itemId}/versions/${versionId}/actions`, + { action: action } + ); } const LicenseModelActionHelper = { + fetchLicenseModels(dispatch) { + return fetchLicenseModels().then(response => { + dispatch({ + type: actionTypes.LICENSE_MODELS_LIST_LOADED, + response + }); + }); + }, - fetchLicenseModels(dispatch) { - return fetchLicenseModels().then(response => { - dispatch({ - type: actionTypes.LICENSE_MODELS_LIST_LOADED, - response - }); - }); - }, + fetchFinalizedLicenseModels(dispatch) { + return fetchFinalizedLicenseModels().then(response => + dispatch({ + type: actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED, + response + }) + ); + }, - fetchFinalizedLicenseModels(dispatch) { - return fetchFinalizedLicenseModels().then(response => dispatch({ - type: actionTypes.FINALIZED_LICENSE_MODELS_LIST_LOADED, - response - })); + fetchArchivedLicenseModels(dispatch) { + return fetchArchivedLicenseModels().then(response => + dispatch({ + type: actionTypes.ARCHIVED_LICENSE_MODELS_LIST_LOADED, + response + }) + ); + }, - }, + fetchLicenseModelById(dispatch, { licenseModelId, version }) { + return fetchLicenseModelById(licenseModelId, version).then(response => { + dispatch({ + type: actionTypes.LICENSE_MODEL_LOADED, + response: { ...response, version } + }); + }); + }, - fetchArchivedLicenseModels(dispatch) { - return fetchArchivedLicenseModels().then(response => dispatch({ - type: actionTypes.ARCHIVED_LICENSE_MODELS_LIST_LOADED, - response - })); + fetchLicenseModelItems(dispatch, { licenseModelId, version }) { + return Promise.all([ + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, { + licenseModelId, + version + }), + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId, + version + }), + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, { + licenseModelId, + version + }), + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, { + licenseModelId, + version + }) + ]); + }, - }, + manageSubmitAction(dispatch, { licenseModelId, version, isDirty }) { + if (isDirty) { + const onCommit = comment => { + return this.performVCAction(dispatch, { + licenseModelId, + action: vcActionsEnum.COMMIT, + version, + comment + }).then(() => { + return this.performSubmitAction(dispatch, { + licenseModelId, + version + }); + }); + }; + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMMIT_COMMENT, + modalComponentProps: { + onCommit, + type: CommitModalType.COMMIT_SUBMIT + }, + title: i18n('Commit & Submit') + } + }); + return Promise.reject(); + } + return this.performSubmitAction(dispatch, { licenseModelId, version }); + }, - fetchLicenseModelById(dispatch, {licenseModelId, version}) { + performSubmitAction(dispatch, { licenseModelId, version }) { + return putLicenseModelAction({ + itemId: licenseModelId, + action: vcActionsEnum.SUBMIT, + version + }).then(() => { + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }).then(updatedVersion => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SUCCESS, + data: { + title: i18n('Submit Succeeded'), + msg: i18n('This license model successfully submitted'), + cancelButtonText: i18n('OK'), + timeout: 2000 + } + }); + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: licenseModelId + }); + return Promise.resolve(updatedVersion); + }); + }); + }, - return fetchLicenseModelById(licenseModelId, version).then(response => { - dispatch({ - type: actionTypes.LICENSE_MODEL_LOADED, - response: {...response, version} - }); - }); - }, - - fetchLicenseModelItems(dispatch, {licenseModelId, version}) { - return Promise.all([ - LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId, version}), - FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version}), - EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}), - LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}) - ]); - }, - - manageSubmitAction(dispatch, {licenseModelId, version, isDirty}) { - if(isDirty) { - const onCommit = comment => { - return this.performVCAction(dispatch, {licenseModelId, action: vcActionsEnum.COMMIT, version, comment}).then(() => { - return this.performSubmitAction(dispatch, {licenseModelId, version}); - }); - }; - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.COMMIT_COMMENT, - modalComponentProps: { - onCommit, - type: CommitModalType.COMMIT_SUBMIT - }, - title: i18n('Commit & Submit') - } - }); - return Promise.reject(); - } - return this.performSubmitAction(dispatch, {licenseModelId, version}); - }, - - performSubmitAction(dispatch, {licenseModelId, version}) { - return putLicenseModelAction({itemId: licenseModelId, action: vcActionsEnum.SUBMIT, version}).then(() => { - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}).then(updatedVersion => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SUCCESS, - data: { - title: i18n('Submit Succeeded'), - msg: i18n('This license model successfully submitted'), - cancelButtonText: i18n('OK'), - timeout: 2000 - } - }); - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: licenseModelId}); - return Promise.resolve(updatedVersion); - }); - }); - }, - - performVCAction(dispatch, {licenseModelId, action, version, comment}) { - return MergeEditorActionHelper.analyzeSyncResult(dispatch, {itemId: licenseModelId, version}).then(({inMerge, isDirty, updatedVersion}) => { - if ( (updatedVersion.status === catalogItemStatuses.CERTIFIED || updatedVersion.archivedStatus === catalogItemStatuses.ARCHIVED) && - (action === VersionControllerActionsEnum.COMMIT || action === VersionControllerActionsEnum.SYNC)) { - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: licenseModelId}); - const msg = updatedVersion.archivedStatus === catalogItemStatuses.ARCHIVED ? i18n('Item was Archived') : i18n('Item version already Certified'); - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Commit error'), - msg, - cancelButtonText: i18n('Cancel') - } - }); - return Promise.resolve(updatedVersion); - } - if (!inMerge) { - if(action === vcActionsEnum.SUBMIT) { - return this.manageSubmitAction(dispatch, {licenseModelId, version, isDirty}); - } - else { - return ItemsHelper.performVCAction({itemId: licenseModelId, action, version, comment}).then(() => { - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: licenseModelId}); - if (action === vcActionsEnum.SYNC) { - return MergeEditorActionHelper.analyzeSyncResult(dispatch, {itemId: licenseModelId, version}).then(({updatedVersion}) => { - return Promise.resolve(updatedVersion); - }); - } else { - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - } - }); - } - } - }); - }, - - saveLicenseModel(dispatch, {licenseModel}) { - return putLicenseModel(licenseModel).then(() => { - dispatch({ - type: actionTypes.LICENSE_MODEL_LOADED, - response: licenseModel - }); - const {id, version: {id: versionId}} = licenseModel; - return ItemsHelper.checkItemStatus(dispatch, {itemId: id, versionId}).then(updatedVersion => { - if (updatedVersion.status !== licenseModel.version.status) { - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: licenseModel.id}); - } - }); - }); - } + performVCAction(dispatch, { licenseModelId, action, version, comment }) { + return MergeEditorActionHelper.analyzeSyncResult(dispatch, { + itemId: licenseModelId, + version + }).then(({ inMerge, isDirty, updatedVersion }) => { + if ( + (updatedVersion.status === catalogItemStatuses.CERTIFIED || + updatedVersion.archivedStatus === + catalogItemStatuses.ARCHIVED) && + (action === VersionControllerActionsEnum.COMMIT || + action === VersionControllerActionsEnum.SYNC) + ) { + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: licenseModelId + }); + const msg = + updatedVersion.archivedStatus === + catalogItemStatuses.ARCHIVED + ? i18n('Item was Archived') + : i18n('Item version already Certified'); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Commit error'), + msg, + cancelButtonText: i18n('Cancel') + } + }); + return Promise.resolve(updatedVersion); + } + if (!inMerge) { + if (action === vcActionsEnum.SUBMIT) { + return this.manageSubmitAction(dispatch, { + licenseModelId, + version, + isDirty + }); + } else { + return ItemsHelper.performVCAction({ + itemId: licenseModelId, + action, + version, + comment + }).then(() => { + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: licenseModelId + }); + if (action === vcActionsEnum.SYNC) { + return MergeEditorActionHelper.analyzeSyncResult( + dispatch, + { itemId: licenseModelId, version } + ).then(({ updatedVersion }) => { + return Promise.resolve(updatedVersion); + }); + } else { + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + } + }); + } + } + }); + }, + saveLicenseModel(dispatch, { licenseModel }) { + return putLicenseModel(licenseModel).then(() => { + dispatch({ + type: actionTypes.LICENSE_MODEL_LOADED, + response: licenseModel + }); + const { id, version: { id: versionId } } = licenseModel; + return ItemsHelper.checkItemStatus(dispatch, { + itemId: id, + versionId + }).then(updatedVersion => { + if (updatedVersion.status !== licenseModel.version.status) { + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: licenseModel.id + }); + } + }); + }); + } }; export default LicenseModelActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js index 08009ee305..d97f682535 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelConstants.js @@ -17,23 +17,22 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; export const actionTypes = keyMirror({ - LICENSE_MODEL_LOADED: null, - LICENSE_MODELS_LIST_LOADED: null, - FINALIZED_LICENSE_MODELS_LIST_LOADED: null, - ARCHIVED_LICENSE_MODELS_LIST_LOADED: null, - EDIT_LICENSE_MODEL: null + LICENSE_MODEL_LOADED: null, + LICENSE_MODELS_LIST_LOADED: null, + FINALIZED_LICENSE_MODELS_LIST_LOADED: null, + ARCHIVED_LICENSE_MODELS_LIST_LOADED: null, + EDIT_LICENSE_MODEL: null }); - export const thresholdUnitType = { - ABSOLUTE: 'Absolute', - PERCENTAGE: 'Percentage' + ABSOLUTE: 'Absolute', + PERCENTAGE: 'Percentage' }; export const optionsInputValues = { - THRESHOLD_UNITS: [ - {enum: '', title: i18n('please select…')}, - {enum: thresholdUnitType.ABSOLUTE, title: 'Absolute'}, - {enum: thresholdUnitType.PERCENTAGE, title: '%'} - ] -};
\ No newline at end of file + THRESHOLD_UNITS: [ + { enum: '', title: i18n('please select…') }, + { enum: thresholdUnitType.ABSOLUTE, title: 'Absolute' }, + { enum: thresholdUnitType.PERCENTAGE, title: '%' } + ] +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js index add5ac6a98..2d27679283 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelEditorReducer.js @@ -13,16 +13,16 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './LicenseModelConstants.js'; +import { actionTypes } from './LicenseModelConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.LICENSE_MODEL_LOADED: - return { - ...state, - data: action.response - }; - default: - return state; - } + switch (action.type) { + case actionTypes.LICENSE_MODEL_LOADED: + return { + ...state, + data: action.response + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js index 36a190a39c..00d669c7d1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelListReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './LicenseModelConstants.js'; +import { actionTypes } from './LicenseModelConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.LICENSE_MODELS_LIST_LOADED: - return [...action.response.results]; - default: - return state; - } + switch (action.type) { + case actionTypes.LICENSE_MODELS_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js index f635532348..f102d286f0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelReducer.js @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {combineReducers} from 'redux'; +import { combineReducers } from 'redux'; import activityLogReducer from 'sdc-app/common/activity-log/ActivityLogReducer.js'; @@ -32,56 +32,75 @@ import entitlementPoolsEditorReducer from './entitlementPools/EntitlementPoolsEd import licenseKeyGroupsEditorReducer from './licenseKeyGroups/LicenseKeyGroupsEditorReducer.js'; import licenseKeyGroupsListReducer from './licenseKeyGroups/LicenseKeyGroupsListReducer.js'; -import {createPlainDataReducer} from 'sdc-app/common/reducers/PlainDataReducer.js'; +import { createPlainDataReducer } from 'sdc-app/common/reducers/PlainDataReducer.js'; -import {actionTypes as licenseModelOverviewConstants, VLM_DESCRIPTION_FORM} from './overview/LicenseModelOverviewConstants.js'; -import limitEditorReducer from './limits/LimitEditorReducer.js'; +import { + actionTypes as licenseModelOverviewConstants, + VLM_DESCRIPTION_FORM +} from './overview/LicenseModelOverviewConstants.js'; +import limitEditorReducer from './limits/LimitEditorReducer.js'; export default combineReducers({ - licenseModelCreation: createPlainDataReducer(licenseModelCreationReducer), - licenseModelEditor: licenseModelEditorReducer, + licenseModelCreation: createPlainDataReducer(licenseModelCreationReducer), + licenseModelEditor: licenseModelEditorReducer, - licenseAgreement: combineReducers({ - licenseAgreementEditor: createPlainDataReducer(licenseAgreementEditorReducer), - licenseAgreementList: licenseAgreementListReducer - }), - featureGroup: combineReducers({ - featureGroupEditor: createPlainDataReducer(featureGroupsEditorReducer), - featureGroupsList: featureGroupsListReducer - }), - entitlementPool: combineReducers({ - entitlementPoolEditor: createPlainDataReducer(entitlementPoolsEditorReducer), - entitlementPoolsList: entitlementPoolsListReducer - }), - licenseKeyGroup: combineReducers({ - licenseKeyGroupsEditor: createPlainDataReducer(licenseKeyGroupsEditorReducer), - licenseKeyGroupsList: licenseKeyGroupsListReducer - }), - licenseModelOverview: combineReducers({ - selectedTab: (state = null, action) => action.type === licenseModelOverviewConstants.LICENSE_MODEL_OVERVIEW_TAB_SELECTED ? action.buttonTab : state, - descriptionEditor: createPlainDataReducer(function(state = false, action) { - if (action.type === licenseModelOverviewConstants.LM_DATA_CHANGED) { - return { - ...state, - data : { - description : action.description - }, - formReady: null, - formName: VLM_DESCRIPTION_FORM, - genericFieldInfo: { - 'description': { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 1000}] - } - } - }; - //return action.description; - } else { - return state; - } - } - )}), - limitEditor: createPlainDataReducer(limitEditorReducer), - activityLog: activityLogReducer + licenseAgreement: combineReducers({ + licenseAgreementEditor: createPlainDataReducer( + licenseAgreementEditorReducer + ), + licenseAgreementList: licenseAgreementListReducer + }), + featureGroup: combineReducers({ + featureGroupEditor: createPlainDataReducer(featureGroupsEditorReducer), + featureGroupsList: featureGroupsListReducer + }), + entitlementPool: combineReducers({ + entitlementPoolEditor: createPlainDataReducer( + entitlementPoolsEditorReducer + ), + entitlementPoolsList: entitlementPoolsListReducer + }), + licenseKeyGroup: combineReducers({ + licenseKeyGroupsEditor: createPlainDataReducer( + licenseKeyGroupsEditorReducer + ), + licenseKeyGroupsList: licenseKeyGroupsListReducer + }), + licenseModelOverview: combineReducers({ + selectedTab: (state = null, action) => + action.type === + licenseModelOverviewConstants.LICENSE_MODEL_OVERVIEW_TAB_SELECTED + ? action.buttonTab + : state, + descriptionEditor: createPlainDataReducer(function( + state = false, + action + ) { + if (action.type === licenseModelOverviewConstants.LM_DATA_CHANGED) { + return { + ...state, + data: { + description: action.description + }, + formReady: null, + formName: VLM_DESCRIPTION_FORM, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 1000 } + ] + } + } + }; + //return action.description; + } else { + return state; + } + }) + }), + limitEditor: createPlainDataReducer(limitEditorReducer), + activityLog: activityLogReducer }); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelValidations.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelValidations.js index 64bae3b6a0..340d345609 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelValidations.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/LicenseModelValidations.js @@ -14,28 +14,34 @@ * permissions and limitations under the License. */ import i18n from 'nfvo-utils/i18n/i18n.js'; -import {thresholdUnitType} from './LicenseModelConstants.js'; +import { thresholdUnitType } from './LicenseModelConstants.js'; import Validator from 'nfvo-utils/Validator.js'; export function 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: ''}; + 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: '' }; } export function thresholdValueValidation(value, state) { - let unit = state.data.thresholdUnits; - if (unit === thresholdUnitType.PERCENTAGE) { - return Validator.validate('thresholdValue', value, [ - {type: 'numeric', data: true}, - {type: 'maximum', data: 100}, - {type: 'minimum', data: 0}]); - } else { - return Validator.validate('thresholdValue', value, [ - {type: 'numeric', data: true}, - ]); - } + let unit = state.data.thresholdUnits; + if (unit === thresholdUnitType.PERCENTAGE) { + return Validator.validate('thresholdValue', value, [ + { type: 'numeric', data: true }, + { type: 'maximum', data: 100 }, + { type: 'minimum', data: 0 } + ]); + } else { + return Validator.validate('thresholdValue', value, [ + { type: 'numeric', data: true } + ]); + } } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js index bcd6e7fe5b..4bbab865fa 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreation.js @@ -13,48 +13,84 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import LicenseModelCreationActionHelper from './LicenseModelCreationActionHelper.js'; import LicenseModelCreationView from './LicenseModelCreationView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import {itemTypes as versionItemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { itemTypes as versionItemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; -export const mapStateToProps = ({users: {usersList}, licenseModelList, finalizedLicenseModelList, archivedLicenseModelList, licenseModel: {licenseModelCreation}}) => { - let {genericFieldInfo} = licenseModelCreation; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let VLMNames = {}; +export const mapStateToProps = ({ + users: { usersList }, + licenseModelList, + finalizedLicenseModelList, + archivedLicenseModelList, + licenseModel: { licenseModelCreation } +}) => { + let { genericFieldInfo } = licenseModelCreation; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + let VLMNames = {}; - const allVlmList = [...licenseModelList, ...finalizedLicenseModelList,...archivedLicenseModelList]; - allVlmList.map((item) => { - VLMNames[item.name.toLowerCase()] = item.id; - }); + const allVlmList = [ + ...licenseModelList, + ...finalizedLicenseModelList, + ...archivedLicenseModelList + ]; + allVlmList.map(item => { + VLMNames[item.name.toLowerCase()] = item.id; + }); - return {...licenseModelCreation, isFormValid: isFormValid, VLMNames, usersList}; + return { + ...licenseModelCreation, + isFormValid: isFormValid, + VLMNames, + usersList + }; }; -export const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onCancel: () => LicenseModelCreationActionHelper.close(dispatch), - onSubmit: (licenseModel, usersList) => { - LicenseModelCreationActionHelper.close(dispatch); - LicenseModelCreationActionHelper.createLicenseModel(dispatch, {licenseModel}).then(response => { - let {itemId, version} = response; - LicenseModelActionHelper.fetchLicenseModels(dispatch).then(() => - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId, allUsers: usersList}).then(() => - VersionsPageActionHelper.fetchVersions(dispatch, {itemType: versionItemTypes.LICENSE_MODEL, itemId}).then(() => - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId: itemId, version}}) - ))); - }); - }, - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; +export const mapActionsToProps = dispatch => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onCancel: () => LicenseModelCreationActionHelper.close(dispatch), + onSubmit: (licenseModel, usersList) => { + LicenseModelCreationActionHelper.close(dispatch); + LicenseModelCreationActionHelper.createLicenseModel(dispatch, { + licenseModel + }).then(response => { + let { itemId, version } = response; + LicenseModelActionHelper.fetchLicenseModels(dispatch).then(() => + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId, + allUsers: usersList + }).then(() => + VersionsPageActionHelper.fetchVersions(dispatch, { + itemType: versionItemTypes.LICENSE_MODEL, + itemId + }).then(() => + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId: itemId, version } + }) + ) + ) + ); + }); + }, + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseModelCreationView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseModelCreationView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js index 87df1386b6..e2b8d55ffe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationActionHelper.js @@ -15,59 +15,56 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './LicenseModelCreationConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './LicenseModelCreationConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-license-models/`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-license-models/`; } function createLicenseModel(licenseModel) { - return RestAPIUtil.post(baseUrl(), { - vendorName: licenseModel.vendorName, - description: licenseModel.description, - iconRef: 'icon' - }); + return RestAPIUtil.post(baseUrl(), { + vendorName: licenseModel.vendorName, + description: licenseModel.description, + iconRef: 'icon' + }); } - export default { + open(dispatch) { + dispatch({ + type: actionTypes.OPEN + }); - open(dispatch) { - dispatch({ - type: actionTypes.OPEN - }); - - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.LICENSE_MODEL_CREATION, - title: i18n('New License Model') - } - }); - }, - - close(dispatch){ - dispatch({ - type: actionTypes.CLOSE - }); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.LICENSE_MODEL_CREATION, + title: i18n('New License Model') + } + }); + }, - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - }, + close(dispatch) { + dispatch({ + type: actionTypes.CLOSE + }); - createLicenseModel(dispatch, {licenseModel}){ - return createLicenseModel(licenseModel).then(result => { - dispatch({ - type: actionTypes.LICENSE_MODEL_CREATED, - result - }); - return result; - }); - } + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + }, + createLicenseModel(dispatch, { licenseModel }) { + return createLicenseModel(licenseModel).then(result => { + dispatch({ + type: actionTypes.LICENSE_MODEL_CREATED, + result + }); + return result; + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js index e9b1c46bef..1cd61a9e4b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationConstants.js @@ -16,9 +16,9 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - OPEN: null, - CLOSE: null, - LICENSE_MODEL_CREATED: null + OPEN: null, + CLOSE: null, + LICENSE_MODEL_CREATED: null }); export const LICENSE_MODEL_CREATION_FORM_NAME = 'LMCREATIONFORM'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js index 879d356de2..7137230cc7 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationReducer.js @@ -13,32 +13,41 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, LICENSE_MODEL_CREATION_FORM_NAME} from './LicenseModelCreationConstants.js'; +import { + actionTypes, + LICENSE_MODEL_CREATION_FORM_NAME +} from './LicenseModelCreationConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.OPEN: - return { - ...state, - formReady: null, - formName: LICENSE_MODEL_CREATION_FORM_NAME, - data: {}, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 1000}] - }, - 'vendorName' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 25}] - } - } - }; - case actionTypes.CLOSE: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.OPEN: + return { + ...state, + formReady: null, + formName: LICENSE_MODEL_CREATION_FORM_NAME, + data: {}, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 1000 } + ] + }, + vendorName: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 25 } + ] + } + } + }; + case actionTypes.CLOSE: + return {}; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx index 948bdc158d..59c4152213 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/creation/LicenseModelCreationView.jsx @@ -19,84 +19,112 @@ 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 {LICENSE_MODEL_CREATION_FORM_NAME} from './LicenseModelCreationConstants.js'; +import { LICENSE_MODEL_CREATION_FORM_NAME } from './LicenseModelCreationConstants.js'; const LicenseModelPropType = PropTypes.shape({ - id: PropTypes.string, - vendorName: PropTypes.string, - description: PropTypes.string + id: PropTypes.string, + vendorName: PropTypes.string, + description: PropTypes.string }); class LicenseModelCreationView extends React.Component { + static propTypes = { + data: LicenseModelPropType, + VLMNames: PropTypes.object, + usersList: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onValidateForm: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - static propTypes = { - data: LicenseModelPropType, - VLMNames: PropTypes.object, - usersList: PropTypes.array, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onValidateForm: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; + render() { + let { data = {}, onDataChanged, genericFieldInfo } = this.props; + let { vendorName, description } = data; + return ( + <div> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={true} + onSubmit={() => this.submit()} + submitButtonText={i18n('Create')} + onReset={() => this.props.onCancel()} + labledButtons={true} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => this.validate()}> + <Input + value={vendorName} + label={i18n('Vendor Name')} + data-test-id="vendor-name" + onChange={vendorName => + onDataChanged( + { vendorName }, + LICENSE_MODEL_CREATION_FORM_NAME, + { + vendorName: name => + this.validateName(name) + } + ) + } + isValid={genericFieldInfo.vendorName.isValid} + errorText={genericFieldInfo.vendorName.errorText} + type="text" + isRequired={true} + className="field-section" + /> + <Input + isRequired={true} + value={description} + label={i18n('Description')} + data-test-id="vendor-description" + overlayPos="bottom" + onChange={description => + onDataChanged( + { description }, + LICENSE_MODEL_CREATION_FORM_NAME + ) + } + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + type="textarea" + className="field-section" + /> + </Form> + )} + </div> + ); + } - render() { - let {data = {}, onDataChanged, genericFieldInfo} = this.props; - let {vendorName, description} = data; - return ( - <div> - {genericFieldInfo && <Form - ref='validationForm' - hasButtons={true} - onSubmit={ () => this.submit() } - submitButtonText={i18n('Create')} - onReset={ () => this.props.onCancel() } - labledButtons={true} - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.validate() }> - <Input - value={vendorName} - label={i18n('Vendor Name')} - data-test-id='vendor-name' - onChange={vendorName => onDataChanged({vendorName}, LICENSE_MODEL_CREATION_FORM_NAME, {vendorName: name => this.validateName(name)})} - isValid={genericFieldInfo.vendorName.isValid} - errorText={genericFieldInfo.vendorName.errorText} - type='text' - isRequired={true} - className='field-section'/> - <Input - isRequired={true} - value={description} - label={i18n('Description')} - data-test-id='vendor-description' - overlayPos='bottom' - onChange={description => onDataChanged({description}, LICENSE_MODEL_CREATION_FORM_NAME)} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - type='textarea' - className='field-section'/> - </Form>} - </div> - ); - } + submit() { + const { data: licenseModel, usersList } = this.props; + this.props.onSubmit(licenseModel, usersList); + } + validateName(value) { + const { data: { id }, VLMNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: VLMNames + }); - submit() { - const {data:licenseModel, usersList} = this.props; - this.props.onSubmit(licenseModel, usersList); - } + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "License model by the name '" + + value + + "' already exists. License model name must be unique" + ) + }; + } - validateName(value) { - const {data: {id}, VLMNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: VLMNames}); - - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('License model by the name \'' + value + '\' already exists. License model name must be unique')}; - } - - validate() { - this.props.onValidateForm(LICENSE_MODEL_CREATION_FORM_NAME); - } + validate() { + this.props.onValidateForm(LICENSE_MODEL_CREATION_FORM_NAME); + } } export default LicenseModelCreationView; 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 84bdac804c..181fc11c9d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js @@ -15,197 +15,281 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes as entitlementPoolsActionTypes } from './EntitlementPoolsConstants.js'; -import {actionTypes as limitEditorActions} from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; -import {default as getValue, getStrValue} from 'nfvo-utils/getValue.js'; +import { actionTypes as entitlementPoolsActionTypes } from './EntitlementPoolsConstants.js'; +import { actionTypes as limitEditorActions } from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; +import { default as getValue, getStrValue } from 'nfvo-utils/getValue.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; function baseUrl(licenseModelId, version) { - const restPrefix = Configuration.get('restPrefix'); - const {id: versionId} = version; - return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/entitlement-pools`; + const restPrefix = Configuration.get('restPrefix'); + const { id: versionId } = version; + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/entitlement-pools`; } function fetchEntitlementPoolsList(licenseModelId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); } function postEntitlementPool(licenseModelId, entitlementPool, version) { - return RestAPIUtil.post(baseUrl(licenseModelId, version), { - name: entitlementPool.name, - description: entitlementPool.description, - thresholdValue: entitlementPool.thresholdValue, - thresholdUnits: getValue(entitlementPool.thresholdUnits), - increments: entitlementPool.increments, - operationalScope: getValue(entitlementPool.operationalScope), - time: entitlementPool.time, - startDate: entitlementPool.startDate, - expiryDate: entitlementPool.expiryDate - }); + return RestAPIUtil.post(baseUrl(licenseModelId, version), { + name: entitlementPool.name, + description: entitlementPool.description, + thresholdValue: entitlementPool.thresholdValue, + thresholdUnits: getValue(entitlementPool.thresholdUnits), + increments: entitlementPool.increments, + operationalScope: getValue(entitlementPool.operationalScope), + time: entitlementPool.time, + startDate: entitlementPool.startDate, + expiryDate: entitlementPool.expiryDate + }); } - -function putEntitlementPool(licenseModelId, previousEntitlementPool, entitlementPool, version) { - - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${entitlementPool.id}`, { - name: entitlementPool.name, - description: entitlementPool.description, - thresholdValue: entitlementPool.thresholdValue, - thresholdUnits: getValue(entitlementPool.thresholdUnits), - increments: entitlementPool.increments, - operationalScope: getValue(entitlementPool.operationalScope), - time: entitlementPool.time, - startDate: entitlementPool.startDate, - expiryDate: entitlementPool.expiryDate - }); +function putEntitlementPool( + licenseModelId, + previousEntitlementPool, + entitlementPool, + version +) { + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${entitlementPool.id}`, + { + name: entitlementPool.name, + description: entitlementPool.description, + thresholdValue: entitlementPool.thresholdValue, + thresholdUnits: getValue(entitlementPool.thresholdUnits), + increments: entitlementPool.increments, + operationalScope: getValue(entitlementPool.operationalScope), + time: entitlementPool.time, + startDate: entitlementPool.startDate, + expiryDate: entitlementPool.expiryDate + } + ); } function deleteEntitlementPool(licenseModelId, entitlementPoolId, version) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${entitlementPoolId}`); + return RestAPIUtil.destroy( + `${baseUrl(licenseModelId, version)}/${entitlementPoolId}` + ); } function fetchLimitsList(licenseModelId, entitlementPoolId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits`); + return RestAPIUtil.fetch( + `${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits` + ); } function deleteLimit(licenseModelId, entitlementPoolId, version, limitId) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits/${limitId}`); + return RestAPIUtil.destroy( + `${baseUrl( + licenseModelId, + version + )}/${entitlementPoolId}/limits/${limitId}` + ); } function postLimit(licenseModelId, entitlementPoolId, version, limit) { - return RestAPIUtil.post(`${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits`, { - name: limit.name, - type: limit.type, - description: limit.description, - metric: getStrValue(limit.metric), - value: limit.value, - unit: getStrValue(limit.unit), - aggregationFunction: getValue(limit.aggregationFunction), - time: getValue(limit.time) - }); + return RestAPIUtil.post( + `${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits`, + { + name: limit.name, + type: limit.type, + description: limit.description, + metric: getStrValue(limit.metric), + value: limit.value, + unit: getStrValue(limit.unit), + aggregationFunction: getValue(limit.aggregationFunction), + time: getValue(limit.time) + } + ); } function putLimit(licenseModelId, entitlementPoolId, version, limit) { - - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits/${limit.id}`, { - name: limit.name, - type: limit.type, - description: limit.description, - metric: getStrValue(limit.metric), - value: limit.value, - unit: getStrValue(limit.unit), - aggregationFunction: getValue(limit.aggregationFunction), - time: getValue(limit.time) - }); + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${entitlementPoolId}/limits/${ + limit.id + }`, + { + name: limit.name, + type: limit.type, + description: limit.description, + metric: getStrValue(limit.metric), + value: limit.value, + unit: getStrValue(limit.unit), + aggregationFunction: getValue(limit.aggregationFunction), + time: getValue(limit.time) + } + ); } export default { + fetchEntitlementPoolsList(dispatch, { licenseModelId, version }) { + return fetchEntitlementPoolsList(licenseModelId, version).then( + response => + dispatch({ + type: + entitlementPoolsActionTypes.ENTITLEMENT_POOLS_LIST_LOADED, + response + }) + ); + }, + + openEntitlementPoolsEditor( + dispatch, + { entitlementPool, licenseModelId, version } = {} + ) { + if (licenseModelId && version) { + this.fetchLimits(dispatch, { + licenseModelId, + version, + entitlementPool + }); + } + dispatch({ + type: entitlementPoolsActionTypes.entitlementPoolsEditor.OPEN, + entitlementPool + }); + }, + + deleteEntitlementPool( + dispatch, + { licenseModelId, entitlementPoolId, version } + ) { + return deleteEntitlementPool( + licenseModelId, + entitlementPoolId, + version + ).then(() => { + dispatch({ + type: entitlementPoolsActionTypes.DELETE_ENTITLEMENT_POOL, + entitlementPoolId + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + }, + + entitlementPoolsEditorDataChanged(dispatch, { deltaData }) { + dispatch({ + type: + entitlementPoolsActionTypes.entitlementPoolsEditor.DATA_CHANGED, + deltaData + }); + }, + + closeEntitlementPoolsEditor(dispatch) { + dispatch({ + type: entitlementPoolsActionTypes.entitlementPoolsEditor.CLOSE + }); + }, + + saveEntitlementPool( + dispatch, + { licenseModelId, previousEntitlementPool, entitlementPool, version } + ) { + if (previousEntitlementPool) { + return putEntitlementPool( + licenseModelId, + previousEntitlementPool, + entitlementPool, + version + ).then(() => { + dispatch({ + type: entitlementPoolsActionTypes.EDIT_ENTITLEMENT_POOL, + entitlementPool + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } else { + return postEntitlementPool( + licenseModelId, + entitlementPool, + version + ).then(response => { + dispatch({ + type: entitlementPoolsActionTypes.ADD_ENTITLEMENT_POOL, + entitlementPool: { + ...entitlementPool, + referencingFeatureGroups: [], + id: response.value + } + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, + entitlementPoolToDelete: false + }); + }, + openDeleteEntitlementPoolConfirm(dispatch, { entitlementPool }) { + dispatch({ + type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, + entitlementPoolToDelete: entitlementPool + }); + }, + + fetchLimits(dispatch, { licenseModelId, version, entitlementPool }) { + return fetchLimitsList( + licenseModelId, + entitlementPool.id, + version + ).then(response => { + dispatch({ + type: + entitlementPoolsActionTypes.entitlementPoolsEditor + .LIMITS_LIST_LOADED, + response + }); + }); + }, + + submitLimit(dispatch, { licenseModelId, version, entitlementPool, limit }) { + const propmise = limit.id + ? putLimit(licenseModelId, entitlementPool.id, version, limit) + : postLimit(licenseModelId, entitlementPool.id, version, limit); + return propmise.then(() => { + dispatch({ + type: limitEditorActions.CLOSE + }); + this.fetchLimits(dispatch, { + licenseModelId, + version, + entitlementPool + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + }, - fetchEntitlementPoolsList(dispatch, {licenseModelId, version}) { - return fetchEntitlementPoolsList(licenseModelId, version).then(response => dispatch({ - type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_LIST_LOADED, - response - })); - }, - - openEntitlementPoolsEditor(dispatch, {entitlementPool, licenseModelId, version} = {}) { - if (licenseModelId && version) { - this.fetchLimits(dispatch, {licenseModelId, version, entitlementPool}); - } - dispatch({ - type: entitlementPoolsActionTypes.entitlementPoolsEditor.OPEN, - entitlementPool - }); - }, - - deleteEntitlementPool(dispatch, {licenseModelId, entitlementPoolId, version}) { - return deleteEntitlementPool(licenseModelId, entitlementPoolId, version).then(() => { - dispatch({ - type: entitlementPoolsActionTypes.DELETE_ENTITLEMENT_POOL, - entitlementPoolId - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, - - entitlementPoolsEditorDataChanged(dispatch, {deltaData}) { - dispatch({ - type: entitlementPoolsActionTypes.entitlementPoolsEditor.DATA_CHANGED, - deltaData - }); - }, - - closeEntitlementPoolsEditor(dispatch) { - dispatch({ - type: entitlementPoolsActionTypes.entitlementPoolsEditor.CLOSE - }); - }, - - saveEntitlementPool(dispatch, {licenseModelId, previousEntitlementPool, entitlementPool, version}) { - if (previousEntitlementPool) { - return putEntitlementPool(licenseModelId, previousEntitlementPool, entitlementPool, version).then(() => { - dispatch({ - type: entitlementPoolsActionTypes.EDIT_ENTITLEMENT_POOL, - entitlementPool - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - else { - return postEntitlementPool(licenseModelId, entitlementPool, version).then(response => { - dispatch({ - type: entitlementPoolsActionTypes.ADD_ENTITLEMENT_POOL, - entitlementPool: { - ...entitlementPool, - referencingFeatureGroups: [], - id: response.value - } - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - }, - - hideDeleteConfirm(dispatch) { - dispatch({ - type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, - entitlementPoolToDelete: false - }); - }, - openDeleteEntitlementPoolConfirm(dispatch, {entitlementPool}) { - dispatch({ - type: entitlementPoolsActionTypes.ENTITLEMENT_POOLS_DELETE_CONFIRM, - entitlementPoolToDelete: entitlementPool - }); - }, - - - - fetchLimits(dispatch, {licenseModelId, version, entitlementPool}) { - return fetchLimitsList(licenseModelId, entitlementPool.id, version). then (response => { - dispatch({ - type: entitlementPoolsActionTypes.entitlementPoolsEditor.LIMITS_LIST_LOADED, - response - }); - }); - }, - - submitLimit(dispatch, {licenseModelId, version, entitlementPool, limit}) { - const propmise = limit.id ? putLimit(licenseModelId,entitlementPool.id, version, limit) - : postLimit(licenseModelId,entitlementPool.id, version, limit); - return propmise.then(() => { - dispatch({ - type: limitEditorActions.CLOSE - }); - this.fetchLimits(dispatch, {licenseModelId, version, entitlementPool}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, - - deleteLimit(dispatch, {licenseModelId, version, entitlementPool, limit}) { - return deleteLimit(licenseModelId,entitlementPool.id, version, limit.id).then(() => { - this.fetchLimits(dispatch, {licenseModelId, version, entitlementPool}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } + deleteLimit(dispatch, { licenseModelId, version, entitlementPool, limit }) { + return deleteLimit( + licenseModelId, + entitlementPool.id, + version, + limit.id + ).then(() => { + this.fetchLimits(dispatch, { + licenseModelId, + version, + entitlementPool + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } }; 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 de2a87ceaf..e69ff688ab 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsConstants.js @@ -15,104 +15,112 @@ */ import keyMirror from 'nfvo-utils/KeyMirror.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import InputOptions, {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import InputOptions, { + other as optionInputOther +} from 'nfvo-components/input/validation/InputOptions.jsx'; export const actionTypes = keyMirror({ + ENTITLEMENT_POOLS_LIST_LOADED: null, + ADD_ENTITLEMENT_POOL: null, + EDIT_ENTITLEMENT_POOL: null, + DELETE_ENTITLEMENT_POOL: null, - ENTITLEMENT_POOLS_LIST_LOADED: null, - ADD_ENTITLEMENT_POOL: null, - EDIT_ENTITLEMENT_POOL: null, - DELETE_ENTITLEMENT_POOL: null, - - entitlementPoolsEditor: { - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, - LIMITS_LIST_LOADED: null - } - + entitlementPoolsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + LIMITS_LIST_LOADED: null + } }); export const enums = keyMirror({ - SELECTED_FEATURE_GROUP_TAB: { - GENERAL: 1, - ENTITLEMENT_POOLS: 2, - LICENCE_KEY_GROUPS: 3 - }, - SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: { - ASSOCIATED_ENTITLEMENT_POOLS: 1, - AVAILABLE_ENTITLEMENT_POOLS: 2 - } + SELECTED_FEATURE_GROUP_TAB: { + GENERAL: 1, + ENTITLEMENT_POOLS: 2, + LICENCE_KEY_GROUPS: 3 + }, + SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: { + ASSOCIATED_ENTITLEMENT_POOLS: 1, + AVAILABLE_ENTITLEMENT_POOLS: 2 + } }); export const defaultState = { - ENTITLEMENT_POOLS_EDITOR_DATA: { - entitlementMetric: {choice: '', other: ''}, - aggregationFunction: {choice: '', other: ''}, - operationalScope: {choices: [], other: ''}, - time: {choice: '', other: ''} - } + ENTITLEMENT_POOLS_EDITOR_DATA: { + entitlementMetric: { choice: '', other: '' }, + aggregationFunction: { choice: '', other: '' }, + operationalScope: { choices: [], other: '' }, + time: { choice: '', other: '' } + } }; export const thresholdUnitType = { - ABSOLUTE: 'Absolute', - PERCENTAGE: 'Percentage' + ABSOLUTE: 'Absolute', + PERCENTAGE: 'Percentage' }; export const optionsInputValues = { - OPERATIONAL_SCOPE: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Network_Wide', title: 'Network Wide'}, - {enum: 'Availability_Zone', title: 'Availability Zone'}, - {enum: 'Data_Center', title: 'Data Center'}, - {enum: 'Tenant', title: 'Tenant'}, - {enum: 'VM', title: 'VM'}, - {enum: 'CPU', title: 'CPU'}, - {enum: 'Core', title: 'Core'} - ], - TIME: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Hour', title: 'Hour'}, - {enum: 'Day', title: 'Day'}, - {enum: 'Month', title: 'Month'} - ], - AGGREGATE_FUNCTION: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Peak', title: 'Peak'}, - {enum: 'Average', title: 'Average'} - ], - ENTITLEMENT_METRIC: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Software_Instances_Count', title: 'Software Instances'}, - {enum: 'Core', title: 'Core'}, - {enum: 'CPU', title: 'CPU'}, - {enum: 'Trunks', title: 'Trunks'}, - {enum: 'User', title: 'User'}, - {enum: 'Subscribers', title: 'Subscribers'}, - {enum: 'Tenants', title: 'Tenants'}, - {enum: 'Tokens', title: 'Tokens'}, - {enum: 'Seats', title: 'Seats'}, - {enum: 'Units_TB', title: 'Units-TB'}, - {enum: 'Units_GB', title: 'Units-GB'}, - {enum: 'Units_MB', title: 'Units-MB'} - ] + OPERATIONAL_SCOPE: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Network_Wide', title: 'Network Wide' }, + { enum: 'Availability_Zone', title: 'Availability Zone' }, + { enum: 'Data_Center', title: 'Data Center' }, + { enum: 'Tenant', title: 'Tenant' }, + { enum: 'VM', title: 'VM' }, + { enum: 'CPU', title: 'CPU' }, + { enum: 'Core', title: 'Core' } + ], + TIME: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Hour', title: 'Hour' }, + { enum: 'Day', title: 'Day' }, + { enum: 'Month', title: 'Month' } + ], + AGGREGATE_FUNCTION: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Peak', title: 'Peak' }, + { enum: 'Average', title: 'Average' } + ], + ENTITLEMENT_METRIC: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Software_Instances_Count', title: 'Software Instances' }, + { enum: 'Core', title: 'Core' }, + { enum: 'CPU', title: 'CPU' }, + { enum: 'Trunks', title: 'Trunks' }, + { enum: 'User', title: 'User' }, + { enum: 'Subscribers', title: 'Subscribers' }, + { enum: 'Tenants', title: 'Tenants' }, + { enum: 'Tokens', title: 'Tokens' }, + { enum: 'Seats', title: 'Seats' }, + { enum: 'Units_TB', title: 'Units-TB' }, + { enum: 'Units_GB', title: 'Units-GB' }, + { enum: 'Units_MB', title: 'Units-MB' } + ] }; -export const extractValue = (item) => { - if (item === undefined) {return '';} //TODO fix it later - return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; +export const extractValue = item => { + if (item === undefined) { + return ''; + } //TODO fix it later + return item + ? item.choice === optionInputOther.OTHER + ? item.other + : InputOptions.getTitleByName(optionsInputValues, item.choice) + : ''; }; -export const extractUnits = (units) => { - if (units === undefined) {return '';} //TODO fix it later - return units === 'Absolute' ? '' : '%'; +export const extractUnits = units => { + if (units === undefined) { + return ''; + } //TODO fix it later + return units === 'Absolute' ? '' : '%'; }; export const tabIds = { - GENERAL: 'GENERAL', - SP_LIMITS: 'SP_LIMITS', - VENDOR_LIMITS: 'VENDOR_LIMITS', - ADD_LIMIT_BUTTON: 'ADD_LIMIT_BUTTON' + GENERAL: 'GENERAL', + SP_LIMITS: 'SP_LIMITS', + VENDOR_LIMITS: 'VENDOR_LIMITS', + ADD_LIMIT_BUTTON: 'ADD_LIMIT_BUTTON' }; -export const SP_ENTITLEMENT_POOL_FORM = 'SPENTITLEMENTPOOL';
\ No newline at end of file +export const SP_ENTITLEMENT_POOL_FORM = 'SPENTITLEMENTPOOL'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js index 23c260f793..5fcdad992a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditor.js @@ -13,54 +13,80 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; import EntitlementPoolsEditorView from './EntitlementPoolsEditorView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import LimitEditorActionHelper from '../limits/LimitEditorActionHelper.js'; -const mapStateToProps = ({licenseModel: {entitlementPool}}) => { +const mapStateToProps = ({ licenseModel: { entitlementPool } }) => { + let { + data, + genericFieldInfo, + formReady, + limitsList + } = entitlementPool.entitlementPoolEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let {data, genericFieldInfo, formReady, limitsList} = entitlementPool.entitlementPoolEditor; + let previousData, + EPNames = {}; + const entitlementPoolId = data ? data.id : null; + if (entitlementPoolId) { + previousData = entitlementPool.entitlementPoolsList.find( + entitlementPool => entitlementPool.id === entitlementPoolId + ); + } - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + const list = entitlementPool.entitlementPoolsList; + for (let i = 0; i < list.length; i++) { + EPNames[list[i].name.toLowerCase()] = list[i].id; + } - let previousData, EPNames = {}; - const entitlementPoolId = data ? data.id : null; - if(entitlementPoolId) { - previousData = entitlementPool.entitlementPoolsList.find(entitlementPool => entitlementPool.id === entitlementPoolId); - } - - const list = entitlementPool.entitlementPoolsList; - for (let i = 0; i < list.length; i++) { - EPNames[list[i].name.toLowerCase()] = list[i].id; - } - - return { - data, - genericFieldInfo, - previousData, - isFormValid, - formReady, - EPNames, - limitsList - }; + return { + data, + genericFieldInfo, + previousData, + isFormValid, + formReady, + EPNames, + limitsList + }; }; -const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onCancel: () => EntitlementPoolsActionHelper.closeEntitlementPoolsEditor(dispatch), - onSubmit: ({previousEntitlementPool, entitlementPool, keepOpen}) => { - if (!keepOpen) {EntitlementPoolsActionHelper.closeEntitlementPoolsEditor(dispatch);} - EntitlementPoolsActionHelper.saveEntitlementPool(dispatch, {licenseModelId, previousEntitlementPool, entitlementPool, version}); - }, - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName), - onCloseLimitEditor: () => LimitEditorActionHelper.closeLimitsEditor(dispatch), - onOpenLimitEditor: (limit) => LimitEditorActionHelper.openLimitsEditor(dispatch, {limit}) - }; +const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onCancel: () => + EntitlementPoolsActionHelper.closeEntitlementPoolsEditor(dispatch), + onSubmit: ({ previousEntitlementPool, entitlementPool, keepOpen }) => { + if (!keepOpen) { + EntitlementPoolsActionHelper.closeEntitlementPoolsEditor( + dispatch + ); + } + EntitlementPoolsActionHelper.saveEntitlementPool(dispatch, { + licenseModelId, + previousEntitlementPool, + entitlementPool, + version + }); + }, + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName), + onCloseLimitEditor: () => + LimitEditorActionHelper.closeLimitsEditor(dispatch), + onOpenLimitEditor: limit => + LimitEditorActionHelper.openLimitsEditor(dispatch, { limit }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(EntitlementPoolsEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + EntitlementPoolsEditorView +); 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 be100f6802..4556b87129 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorReducer.js @@ -13,87 +13,101 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, defaultState, SP_ENTITLEMENT_POOL_FORM} from './EntitlementPoolsConstants.js'; +import { + actionTypes, + defaultState, + SP_ENTITLEMENT_POOL_FORM +} from './EntitlementPoolsConstants.js'; import moment from 'moment'; -import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; +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, - formName: SP_ENTITLEMENT_POOL_FORM, - genericFieldInfo: { - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}] - }, - 'increments' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 120}] - }, - 'operationalScope' : { - isValid: true, - errorText: '', - validations: [] - }, - 'thresholdUnits' : { - isValid: true, - errorText: '', - validations: [] - }, - 'thresholdValue' : { - isValid: true, - errorText: '', - validations: [] - }, - 'startDate': { - isValid: true, - errorText: '', - validations: [] - }, - 'expiryDate': { - isValid: true, - errorText: '', - validations: [] - } - }, - data: action.entitlementPool ? entitlementPoolData : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA - }; - case actionTypes.entitlementPoolsEditor.DATA_CHANGED: - return { - ...state, - data: { - ...state.data, - ...action.deltaData - } - }; - case actionTypes.entitlementPoolsEditor.CLOSE: - return {}; - - case actionTypes.entitlementPoolsEditor.LIMITS_LIST_LOADED: - return { - ...state, - limitsList: action.response.results - }; - default: - return state; - } + 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, + formName: SP_ENTITLEMENT_POOL_FORM, + genericFieldInfo: { + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }] + }, + increments: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 120 }] + }, + operationalScope: { + isValid: true, + errorText: '', + validations: [] + }, + thresholdUnits: { + isValid: true, + errorText: '', + validations: [] + }, + thresholdValue: { + isValid: true, + errorText: '', + validations: [] + }, + startDate: { + isValid: true, + errorText: '', + validations: [] + }, + expiryDate: { + isValid: true, + errorText: '', + validations: [] + } + }, + data: action.entitlementPool + ? entitlementPoolData + : defaultState.ENTITLEMENT_POOLS_EDITOR_DATA + }; + case actionTypes.entitlementPoolsEditor.DATA_CHANGED: + return { + ...state, + data: { + ...state.data, + ...action.deltaData + } + }; + case actionTypes.entitlementPoolsEditor.CLOSE: + return {}; + case actionTypes.entitlementPoolsEditor.LIMITS_LIST_LOADED: + return { + ...state, + limitsList: action.response.results + }; + default: + return state; + } }; 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 efae7f3ad2..46eda622b5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsEditorView.jsx @@ -25,307 +25,479 @@ import Form from 'nfvo-components/input/validation/Form.jsx'; import Button from 'sdc-ui/lib/react/Button.js'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import {optionsInputValues as EntitlementPoolsOptionsInputValues, SP_ENTITLEMENT_POOL_FORM, tabIds} from './EntitlementPoolsConstants.js'; -import {optionsInputValues as LicenseModelOptionsInputValues} from '../LicenseModelConstants.js'; -import {validateStartDate, thresholdValueValidation} from '../LicenseModelValidations.js'; -import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { + optionsInputValues as EntitlementPoolsOptionsInputValues, + SP_ENTITLEMENT_POOL_FORM, + tabIds +} from './EntitlementPoolsConstants.js'; +import { optionsInputValues as LicenseModelOptionsInputValues } from '../LicenseModelConstants.js'; +import { + validateStartDate, + thresholdValueValidation +} from '../LicenseModelValidations.js'; +import { DATE_FORMAT } from 'sdc-app/onboarding/OnboardingConstants.js'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; import Tabs from 'sdc-ui/lib/react/Tabs.js'; import Tab from 'sdc-ui/lib/react/Tab.js'; import EntitlementPoolsLimits from './EntitlementPoolsLimits.js'; -import {limitType, NEW_LIMIT_TEMP_ID} from '../limits/LimitEditorConstants.js'; +import { + limitType, + NEW_LIMIT_TEMP_ID +} from '../limits/LimitEditorConstants.js'; const EntitlementPoolPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - operationalScope: PropTypes.shape({ - choices: PropTypes.array, - other: PropTypes.string - }), - thresholdUnits: PropTypes.string, - thresholdValue: PropTypes.string, - increments: PropTypes.string, - startDate: PropTypes.string, - expiryDate: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + operationalScope: PropTypes.shape({ + choices: PropTypes.array, + other: PropTypes.string + }), + thresholdUnits: PropTypes.string, + thresholdValue: PropTypes.string, + increments: PropTypes.string, + startDate: PropTypes.string, + expiryDate: PropTypes.string }); -const EntitlementPoolsFormContent = ({data, genericFieldInfo, onDataChanged, validateName, - thresholdValueValidation, validateStartDate}) => { +const EntitlementPoolsFormContent = ({ + data, + genericFieldInfo, + onDataChanged, + validateName, + thresholdValueValidation, + validateStartDate +}) => { + let { + name, + description, + operationalScope, + thresholdUnits, + thresholdValue, + increments, + startDate, + expiryDate + } = data; + return ( + <GridSection hasLastColSet> + <GridItem colSpan={2}> + <Input + onChange={name => + onDataChanged({ name }, SP_ENTITLEMENT_POOL_FORM, { + name: validateName + }) + } + isValid={genericFieldInfo.name.isValid} + isRequired={true} + errorText={genericFieldInfo.name.errorText} + label={i18n('Name')} + value={name} + data-test-id="create-ep-name" + type="text" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <InputOptions + onInputChange={() => {}} + isMultiSelect={true} + onEnumChange={operationalScope => + onDataChanged( + { + operationalScope: { + choices: operationalScope, + other: '' + } + }, + SP_ENTITLEMENT_POOL_FORM + ) + } + onOtherChange={operationalScope => + onDataChanged( + { + operationalScope: { + choices: [optionInputOther.OTHER], + other: operationalScope + } + }, + SP_ENTITLEMENT_POOL_FORM + ) + } + label={i18n('Operational Scope')} + data-test-id="create-ep-operational-scope" + type="select" + multiSelectedEnum={ + operationalScope && operationalScope.choices + } + otherValue={operationalScope && operationalScope.other} + values={ + EntitlementPoolsOptionsInputValues.OPERATIONAL_SCOPE + } + isValid={genericFieldInfo.operationalScope.isValid} + errorText={genericFieldInfo.operationalScope.errorText} + /> + </GridItem> + <GridItem colSpan={2} stretch> + <Input + onChange={description => + onDataChanged({ description }, SP_ENTITLEMENT_POOL_FORM) + } + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + label={i18n('Description')} + value={description} + data-test-id="create-ep-description" + type="textarea" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <div className="threshold-section"> + <Input + onChange={e => { + // setting the unit to the correct value + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onDataChanged( + { thresholdUnits: val }, + SP_ENTITLEMENT_POOL_FORM + ); + // TODO make sure that the value is valid too + if (thresholdValue && thresholdValue !== '') { + onDataChanged( + { thresholdValue: thresholdValue }, + SP_ENTITLEMENT_POOL_FORM, + { thresholdValue: thresholdValueValidation } + ); + } + }} + value={thresholdUnits} + label={i18n('Threshold Units')} + data-test-id="create-ep-threshold-units" + isValid={genericFieldInfo.thresholdUnits.isValid} + errorText={genericFieldInfo.thresholdUnits.errorText} + groupClassName="bootstrap-input-options" + className="input-options-select" + type="select"> + {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map( + mtype => ( + <option key={mtype.enum} value={mtype.enum}>{`${ + mtype.title + }`}</option> + ) + )} + </Input> - let {name, description, operationalScope, thresholdUnits, thresholdValue, - increments, startDate, expiryDate} = data; - return ( - <GridSection hasLastColSet> - <GridItem colSpan={2}> - <Input - onChange={name => onDataChanged({name}, SP_ENTITLEMENT_POOL_FORM, {name: validateName})} - isValid={genericFieldInfo.name.isValid} - isRequired={true} - errorText={genericFieldInfo.name.errorText} - label={i18n('Name')} - value={name} - data-test-id='create-ep-name' - type='text'/> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <InputOptions - onInputChange={()=>{}} - isMultiSelect={true} - onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}}, - SP_ENTITLEMENT_POOL_FORM)} - onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER], - other: operationalScope}}, SP_ENTITLEMENT_POOL_FORM)} - label={i18n('Operational Scope')} - data-test-id='create-ep-operational-scope' - type='select' - multiSelectedEnum={operationalScope && operationalScope.choices} - otherValue={operationalScope && operationalScope.other} - values={EntitlementPoolsOptionsInputValues.OPERATIONAL_SCOPE} - isValid={genericFieldInfo.operationalScope.isValid} - errorText={genericFieldInfo.operationalScope.errorText} /> - </GridItem> - <GridItem colSpan={2} stretch> - <Input - onChange={description => onDataChanged({description}, SP_ENTITLEMENT_POOL_FORM)} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - label={i18n('Description')} - value={description} - data-test-id='create-ep-description' - type='textarea'/> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <div className='threshold-section'> - <Input - onChange={e => { - // setting the unit to the correct value - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({thresholdUnits: val}, SP_ENTITLEMENT_POOL_FORM); - // TODO make sure that the value is valid too - if(thresholdValue && thresholdValue !== '') { - onDataChanged({thresholdValue: thresholdValue}, SP_ENTITLEMENT_POOL_FORM,{thresholdValue : thresholdValueValidation}); - }} - - } - value={thresholdUnits} - label={i18n('Threshold Units')} - data-test-id='create-ep-threshold-units' - isValid={genericFieldInfo.thresholdUnits.isValid} - errorText={genericFieldInfo.thresholdUnits.errorText} - groupClassName='bootstrap-input-options' - className='input-options-select' - type='select' > - {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map(mtype => - <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)} - </Input> - - <Input - className='entitlement-pools-form-row-threshold-value' - onChange={thresholdValue => onDataChanged({thresholdValue}, SP_ENTITLEMENT_POOL_FORM, - {thresholdValue : thresholdValueValidation})} - label={i18n('Threshold Value')} - isValid={genericFieldInfo.thresholdValue.isValid} - errorText={genericFieldInfo.thresholdValue.errorText} - data-test-id='create-ep-threshold-value' - value={thresholdValue} - type='text'/> - </div> - <Input - onChange={increments => onDataChanged({increments}, SP_ENTITLEMENT_POOL_FORM)} - label={i18n('Increments')} - value={increments} - data-test-id='create-ep-increments' - type='text'/> - <div className='date-section'> - <Input - type='date' - label={i18n('Start Date')} - value={startDate} - dateFormat={DATE_FORMAT} - startDate={startDate} - endDate={expiryDate} - onChange={startDate => onDataChanged( - {startDate: startDate ? startDate.format(DATE_FORMAT) : ''}, - SP_ENTITLEMENT_POOL_FORM, - {startDate: validateStartDate} - )} - isValid={genericFieldInfo.startDate.isValid} - errorText={genericFieldInfo.startDate.errorText} - selectsStart/> - <Input - type='date' - label={i18n('Expiry Date')} - value={expiryDate} - dateFormat={DATE_FORMAT} - startDate={startDate} - endDate={expiryDate} - onChange={expiryDate => { - onDataChanged({expiryDate: expiryDate ? expiryDate.format(DATE_FORMAT) : ''}, SP_ENTITLEMENT_POOL_FORM); - onDataChanged({startDate}, SP_ENTITLEMENT_POOL_FORM, {startDate: validateStartDate}); - }} - isValid={genericFieldInfo.expiryDate.isValid} - errorText={genericFieldInfo.expiryDate.errorText} - selectsEnd/> - </div> - </GridItem> - </GridSection> - ); + <Input + className="entitlement-pools-form-row-threshold-value" + onChange={thresholdValue => + onDataChanged( + { thresholdValue }, + SP_ENTITLEMENT_POOL_FORM, + { + thresholdValue: thresholdValueValidation + } + ) + } + label={i18n('Threshold Value')} + isValid={genericFieldInfo.thresholdValue.isValid} + errorText={genericFieldInfo.thresholdValue.errorText} + data-test-id="create-ep-threshold-value" + value={thresholdValue} + type="text" + /> + </div> + <Input + onChange={increments => + onDataChanged({ increments }, SP_ENTITLEMENT_POOL_FORM) + } + label={i18n('Increments')} + value={increments} + data-test-id="create-ep-increments" + type="text" + /> + <div className="date-section"> + <Input + type="date" + label={i18n('Start Date')} + value={startDate} + dateFormat={DATE_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={startDate => + onDataChanged( + { + startDate: startDate + ? startDate.format(DATE_FORMAT) + : '' + }, + SP_ENTITLEMENT_POOL_FORM, + { startDate: validateStartDate } + ) + } + isValid={genericFieldInfo.startDate.isValid} + errorText={genericFieldInfo.startDate.errorText} + selectsStart + /> + <Input + type="date" + label={i18n('Expiry Date')} + value={expiryDate} + dateFormat={DATE_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={expiryDate => { + onDataChanged( + { + expiryDate: expiryDate + ? expiryDate.format(DATE_FORMAT) + : '' + }, + SP_ENTITLEMENT_POOL_FORM + ); + onDataChanged( + { startDate }, + SP_ENTITLEMENT_POOL_FORM, + { + startDate: validateStartDate + } + ); + }} + isValid={genericFieldInfo.expiryDate.isValid} + errorText={genericFieldInfo.expiryDate.errorText} + selectsEnd + /> + </div> + </GridItem> + </GridSection> + ); }; class EntitlementPoolsEditorView extends React.Component { + static propTypes = { + data: EntitlementPoolPropType, + previousData: EntitlementPoolPropType, + EPNames: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - static propTypes = { - data: EntitlementPoolPropType, - previousData: EntitlementPoolPropType, - EPNames: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; - - static defaultProps = { - data: {} - }; - - componentDidUpdate(prevProps) { - if (this.props.formReady && this.props.formReady !== prevProps.formReady) { // if form validation succeeded -> continue with submit - this.submit(); - } - } + static defaultProps = { + data: {} + }; - state = { - selectedTab: tabIds.GENERAL, - selectedLimit: '' - }; + componentDidUpdate(prevProps) { + if ( + this.props.formReady && + this.props.formReady !== prevProps.formReady + ) { + // if form validation succeeded -> continue with submit + this.submit(); + } + } - render() { - let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo, onCloseLimitEditor, limitsList = []} = this.props; - const {selectedTab} = this.state; - const isTabsDisabled = !data.id || !this.props.isFormValid; + state = { + selectedTab: tabIds.GENERAL, + selectedLimit: '' + }; - return ( - <div> - <Tabs - type='menu' - activeTab={selectedTab} - onTabClick={(tabIndex)=>{ - if (tabIndex === tabIds.ADD_LIMIT_BUTTON) { - this.onAddLimit(); - } else { - this.setState({selectedTab: tabIndex}); - this.setState({selectedLimit: ''}); - onCloseLimitEditor(); - } - }} - invalidTabs={[]}> - <Tab tabId={tabIds.GENERAL} data-test-id='general-tab' title={i18n('General')}> - { - genericFieldInfo && <Form - ref='validationForm' - hasButtons={false} - labledButtons={false} - isReadOnlyMode={isReadOnlyMode} - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM) } - className='license-model-form entitlement-pools-form'> - <EntitlementPoolsFormContent - data={data} - genericFieldInfo={genericFieldInfo} - onDataChanged={onDataChanged} - validateName={(value) => this.validateName(value)} - validateStartDate={(value, state) => validateStartDate(value, state)} - thresholdValueValidation={(value, state) => thresholdValueValidation(value, state)}/> - </Form> - } - </Tab> - <Tab disabled={isTabsDisabled} tabId={tabIds.SP_LIMITS} data-test-id='sp-limits-tab' title={i18n('SP Limits')}> - {selectedTab === tabIds.SP_LIMITS && - <EntitlementPoolsLimits - isReadOnlyMode={isReadOnlyMode} - limitType={limitType.SERVICE_PROVIDER} - limitsList={limitsList.filter(item => item.type === limitType.SERVICE_PROVIDER)} - selectedLimit={this.state.selectedLimit} - onCloseLimitEditor={() => this.onCloseLimitEditor()} - onSelectLimit={limit => this.onSelectLimit(limit)}/>} - </Tab> - <Tab disabled={isTabsDisabled} tabId={tabIds.VENDOR_LIMITS} data-test-id='vendor-limits-tab' title={i18n('Vendor Limits')}> - {selectedTab === tabIds.VENDOR_LIMITS && - <EntitlementPoolsLimits - isReadOnlyMode={isReadOnlyMode} - limitType={limitType.VENDOR} - limitsList={limitsList.filter(item => item.type === limitType.VENDOR)} - selectedLimit={this.state.selectedLimit} - onCloseLimitEditor={() => this.onCloseLimitEditor()} - onSelectLimit={limit => this.onSelectLimit(limit)}/>} - </Tab> - { - selectedTab !== tabIds.GENERAL ? - <Button - disabled={this.state.selectedLimit || isReadOnlyMode} - className='add-limit-button' - tabId={tabIds.ADD_LIMIT_BUTTON} - btnType='link' - iconName='plus'> - {i18n('Add Limit')} - </Button> - : - <div key='empty_ep_tab_key'></div> // Render empty div to not break tabs - } - </Tabs> - <GridSection className='license-model-modal-buttons entitlement-pools-editor-buttons'> - {!this.state.selectedLimit && - <Button btnType='default' disabled={!this.props.isFormValid || isReadOnlyMode} onClick={() => this.submit()} type='reset'> - {i18n('Save')} - </Button> - } - <Button btnType={this.state.selectedLimit ? 'default' : 'outline'} onClick={() => this.props.onCancel()} type='reset'> - {i18n('Cancel')} - </Button> - </GridSection> - </div> - ); - } + render() { + let { + data = {}, + onDataChanged, + isReadOnlyMode, + genericFieldInfo, + onCloseLimitEditor, + limitsList = [] + } = this.props; + const { selectedTab } = this.state; + const isTabsDisabled = !data.id || !this.props.isFormValid; - submit() { - const {data: entitlementPool, previousData: previousEntitlementPool, formReady} = this.props; - if (!formReady) { - this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM); - } else { - this.props.onSubmit({entitlementPool, previousEntitlementPool}); - } - } + return ( + <div> + <Tabs + type="menu" + activeTab={selectedTab} + onTabClick={tabIndex => { + if (tabIndex === tabIds.ADD_LIMIT_BUTTON) { + this.onAddLimit(); + } else { + this.setState({ selectedTab: tabIndex }); + this.setState({ selectedLimit: '' }); + onCloseLimitEditor(); + } + }} + invalidTabs={[]}> + <Tab + tabId={tabIds.GENERAL} + data-test-id="general-tab" + title={i18n('General')}> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={false} + labledButtons={false} + isReadOnlyMode={isReadOnlyMode} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => + this.props.onValidateForm( + SP_ENTITLEMENT_POOL_FORM + ) + } + className="license-model-form entitlement-pools-form"> + <EntitlementPoolsFormContent + data={data} + genericFieldInfo={genericFieldInfo} + onDataChanged={onDataChanged} + validateName={value => + this.validateName(value) + } + validateStartDate={(value, state) => + validateStartDate(value, state) + } + thresholdValueValidation={(value, state) => + thresholdValueValidation(value, state) + } + /> + </Form> + )} + </Tab> + <Tab + disabled={isTabsDisabled} + tabId={tabIds.SP_LIMITS} + data-test-id="sp-limits-tab" + title={i18n('SP Limits')}> + {selectedTab === tabIds.SP_LIMITS && ( + <EntitlementPoolsLimits + isReadOnlyMode={isReadOnlyMode} + limitType={limitType.SERVICE_PROVIDER} + limitsList={limitsList.filter( + item => + item.type === limitType.SERVICE_PROVIDER + )} + selectedLimit={this.state.selectedLimit} + onCloseLimitEditor={() => + this.onCloseLimitEditor() + } + onSelectLimit={limit => + this.onSelectLimit(limit) + } + /> + )} + </Tab> + <Tab + disabled={isTabsDisabled} + tabId={tabIds.VENDOR_LIMITS} + data-test-id="vendor-limits-tab" + title={i18n('Vendor Limits')}> + {selectedTab === tabIds.VENDOR_LIMITS && ( + <EntitlementPoolsLimits + isReadOnlyMode={isReadOnlyMode} + limitType={limitType.VENDOR} + limitsList={limitsList.filter( + item => item.type === limitType.VENDOR + )} + selectedLimit={this.state.selectedLimit} + onCloseLimitEditor={() => + this.onCloseLimitEditor() + } + onSelectLimit={limit => + this.onSelectLimit(limit) + } + /> + )} + </Tab> + {selectedTab !== tabIds.GENERAL ? ( + <Button + disabled={ + this.state.selectedLimit || isReadOnlyMode + } + className="add-limit-button" + tabId={tabIds.ADD_LIMIT_BUTTON} + btnType="link" + iconName="plus"> + {i18n('Add Limit')} + </Button> + ) : ( + <div key="empty_ep_tab_key" /> + ) // Render empty div to not break tabs + } + </Tabs> + <GridSection className="license-model-modal-buttons entitlement-pools-editor-buttons"> + {!this.state.selectedLimit && ( + <Button + btnType="default" + disabled={!this.props.isFormValid || isReadOnlyMode} + onClick={() => this.submit()} + type="reset"> + {i18n('Save')} + </Button> + )} + <Button + btnType={ + this.state.selectedLimit ? 'default' : 'outline' + } + onClick={() => this.props.onCancel()} + type="reset"> + {i18n('Cancel')} + </Button> + </GridSection> + </div> + ); + } - validateName(value) { - const {data: {id}, EPNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: EPNames}); + submit() { + const { + data: entitlementPool, + previousData: previousEntitlementPool, + formReady + } = this.props; + if (!formReady) { + this.props.onValidateForm(SP_ENTITLEMENT_POOL_FORM); + } else { + this.props.onSubmit({ entitlementPool, previousEntitlementPool }); + } + } - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('Entitlement pool by the name \'' + value + '\' already exists. Entitlement pool name must be unique')}; - } + validateName(value) { + const { data: { id }, EPNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: EPNames + }); - onSelectLimit(limit) { - if (limit.id === this.state.selectedLimit) { - this.setState({selectedLimit: ''}); - return; - } - this.setState({selectedLimit: limit.id}); - this.props.onOpenLimitEditor(limit); - } + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "Entitlement pool by the name '" + + value + + "' already exists. Entitlement pool name must be unique" + ) + }; + } - onCloseLimitEditor() { - this.setState({selectedLimit: ''}); - this.props.onCloseLimitEditor(); - } + onSelectLimit(limit) { + if (limit.id === this.state.selectedLimit) { + this.setState({ selectedLimit: '' }); + return; + } + this.setState({ selectedLimit: limit.id }); + this.props.onOpenLimitEditor(limit); + } - onAddLimit() { - this.setState({selectedLimit: NEW_LIMIT_TEMP_ID}); - this.props.onOpenLimitEditor(); - } + onCloseLimitEditor() { + this.setState({ selectedLimit: '' }); + this.props.onCloseLimitEditor(); + } + onAddLimit() { + this.setState({ selectedLimit: NEW_LIMIT_TEMP_ID }); + this.props.onOpenLimitEditor(); + } } export default EntitlementPoolsEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsLimits.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsLimits.js index 8300594098..fd5fe6dd21 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsLimits.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsLimits.js @@ -13,44 +13,74 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import Limits from 'sdc-app/onboarding/licenseModel/limits/Limits.jsx'; -import {actionTypes as globalModalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as globalModalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; -const mapStateToProps = ({licenseModel: {entitlementPool: {entitlementPoolEditor: {data}}, limitEditor}, currentScreen}) => { - let {props: {licenseModelId, version}} = currentScreen; - return { - parent: data, - limitEditor, - licenseModelId, - version - }; +const mapStateToProps = ({ + licenseModel: { + entitlementPool: { entitlementPoolEditor: { data } }, + limitEditor + }, + currentScreen +}) => { + let { props: { licenseModelId, version } } = currentScreen; + return { + parent: data, + limitEditor, + licenseModelId, + version + }; }; -const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onSubmit: (limit, entitlementPool, licenseModelId, version) => EntitlementPoolsActionHelper.submitLimit(dispatch, - { - limit, - entitlementPool, - licenseModelId, - version}), - onDelete: ({limit, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit}) => dispatch({ - type: globalModalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete {name}?', {name: limit.name}), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=> EntitlementPoolsActionHelper.deleteLimit(dispatch, {limit, entitlementPool: parent, licenseModelId, version}).then(() => - selectedLimit === limit.id && onCloseLimitEditor() - ) - } - }) - }; +const mapActionsToProps = dispatch => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onSubmit: (limit, entitlementPool, licenseModelId, version) => + EntitlementPoolsActionHelper.submitLimit(dispatch, { + limit, + entitlementPool, + licenseModelId, + version + }), + onDelete: ({ + limit, + parent, + licenseModelId, + version, + onCloseLimitEditor, + selectedLimit + }) => + dispatch({ + type: globalModalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete {name}?', { + name: limit.name + }), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + EntitlementPoolsActionHelper.deleteLimit(dispatch, { + limit, + entitlementPool: parent, + licenseModelId, + version + }).then( + () => + selectedLimit === limit.id && + onCloseLimitEditor() + ) + } + }) + }; }; export default connect(mapStateToProps, mapActionsToProps)(Limits); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js index f1dc1f8542..819fb7d824 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditor.js @@ -13,45 +13,60 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import EntitlementPoolsActionHelper from './EntitlementPoolsActionHelper.js'; -import EntitlementPoolsListEditorView, {generateConfirmationMsg} from './EntitlementPoolsListEditorView.jsx'; -import {actionTypes as globalMoadlActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import EntitlementPoolsListEditorView, { + generateConfirmationMsg +} from './EntitlementPoolsListEditorView.jsx'; +import { actionTypes as globalMoadlActions } from 'nfvo-components/modal/GlobalModalConstants.js'; -const mapStateToProps = ({licenseModel: {entitlementPool, licenseModelEditor}}) => { - - const {entitlementPoolsList} = entitlementPool; - const {data} = entitlementPool.entitlementPoolEditor; - const {vendorName} = licenseModelEditor.data; - - return { - vendorName, - entitlementPoolsList, - isDisplayModal: Boolean(data), - isModalInEditMode: Boolean(data && data.id), - }; +const mapStateToProps = ({ + licenseModel: { entitlementPool, licenseModelEditor } +}) => { + const { entitlementPoolsList } = entitlementPool; + const { data } = entitlementPool.entitlementPoolEditor; + const { vendorName } = licenseModelEditor.data; + return { + vendorName, + entitlementPoolsList, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; }; -const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onAddEntitlementPoolClick: () => EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch), - onEditEntitlementPoolClick: entitlementPool => EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch, {entitlementPool, licenseModelId, version}), - onDeleteEntitlementPool: entitlementPool => dispatch({ - type: globalMoadlActions.GLOBAL_MODAL_WARNING, - data:{ - msg: generateConfirmationMsg(entitlementPool), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: () => EntitlementPoolsActionHelper.deleteEntitlementPool(dispatch, { - licenseModelId, - entitlementPoolId: entitlementPool.id, - version - }) - } - }) - }; +const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onAddEntitlementPoolClick: () => + EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch), + onEditEntitlementPoolClick: entitlementPool => + EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch, { + entitlementPool, + licenseModelId, + version + }), + onDeleteEntitlementPool: entitlementPool => + dispatch({ + type: globalMoadlActions.GLOBAL_MODAL_WARNING, + data: { + msg: generateConfirmationMsg(entitlementPool), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + EntitlementPoolsActionHelper.deleteEntitlementPool( + dispatch, + { + licenseModelId, + entitlementPoolId: entitlementPool.id, + version + } + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(EntitlementPoolsListEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + EntitlementPoolsListEditorView +); 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 cc0cda1992..7a07f94bd5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListEditorView.jsx @@ -22,120 +22,162 @@ import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; import EntitlementPoolsEditor from './EntitlementPoolsEditor.js'; -import {extractUnits} from './EntitlementPoolsConstants'; +import { extractUnits } from './EntitlementPoolsConstants'; class EntitlementPoolsListEditorView extends React.Component { - static propTypes = { - vendorName: PropTypes.string, - licenseModelId: PropTypes.string.isRequired, - entitlementPoolsList: PropTypes.array, - isReadOnlyMode: PropTypes.bool.isRequired, - isDisplayModal: PropTypes.bool, - isModalInEditMode: PropTypes.bool, - onAddEntitlementPoolClick: PropTypes.func, - onEditEntitlementPoolClick: PropTypes.func, - onDeleteEntitlementPool: PropTypes.func, - }; + static propTypes = { + vendorName: PropTypes.string, + licenseModelId: PropTypes.string.isRequired, + entitlementPoolsList: PropTypes.array, + isReadOnlyMode: PropTypes.bool.isRequired, + isDisplayModal: PropTypes.bool, + isModalInEditMode: PropTypes.bool, + onAddEntitlementPoolClick: PropTypes.func, + onEditEntitlementPoolClick: PropTypes.func, + onDeleteEntitlementPool: PropTypes.func + }; - static defaultProps = { - entitlementPoolsList: [] - }; + static defaultProps = { + entitlementPoolsList: [] + }; - state = { - localFilter: '' - }; + state = { + localFilter: '' + }; - render() { - let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; - let {onAddEntitlementPoolClick} = this.props; - const {localFilter} = this.state; + render() { + let { + licenseModelId, + isReadOnlyMode, + isDisplayModal, + isModalInEditMode, + version + } = this.props; + let { onAddEntitlementPoolClick } = this.props; + const { localFilter } = this.state; - return ( - <div className='license-model-list-editor entitlement-pools-list-editor'> - <ListEditorView - title={i18n('Entitlement Pools')} - plusButtonTitle={i18n('Add Entitlement Pool')} - onAdd={onAddEntitlementPoolClick} - filterValue={localFilter} - onFilter={value => this.setState({localFilter: value})} - isReadOnlyMode={isReadOnlyMode}> - {this.filterList().map(entitlementPool => this.renderEntitlementPoolListItem(entitlementPool, isReadOnlyMode))} - </ListEditorView> - <Modal show={isDisplayModal} bsSize='large' animation={true} className='onborading-modal license-model-modal entitlement-pools-modal'> - <Modal.Header> - <Modal.Title>{`${isModalInEditMode ? i18n('Edit Entitlement Pool') : i18n('Create New Entitlement Pool')}`}</Modal.Title> - </Modal.Header> - <Modal.Body> - { - isDisplayModal && ( - <EntitlementPoolsEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/> - ) - } - </Modal.Body> - </Modal> - </div> - ); - } + return ( + <div className="license-model-list-editor entitlement-pools-list-editor"> + <ListEditorView + title={i18n('Entitlement Pools')} + plusButtonTitle={i18n('Add Entitlement Pool')} + onAdd={onAddEntitlementPoolClick} + filterValue={localFilter} + onFilter={value => this.setState({ localFilter: value })} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(entitlementPool => + this.renderEntitlementPoolListItem( + entitlementPool, + isReadOnlyMode + ) + )} + </ListEditorView> + <Modal + show={isDisplayModal} + bsSize="large" + animation={true} + className="onborading-modal license-model-modal entitlement-pools-modal"> + <Modal.Header> + <Modal.Title>{`${ + isModalInEditMode + ? i18n('Edit Entitlement Pool') + : i18n('Create New Entitlement Pool') + }`}</Modal.Title> + </Modal.Header> + <Modal.Body> + {isDisplayModal && ( + <EntitlementPoolsEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </Modal.Body> + </Modal> + </div> + ); + } - filterList() { - let {entitlementPoolsList} = this.props; - let {localFilter} = this.state; - if(localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return entitlementPoolsList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return entitlementPoolsList; - } - } + filterList() { + let { entitlementPoolsList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return entitlementPoolsList.filter( + ({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + } + ); + } else { + return entitlementPoolsList; + } + } - renderEntitlementPoolListItem(entitlementPool, isReadOnlyMode) { - let {id, name, description, thresholdValue, thresholdUnits} = entitlementPool; - let {onEditEntitlementPoolClick, onDeleteEntitlementPool} = this.props; - return ( - <ListEditorItemView - key={id} - onSelect={() => onEditEntitlementPoolClick(entitlementPool)} - onDelete={() => onDeleteEntitlementPool(entitlementPool)} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode}> - <div className='list-editor-item-view-field'> + renderEntitlementPoolListItem(entitlementPool, isReadOnlyMode) { + let { + id, + name, + description, + thresholdValue, + thresholdUnits + } = entitlementPool; + let { + onEditEntitlementPoolClick, + onDeleteEntitlementPool + } = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => onEditEntitlementPoolClick(entitlementPool)} + onDelete={() => onDeleteEntitlementPool(entitlementPool)} + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div> + <div className="textEllipses text name">{name}</div> + </div> + </div> - <div className='title'>{i18n('Name')}</div> - <div ><div className='textEllipses text name'>{name}</div></div> - </div> - - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Entitlement')}</div> - <div className='entitlement-pools-count'>{thresholdValue && `${thresholdValue} ${extractUnits(thresholdUnits)}`}</div> - </div> - - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Description')}</div> - <div className='text description'>{description}</div> - </div> - </ListEditorItemView> - ); - } + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Entitlement')}</div> + <div className="entitlement-pools-count"> + {thresholdValue && + `${thresholdValue} ${extractUnits(thresholdUnits)}`} + </div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Description')}</div> + <div className="text description">{description}</div> + </div> + </ListEditorItemView> + ); + } } export default EntitlementPoolsListEditorView; export function generateConfirmationMsg(entitlementPoolToDelete) { - let poolName = entitlementPoolToDelete ? entitlementPoolToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{poolName}"?', {poolName: poolName}); - let subMsg = entitlementPoolToDelete - && entitlementPoolToDelete.referencingFeatureGroups - && entitlementPoolToDelete.referencingFeatureGroups.length > 0 ? - i18n('This entitlement pool is associated with one or more feature groups') : - ''; - return ( - <div> - <p>{msg}</p> - <p>{subMsg}</p> - </div> - ); + let poolName = entitlementPoolToDelete ? entitlementPoolToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{poolName}"?', { + poolName: poolName + }); + let subMsg = + entitlementPoolToDelete && + entitlementPoolToDelete.referencingFeatureGroups && + entitlementPoolToDelete.referencingFeatureGroups.length > 0 + ? i18n( + 'This entitlement pool is associated with one or more feature groups' + ) + : ''; + return ( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js index fefd823207..3c8621d9d8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsListReducer.js @@ -13,19 +13,29 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './EntitlementPoolsConstants'; +import { actionTypes } from './EntitlementPoolsConstants'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.ENTITLEMENT_POOLS_LIST_LOADED: - return [...action.response.results]; - case actionTypes.ADD_ENTITLEMENT_POOL: - return [...state, action.entitlementPool]; - case actionTypes.EDIT_ENTITLEMENT_POOL: - const indexForEdit = state.findIndex(entitlementPool => entitlementPool.id === action.entitlementPool.id); - return [...state.slice(0, indexForEdit), action.entitlementPool, ...state.slice(indexForEdit + 1)]; - case actionTypes.DELETE_ENTITLEMENT_POOL: - return state.filter(entitlementPool => entitlementPool.id !== action.entitlementPoolId); - default: - return state; - } + switch (action.type) { + case actionTypes.ENTITLEMENT_POOLS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_ENTITLEMENT_POOL: + return [...state, action.entitlementPool]; + case actionTypes.EDIT_ENTITLEMENT_POOL: + const indexForEdit = state.findIndex( + entitlementPool => + entitlementPool.id === action.entitlementPool.id + ); + return [ + ...state.slice(0, indexForEdit), + action.entitlementPool, + ...state.slice(indexForEdit + 1) + ]; + case actionTypes.DELETE_ENTITLEMENT_POOL: + return state.filter( + entitlementPool => + entitlementPool.id !== action.entitlementPoolId + ); + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js index 6edb1e1f0c..997a6e09ed 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditor.js @@ -13,66 +13,92 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; import FeatureGroupEditorView from './FeatureGroupEditorView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -export const mapStateToProps = ({licenseModel: {featureGroup, entitlementPool, licenseKeyGroup}}) => { - let {entitlementPoolsList = []} = entitlementPool; - let {licenseKeyGroupsList = []} = licenseKeyGroup; - const {featureGroupEditor} = featureGroup; - let {data, selectedTab, genericFieldInfo, formReady} = featureGroupEditor; - const featureGroupId = data ? data.id : null; - const list = featureGroup.featureGroupsList; +export const mapStateToProps = ({ + licenseModel: { featureGroup, entitlementPool, licenseKeyGroup } +}) => { + let { entitlementPoolsList = [] } = entitlementPool; + let { licenseKeyGroupsList = [] } = licenseKeyGroup; + const { featureGroupEditor } = featureGroup; + let { data, selectedTab, genericFieldInfo, formReady } = featureGroupEditor; + const featureGroupId = data ? data.id : null; + const list = featureGroup.featureGroupsList; - let previousData, FGNames = {}, isFormValid = true, invalidTabs = []; + let previousData, + FGNames = {}, + isFormValid = true, + invalidTabs = []; - if (featureGroupId) { - previousData = list.find(featureGroup => featureGroup.id === featureGroupId); - } + if (featureGroupId) { + previousData = list.find( + featureGroup => featureGroup.id === featureGroupId + ); + } - for (let i = 0; i < list.length; i++) { - FGNames[list[i].name.toLowerCase()] = list[i].id; - } + for (let i = 0; i < list.length; i++) { + FGNames[list[i].name.toLowerCase()] = list[i].id; + } - for (let field in genericFieldInfo) { - if (!genericFieldInfo[field].isValid) { - isFormValid = false; - let tabId = genericFieldInfo[field].tabId; - if (invalidTabs.indexOf(tabId) === -1) { - invalidTabs[invalidTabs.length] = genericFieldInfo[field].tabId; - } - } - } + for (let field in genericFieldInfo) { + if (!genericFieldInfo[field].isValid) { + isFormValid = false; + let tabId = genericFieldInfo[field].tabId; + if (invalidTabs.indexOf(tabId) === -1) { + invalidTabs[invalidTabs.length] = genericFieldInfo[field].tabId; + } + } + } - return { - data, - previousData, - selectedTab, - entitlementPoolsList, - licenseKeyGroupsList, - isFormValid, - formReady, - genericFieldInfo, - invalidTabs, - FGNames - }; + return { + data, + previousData, + selectedTab, + entitlementPoolsList, + licenseKeyGroupsList, + isFormValid, + formReady, + genericFieldInfo, + invalidTabs, + FGNames + }; }; - -const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onTabSelect: tab => FeatureGroupsActionHelper.selectEntitlementPoolsEditorTab(dispatch, {tab}), - onSubmit: (previousFeatureGroup, featureGroup) => { - FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch); - FeatureGroupsActionHelper.saveFeatureGroup(dispatch, {licenseModelId, previousFeatureGroup, featureGroup, version}); - }, - onCancel: () => FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch), - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; +const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onTabSelect: tab => + FeatureGroupsActionHelper.selectEntitlementPoolsEditorTab( + dispatch, + { + tab + } + ), + onSubmit: (previousFeatureGroup, featureGroup) => { + FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch); + FeatureGroupsActionHelper.saveFeatureGroup(dispatch, { + licenseModelId, + previousFeatureGroup, + featureGroup, + version + }); + }, + onCancel: () => + FeatureGroupsActionHelper.closeFeatureGroupsEditor(dispatch), + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(FeatureGroupEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + FeatureGroupEditorView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx index 6d0acaa65d..fc8269332a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupEditorView.jsx @@ -19,211 +19,320 @@ import Tabs from 'nfvo-components/input/validation/Tabs.jsx'; import Tab from 'sdc-ui/lib/react/Tab.js'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import {TabsForm as Form} from 'nfvo-components/input/validation/Form.jsx'; +import { TabsForm as Form } from 'nfvo-components/input/validation/Form.jsx'; import DualListboxView from 'nfvo-components/input/dualListbox/DualListboxView.jsx'; import Input from 'nfvo-components/input/validation/Input.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Validator from 'nfvo-utils/Validator.js'; -import {state as FeatureGroupStateConstants, FG_EDITOR_FORM} from './FeatureGroupsConstants.js'; +import { + state as FeatureGroupStateConstants, + FG_EDITOR_FORM +} from './FeatureGroupsConstants.js'; const FeatureGroupsPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - partNumber: PropTypes.string, - manufacturerReferenceNumber: PropTypes.string, - entitlementPoolsIds: PropTypes.arrayOf(PropTypes.string), - licenseKeyGroupsIds: PropTypes.arrayOf(PropTypes.string) + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + partNumber: PropTypes.string, + manufacturerReferenceNumber: PropTypes.string, + entitlementPoolsIds: PropTypes.arrayOf(PropTypes.string), + licenseKeyGroupsIds: PropTypes.arrayOf(PropTypes.string) }); -const GeneralTab = ({data = {}, onDataChanged, genericFieldInfo, validateName}) => { - let {name, description, partNumber, manufacturerReferenceNumber} = data; - return ( - <GridSection hasLastColSet> - <GridItem colSpan={2}> - <Input - groupClassName='field-section' - onChange={name => onDataChanged({name}, FG_EDITOR_FORM, {name: validateName})} - label={i18n('Name')} - data-test-id='create-fg-name' - value={name} - name='feature-group-name' - type='text' - isRequired={true} - isValid={genericFieldInfo.name.isValid} - errorText={genericFieldInfo.name.errorText} /> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - groupClassName='field-section' - className='description-field' - onChange={description => onDataChanged({description}, FG_EDITOR_FORM)} - data-test-id='create-fg-description' - label={i18n('Description')} - value={description} - name='feature-group-description' - type='textarea' - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} /> - </GridItem> - <GridItem colSpan={2}> - <Input - groupClassName='field-section' - onChange={partNumber => onDataChanged({partNumber}, FG_EDITOR_FORM)} - label={i18n('Part Number')} - data-test-id='create-fg-part-number' - value={partNumber} - isRequired={true} - type='text' - isValid={genericFieldInfo.partNumber.isValid} - errorText={genericFieldInfo.partNumber.errorText} /> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - groupClassName='field-section' - onChange={manufacturerReferenceNumber => onDataChanged({manufacturerReferenceNumber}, FG_EDITOR_FORM)} - label={i18n('Manufacturer Reference Number')} - data-test-id='create-fg-reference-number' - value={manufacturerReferenceNumber} - isRequired={true} - type='text' - isValid={genericFieldInfo.manufacturerReferenceNumber.isValid} - errorText={genericFieldInfo.manufacturerReferenceNumber.errorText} /> - </GridItem> - </GridSection> - ); +const GeneralTab = ({ + data = {}, + onDataChanged, + genericFieldInfo, + validateName +}) => { + let { name, description, partNumber, manufacturerReferenceNumber } = data; + return ( + <GridSection hasLastColSet> + <GridItem colSpan={2}> + <Input + groupClassName="field-section" + onChange={name => + onDataChanged({ name }, FG_EDITOR_FORM, { + name: validateName + }) + } + label={i18n('Name')} + data-test-id="create-fg-name" + value={name} + name="feature-group-name" + type="text" + isRequired={true} + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + groupClassName="field-section" + className="description-field" + onChange={description => + onDataChanged({ description }, FG_EDITOR_FORM) + } + data-test-id="create-fg-description" + label={i18n('Description')} + value={description} + name="feature-group-description" + type="textarea" + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + /> + </GridItem> + <GridItem colSpan={2}> + <Input + groupClassName="field-section" + onChange={partNumber => + onDataChanged({ partNumber }, FG_EDITOR_FORM) + } + label={i18n('Part Number')} + data-test-id="create-fg-part-number" + value={partNumber} + isRequired={true} + type="text" + isValid={genericFieldInfo.partNumber.isValid} + errorText={genericFieldInfo.partNumber.errorText} + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + groupClassName="field-section" + onChange={manufacturerReferenceNumber => + onDataChanged( + { manufacturerReferenceNumber }, + FG_EDITOR_FORM + ) + } + label={i18n('Manufacturer Reference Number')} + data-test-id="create-fg-reference-number" + value={manufacturerReferenceNumber} + isRequired={true} + type="text" + isValid={ + genericFieldInfo.manufacturerReferenceNumber.isValid + } + errorText={ + genericFieldInfo.manufacturerReferenceNumber.errorText + } + /> + </GridItem> + </GridSection> + ); }; -const EntitlementPoolsTab = ({entitlementPoolsList, data, onDataChanged, isReadOnlyMode}) => { - const dualBoxFilterTitle = { - left: i18n('Available Entitlement Pools'), - right: i18n('Selected Entitlement Pools') - }; - if (entitlementPoolsList.length > 0) { - return ( - <DualListboxView - isReadOnlyMode={isReadOnlyMode} - filterTitle={dualBoxFilterTitle} - selectedValuesList={data.entitlementPoolsIds} - availableList={entitlementPoolsList} - onChange={ selectedValuesList => onDataChanged( { entitlementPoolsIds: selectedValuesList }, FG_EDITOR_FORM )}/> - ); - } else { - return ( - <p>{i18n('There are no available entitlement pools')}</p> - ); - } +const EntitlementPoolsTab = ({ + entitlementPoolsList, + data, + onDataChanged, + isReadOnlyMode +}) => { + const dualBoxFilterTitle = { + left: i18n('Available Entitlement Pools'), + right: i18n('Selected Entitlement Pools') + }; + if (entitlementPoolsList.length > 0) { + return ( + <DualListboxView + isReadOnlyMode={isReadOnlyMode} + filterTitle={dualBoxFilterTitle} + selectedValuesList={data.entitlementPoolsIds} + availableList={entitlementPoolsList} + onChange={selectedValuesList => + onDataChanged( + { entitlementPoolsIds: selectedValuesList }, + FG_EDITOR_FORM + ) + } + /> + ); + } else { + return <p>{i18n('There are no available entitlement pools')}</p>; + } }; -const LKGTab = ({licenseKeyGroupsList, data, onDataChanged, isReadOnlyMode}) => { - const dualBoxFilterTitle = { - left: i18n('Available License Key Groups'), - right: i18n('Selected License Key Groups') - }; - if (licenseKeyGroupsList.length > 0) { - return ( - <DualListboxView - isReadOnlyMode={isReadOnlyMode} - filterTitle={dualBoxFilterTitle} - selectedValuesList={data.licenseKeyGroupsIds} - availableList={licenseKeyGroupsList} - onChange={ selectedValuesList => onDataChanged( { licenseKeyGroupsIds: selectedValuesList }, FG_EDITOR_FORM )}/> - ); - } else { - return ( - <p>{i18n('There are no available license key groups')}</p> - ); - } +const LKGTab = ({ + licenseKeyGroupsList, + data, + onDataChanged, + isReadOnlyMode +}) => { + const dualBoxFilterTitle = { + left: i18n('Available License Key Groups'), + right: i18n('Selected License Key Groups') + }; + if (licenseKeyGroupsList.length > 0) { + return ( + <DualListboxView + isReadOnlyMode={isReadOnlyMode} + filterTitle={dualBoxFilterTitle} + selectedValuesList={data.licenseKeyGroupsIds} + availableList={licenseKeyGroupsList} + onChange={selectedValuesList => + onDataChanged( + { licenseKeyGroupsIds: selectedValuesList }, + FG_EDITOR_FORM + ) + } + /> + ); + } else { + return <p>{i18n('There are no available license key groups')}</p>; + } }; class FeatureGroupEditorView extends React.Component { + static propTypes = { + data: FeatureGroupsPropType, + previousData: FeatureGroupsPropType, + isReadOnlyMode: PropTypes.bool, + FGNames: PropTypes.object, + onSubmit: PropTypes.func, + onCancel: PropTypes.func, - static propTypes = { - data: FeatureGroupsPropType, - previousData: FeatureGroupsPropType, - isReadOnlyMode: PropTypes.bool, - FGNames: PropTypes.object, - - onSubmit: PropTypes.func, - onCancel: PropTypes.func, - - selectedTab: PropTypes.number, - onTabSelect: PropTypes.func, - - entitlementPoolsList: DualListboxView.propTypes.availableList, - licenseKeyGroupsList: DualListboxView.propTypes.availableList - }; - - - static defaultProps = { - data: {}, - selectedTab: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL, - }; - - state = { - localEntitlementPoolsListFilter: '', - localLicenseKeyGroupsListFilter: '' - }; - - - render() { - let {selectedTab, onTabSelect, isReadOnlyMode, invalidTabs, data, onDataChanged, genericFieldInfo, entitlementPoolsList, licenseKeyGroupsList} = this.props; - return ( - <div> - { genericFieldInfo && <Form - ref='validationForm' - hasButtons={true} - onSubmit={ () => this.submit() } - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.props.onValidateForm(FG_EDITOR_FORM) } - onReset={ () => this.props.onCancel() } - labledButtons={true} - isReadOnlyMode={isReadOnlyMode} - name='feature-group-validation-form' - className='license-model-form feature-group-form'> - <Tabs activeTab={onTabSelect ? selectedTab : undefined} onTabClick={onTabSelect} invalidTabs={invalidTabs} id='vlmFGValTabs' > - <Tab tabId={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL} title={i18n('General')} > - <fieldset disabled={isReadOnlyMode}> - <GeneralTab data={data} onDataChanged={onDataChanged} genericFieldInfo={genericFieldInfo} validateName={(value)=> this.validateName(value)}/> - </fieldset> - </Tab> - <Tab - tabId={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.ENTITLEMENT_POOLS} - title={i18n('Entitlement Pools')} > - <fieldset disabled={isReadOnlyMode}> - <EntitlementPoolsTab isReadOnlyMode={isReadOnlyMode} data={data} onDataChanged={onDataChanged} entitlementPoolsList={entitlementPoolsList} /> - </fieldset> - </Tab> - <Tab - tabId={FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.LICENSE_KEY_GROUPS} - title={i18n('License Key Groups')} > - <fieldset disabled={isReadOnlyMode}> - <LKGTab isReadOnlyMode={isReadOnlyMode} data={data} onDataChanged={onDataChanged} licenseKeyGroupsList={licenseKeyGroupsList} /> - </fieldset> - </Tab> - </Tabs> - - </Form> } - </div> - ); - } - - submit() { - const {data: featureGroup, previousData: previousFeatureGroup} = this.props; - this.props.onSubmit(previousFeatureGroup, featureGroup); - } - - validateName(value) { - const {data: {id}, FGNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: FGNames}); - - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('Feature group by the name \'' + value + '\' already exists. Feature group name must be unique')}; - } -} + selectedTab: PropTypes.number, + onTabSelect: PropTypes.func, + + entitlementPoolsList: DualListboxView.propTypes.availableList, + licenseKeyGroupsList: DualListboxView.propTypes.availableList + }; + + static defaultProps = { + data: {}, + selectedTab: + FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL + }; + + state = { + localEntitlementPoolsListFilter: '', + localLicenseKeyGroupsListFilter: '' + }; + render() { + let { + selectedTab, + onTabSelect, + isReadOnlyMode, + invalidTabs, + data, + onDataChanged, + genericFieldInfo, + entitlementPoolsList, + licenseKeyGroupsList + } = this.props; + return ( + <div> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={true} + onSubmit={() => this.submit()} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => + this.props.onValidateForm(FG_EDITOR_FORM) + } + onReset={() => this.props.onCancel()} + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + name="feature-group-validation-form" + className="license-model-form feature-group-form"> + <Tabs + activeTab={onTabSelect ? selectedTab : undefined} + onTabClick={onTabSelect} + invalidTabs={invalidTabs} + id="vlmFGValTabs"> + <Tab + tabId={ + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB.GENERAL + } + title={i18n('General')}> + <fieldset disabled={isReadOnlyMode}> + <GeneralTab + data={data} + onDataChanged={onDataChanged} + genericFieldInfo={genericFieldInfo} + validateName={value => + this.validateName(value) + } + /> + </fieldset> + </Tab> + <Tab + tabId={ + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB + .ENTITLEMENT_POOLS + } + title={i18n('Entitlement Pools')}> + <fieldset disabled={isReadOnlyMode}> + <EntitlementPoolsTab + isReadOnlyMode={isReadOnlyMode} + data={data} + onDataChanged={onDataChanged} + entitlementPoolsList={ + entitlementPoolsList + } + /> + </fieldset> + </Tab> + <Tab + tabId={ + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB + .LICENSE_KEY_GROUPS + } + title={i18n('License Key Groups')}> + <fieldset disabled={isReadOnlyMode}> + <LKGTab + isReadOnlyMode={isReadOnlyMode} + data={data} + onDataChanged={onDataChanged} + licenseKeyGroupsList={ + licenseKeyGroupsList + } + /> + </fieldset> + </Tab> + </Tabs> + </Form> + )} + </div> + ); + } + + submit() { + const { + data: featureGroup, + previousData: previousFeatureGroup + } = this.props; + this.props.onSubmit(previousFeatureGroup, featureGroup); + } + + validateName(value) { + const { data: { id }, FGNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: FGNames + }); + + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "Feature group by the name '" + + value + + "' already exists. Feature group name must be unique" + ) + }; + } +} export default FeatureGroupEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js index 26925487db..55e2710231 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditor.js @@ -13,48 +13,62 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; -import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; -import FeatureGroupListEditorView, {generateConfirmationMsg} from './FeatureGroupListEditorView.jsx'; +import { connect } from 'react-redux'; +import FeatureGroupsActionHelper from './FeatureGroupsActionHelper.js'; +import FeatureGroupListEditorView, { + generateConfirmationMsg +} from './FeatureGroupListEditorView.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as globalMoadlActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as globalMoadlActions } from 'nfvo-components/modal/GlobalModalConstants.js'; -export const mapStateToProps = ({licenseModel: {featureGroup, licenseModelEditor}}) => { - - const {featureGroupEditor: {data}, featureGroupsList} = featureGroup; - const {vendorName, version} = licenseModelEditor.data; - - return { - vendorName, - version, - featureGroupsModal: { - show: Boolean(data), - editMode: Boolean(data && data.id) - }, - featureGroupsList - }; +export const mapStateToProps = ({ + licenseModel: { featureGroup, licenseModelEditor } +}) => { + const { featureGroupEditor: { data }, featureGroupsList } = featureGroup; + const { vendorName, version } = licenseModelEditor.data; + return { + vendorName, + version, + featureGroupsModal: { + show: Boolean(data), + editMode: Boolean(data && data.id) + }, + featureGroupsList + }; }; - -const mapActionsToProps = (dispatch, {licenseModelId}) => { - return { - onDeleteFeatureGroupClick: (featureGroup, version) => dispatch({ - type: globalMoadlActions.GLOBAL_MODAL_WARNING, - data:{ - msg: generateConfirmationMsg(featureGroup), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=>FeatureGroupsActionHelper.deleteFeatureGroup(dispatch, {featureGroupId: featureGroup.id, licenseModelId, version}) - } - }), - onAddFeatureGroupClick: (actualVersion) => FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, {licenseModelId, version: actualVersion}), - onEditFeatureGroupClick: (featureGroup, actualVersion) => FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, { - featureGroup, - licenseModelId, - version: actualVersion - }) - }; +const mapActionsToProps = (dispatch, { licenseModelId }) => { + return { + onDeleteFeatureGroupClick: (featureGroup, version) => + dispatch({ + type: globalMoadlActions.GLOBAL_MODAL_WARNING, + data: { + msg: generateConfirmationMsg(featureGroup), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + FeatureGroupsActionHelper.deleteFeatureGroup(dispatch, { + featureGroupId: featureGroup.id, + licenseModelId, + version + }) + } + }), + onAddFeatureGroupClick: actualVersion => + FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, { + licenseModelId, + version: actualVersion + }), + onEditFeatureGroupClick: (featureGroup, actualVersion) => + FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, { + featureGroup, + licenseModelId, + version: actualVersion + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(FeatureGroupListEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + FeatureGroupListEditorView +); 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 f59e000c21..91f77b3111 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupListEditorView.jsx @@ -24,147 +24,184 @@ import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.js import FeatureGroupEditor from './FeatureGroupEditor.js'; class FeatureGroupListEditorView extends React.Component { - static propTypes = { - vendorName: PropTypes.string, - licenseModelId: PropTypes.string.isRequired, - featureGroupsModal: PropTypes.shape({ - show: PropTypes.bool, - editMode: PropTypes.bool - }), - isReadOnlyMode: PropTypes.bool.isRequired, - onAddFeatureGroupClick: PropTypes.func, - onEditFeatureGroupClick: PropTypes.func, - onDeleteFeatureGroupClick: PropTypes.func, - onCancelFeatureGroupsEditor: PropTypes.func, - featureGroupsList: PropTypes.array - }; - - static defaultProps = { - featureGroupsList: [], - featureGroupsModal: { - show: false, - editMode: false - } - }; - - state = { - localFilter: '' - }; - - render() { - let {licenseModelId, featureGroupsModal, isReadOnlyMode, onAddFeatureGroupClick, version} = this.props; - const {localFilter} = this.state; - return ( - <div className='license-model-list-editor feature-groups-list-editor'> - <ListEditorView - title={i18n('Feature Groups')} - plusButtonTitle={i18n('Add Feature Group')} - filterValue={localFilter} - onFilter={value => this.setState({localFilter: value})} - onAdd={() => onAddFeatureGroupClick(version)} - isReadOnlyMode={isReadOnlyMode}> - {this.filterList().map(listItem => this.renderFeatureGroupListItem(listItem, isReadOnlyMode, version))} - </ListEditorView> - {featureGroupsModal.show && <Modal show={featureGroupsModal.show} bsSize='large' animation={true} - className='onborading-modal license-model-modal feature-group-modal'> - <Modal.Header> - <Modal.Title>{`${featureGroupsModal.editMode ? i18n('Edit Feature Group') : i18n('Create New Feature Group')}`}</Modal.Title> - </Modal.Header> - <Modal.Body> - <FeatureGroupEditor - version={version} - licenseModelId={licenseModelId} - isReadOnlyMode={isReadOnlyMode}/> - </Modal.Body> - </Modal> - } - - </div> - ); - } - - - renderFeatureGroupListItem(listItem, isReadOnlyMode, version) { - let {name, description, manufacturerReferenceNumber, entitlementPoolsIds = [], licenseKeyGroupsIds = []} = listItem; - return ( - <ListEditorItemView - key={listItem.id} - onDelete={() => this.deleteFeatureGroupItem(listItem, version)} - onSelect={() => this.editFeatureGroupItem(listItem, version)} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode}> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Name')}</div> - <div className='text name'>{name}</div> - </div> - - <div className='list-editor-item-view-field smaller-field'> - <div className='feature-groups-count-field'> - <div className='title'>{i18n('EP')}</div> - <div className='feature-groups-count-ep'>{entitlementPoolsIds.length || 0}</div> - </div> - </div> - <div className='list-editor-item-view-field smaller-field'> - <div className='feature-groups-count-field'> - <div className='title'>{i18n('LKG')}</div> - <div className='feature-groups-count-lk'>{licenseKeyGroupsIds.length || 0}</div> - </div> - </div> - - <div className='list-editor-item-view-field'> - <div className='feature-groups-count-field'> - <div className='title title-no-wrap'>{i18n('Manufacturer Reference Number')}</div> - <div className='feature-groups-mrn-ep'>{manufacturerReferenceNumber}</div> - </div> - </div> - - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Description')}</div> - <div className='text description'>{description}</div> - </div> - - - - </ListEditorItemView> - ); - } - - filterList() { - let {featureGroupsList} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return featureGroupsList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return featureGroupsList; - } - } - - editFeatureGroupItem(featureGroup, version) { - this.props.onEditFeatureGroupClick(featureGroup, version); - } - - deleteFeatureGroupItem(featureGroup, version) { - this.props.onDeleteFeatureGroupClick(featureGroup, version); - } + static propTypes = { + vendorName: PropTypes.string, + licenseModelId: PropTypes.string.isRequired, + featureGroupsModal: PropTypes.shape({ + show: PropTypes.bool, + editMode: PropTypes.bool + }), + isReadOnlyMode: PropTypes.bool.isRequired, + onAddFeatureGroupClick: PropTypes.func, + onEditFeatureGroupClick: PropTypes.func, + onDeleteFeatureGroupClick: PropTypes.func, + onCancelFeatureGroupsEditor: PropTypes.func, + featureGroupsList: PropTypes.array + }; + + static defaultProps = { + featureGroupsList: [], + featureGroupsModal: { + show: false, + editMode: false + } + }; + + state = { + localFilter: '' + }; + + render() { + let { + licenseModelId, + featureGroupsModal, + isReadOnlyMode, + onAddFeatureGroupClick, + version + } = this.props; + const { localFilter } = this.state; + return ( + <div className="license-model-list-editor feature-groups-list-editor"> + <ListEditorView + title={i18n('Feature Groups')} + plusButtonTitle={i18n('Add Feature Group')} + filterValue={localFilter} + onFilter={value => this.setState({ localFilter: value })} + onAdd={() => onAddFeatureGroupClick(version)} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(listItem => + this.renderFeatureGroupListItem( + listItem, + isReadOnlyMode, + version + ) + )} + </ListEditorView> + {featureGroupsModal.show && ( + <Modal + show={featureGroupsModal.show} + bsSize="large" + animation={true} + className="onborading-modal license-model-modal feature-group-modal"> + <Modal.Header> + <Modal.Title>{`${ + featureGroupsModal.editMode + ? i18n('Edit Feature Group') + : i18n('Create New Feature Group') + }`}</Modal.Title> + </Modal.Header> + <Modal.Body> + <FeatureGroupEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + </Modal.Body> + </Modal> + )} + </div> + ); + } + + renderFeatureGroupListItem(listItem, isReadOnlyMode, version) { + let { + name, + description, + manufacturerReferenceNumber, + entitlementPoolsIds = [], + licenseKeyGroupsIds = [] + } = listItem; + return ( + <ListEditorItemView + key={listItem.id} + onDelete={() => this.deleteFeatureGroupItem(listItem, version)} + onSelect={() => this.editFeatureGroupItem(listItem, version)} + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div className="text name">{name}</div> + </div> + + <div className="list-editor-item-view-field smaller-field"> + <div className="feature-groups-count-field"> + <div className="title">{i18n('EP')}</div> + <div className="feature-groups-count-ep"> + {entitlementPoolsIds.length || 0} + </div> + </div> + </div> + <div className="list-editor-item-view-field smaller-field"> + <div className="feature-groups-count-field"> + <div className="title">{i18n('LKG')}</div> + <div className="feature-groups-count-lk"> + {licenseKeyGroupsIds.length || 0} + </div> + </div> + </div> + + <div className="list-editor-item-view-field"> + <div className="feature-groups-count-field"> + <div className="title title-no-wrap"> + {i18n('Manufacturer Reference Number')} + </div> + <div className="feature-groups-mrn-ep"> + {manufacturerReferenceNumber} + </div> + </div> + </div> + + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Description')}</div> + <div className="text description">{description}</div> + </div> + </ListEditorItemView> + ); + } + + filterList() { + let { featureGroupsList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return featureGroupsList.filter( + ({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + } + ); + } else { + return featureGroupsList; + } + } + + editFeatureGroupItem(featureGroup, version) { + this.props.onEditFeatureGroupClick(featureGroup, version); + } + + deleteFeatureGroupItem(featureGroup, version) { + this.props.onDeleteFeatureGroupClick(featureGroup, version); + } } export default FeatureGroupListEditorView; export function generateConfirmationMsg(featureGroupToDelete) { - let name = featureGroupToDelete ? featureGroupToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{name}"?', {name: name}); - let subMsg = featureGroupToDelete.referencingLicenseAgreements - && featureGroupToDelete.referencingLicenseAgreements.length > 0 ? - i18n('This feature group is associated with one ore more license agreements') : - ''; - return ( - <div> - <p>{msg}</p> - <p>{subMsg}</p> - </div> - ); + let name = featureGroupToDelete ? featureGroupToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{name}"?', { name: name }); + let subMsg = + featureGroupToDelete.referencingLicenseAgreements && + featureGroupToDelete.referencingLicenseAgreements.length > 0 + ? i18n( + 'This feature group is associated with one ore more license agreements' + ) + : ''; + return ( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js index 9e7fe8e0dd..22e21a613a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js @@ -15,132 +15,202 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes as featureGroupsActionConstants} from './FeatureGroupsConstants.js'; +import { actionTypes as featureGroupsActionConstants } from './FeatureGroupsConstants.js'; import EntitlementPoolsActionHelper from 'sdc-app/onboarding/licenseModel/entitlementPools/EntitlementPoolsActionHelper.js'; import LicenseKeyGroupsActionHelper from 'sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; function baseUrl(licenseModelId, version) { - const restPrefix = Configuration.get('restPrefix'); - const {id: versionId} = version; - return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/feature-groups`; + const restPrefix = Configuration.get('restPrefix'); + const { id: versionId } = version; + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/feature-groups`; } function fetchFeatureGroup(licenseModelId, featureGroupId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}/${featureGroupId}`); + return RestAPIUtil.fetch( + `${baseUrl(licenseModelId, version)}/${featureGroupId}` + ); } function fetchFeatureGroupsList(licenseModelId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); } function deleteFeatureGroup(licenseModelId, featureGroupId, version) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${featureGroupId}`); + return RestAPIUtil.destroy( + `${baseUrl(licenseModelId, version)}/${featureGroupId}` + ); } function addFeatureGroup(licenseModelId, featureGroup, version) { - return RestAPIUtil.post(baseUrl(licenseModelId, version), { - name: featureGroup.name, - description: featureGroup.description, - partNumber: featureGroup.partNumber, - manufacturerReferenceNumber: featureGroup.manufacturerReferenceNumber, - addedLicenseKeyGroupsIds: featureGroup.licenseKeyGroupsIds, - addedEntitlementPoolsIds: featureGroup.entitlementPoolsIds - }); + return RestAPIUtil.post(baseUrl(licenseModelId, version), { + name: featureGroup.name, + description: featureGroup.description, + partNumber: featureGroup.partNumber, + manufacturerReferenceNumber: featureGroup.manufacturerReferenceNumber, + addedLicenseKeyGroupsIds: featureGroup.licenseKeyGroupsIds, + addedEntitlementPoolsIds: featureGroup.entitlementPoolsIds + }); } -function updateFeatureGroup(licenseModelId, previousFeatureGroup, featureGroup, version) { - - const {licenseKeyGroupsIds = []} = featureGroup; - const {licenseKeyGroupsIds: prevLicenseKeyGroupsIds = []} = previousFeatureGroup; - const {entitlementPoolsIds = []} = featureGroup; - const {entitlementPoolsIds: prevEntitlementPoolsIds = []} = previousFeatureGroup; - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${featureGroup.id}`, { - name: featureGroup.name, - description: featureGroup.description, - partNumber: featureGroup.partNumber, - manufacturerReferenceNumber: featureGroup.manufacturerReferenceNumber, - addedLicenseKeyGroupsIds: licenseKeyGroupsIds.filter(licenseKeyGroupId => prevLicenseKeyGroupsIds.indexOf(licenseKeyGroupId) === -1), - removedLicenseKeyGroupsIds: prevLicenseKeyGroupsIds.filter(prevLicenseKeyGroupId => licenseKeyGroupsIds.indexOf(prevLicenseKeyGroupId) === -1), - addedEntitlementPoolsIds: entitlementPoolsIds.filter(entitlementPoolId => prevEntitlementPoolsIds.indexOf(entitlementPoolId) === -1), - removedEntitlementPoolsIds: prevEntitlementPoolsIds.filter(prevEntitlementPoolId => entitlementPoolsIds.indexOf(prevEntitlementPoolId) === -1) - - }); +function updateFeatureGroup( + licenseModelId, + previousFeatureGroup, + featureGroup, + version +) { + const { licenseKeyGroupsIds = [] } = featureGroup; + const { + licenseKeyGroupsIds: prevLicenseKeyGroupsIds = [] + } = previousFeatureGroup; + const { entitlementPoolsIds = [] } = featureGroup; + const { + entitlementPoolsIds: prevEntitlementPoolsIds = [] + } = previousFeatureGroup; + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${featureGroup.id}`, + { + name: featureGroup.name, + description: featureGroup.description, + partNumber: featureGroup.partNumber, + manufacturerReferenceNumber: + featureGroup.manufacturerReferenceNumber, + addedLicenseKeyGroupsIds: licenseKeyGroupsIds.filter( + licenseKeyGroupId => + prevLicenseKeyGroupsIds.indexOf(licenseKeyGroupId) === -1 + ), + removedLicenseKeyGroupsIds: prevLicenseKeyGroupsIds.filter( + prevLicenseKeyGroupId => + licenseKeyGroupsIds.indexOf(prevLicenseKeyGroupId) === -1 + ), + addedEntitlementPoolsIds: entitlementPoolsIds.filter( + entitlementPoolId => + prevEntitlementPoolsIds.indexOf(entitlementPoolId) === -1 + ), + removedEntitlementPoolsIds: prevEntitlementPoolsIds.filter( + prevEntitlementPoolId => + entitlementPoolsIds.indexOf(prevEntitlementPoolId) === -1 + ) + } + ); } export default { - fetchFeatureGroup(dispatch, {licenseModelId, featureGroupId, version}) { - return fetchFeatureGroup(licenseModelId, featureGroupId, version); - }, + fetchFeatureGroup(dispatch, { licenseModelId, featureGroupId, version }) { + return fetchFeatureGroup(licenseModelId, featureGroupId, version); + }, - fetchFeatureGroupsList(dispatch, {licenseModelId, version}) { - return fetchFeatureGroupsList(licenseModelId, version).then(response => dispatch({ - type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED, - response - })); - }, + fetchFeatureGroupsList(dispatch, { licenseModelId, version }) { + return fetchFeatureGroupsList(licenseModelId, version).then(response => + dispatch({ + type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED, + response + }) + ); + }, - deleteFeatureGroup(dispatch, {licenseModelId, featureGroupId, version}) { - return deleteFeatureGroup(licenseModelId, featureGroupId, version).then(() => { - dispatch({ - type: featureGroupsActionConstants.DELETE_FEATURE_GROUPS, - featureGroupId - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, + deleteFeatureGroup(dispatch, { licenseModelId, featureGroupId, version }) { + return deleteFeatureGroup(licenseModelId, featureGroupId, version).then( + () => { + dispatch({ + type: featureGroupsActionConstants.DELETE_FEATURE_GROUPS, + featureGroupId + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + } + ); + }, - saveFeatureGroup(dispatch, {licenseModelId, previousFeatureGroup, featureGroup, version}) { - if (previousFeatureGroup) { - return updateFeatureGroup(licenseModelId, previousFeatureGroup, featureGroup, version).then(() =>{ - dispatch({ - type: featureGroupsActionConstants.EDIT_FEATURE_GROUPS, - featureGroup - }); - EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}); - LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - else { - return addFeatureGroup(licenseModelId, featureGroup, version).then(response => { - dispatch({ - type: featureGroupsActionConstants.ADD_FEATURE_GROUPS, - featureGroup: { - ...featureGroup, - id: response.value, - referencingLicenseAgreements: [] - } - }); - EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}); - LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - }, + saveFeatureGroup( + dispatch, + { licenseModelId, previousFeatureGroup, featureGroup, version } + ) { + if (previousFeatureGroup) { + return updateFeatureGroup( + licenseModelId, + previousFeatureGroup, + featureGroup, + version + ).then(() => { + dispatch({ + type: featureGroupsActionConstants.EDIT_FEATURE_GROUPS, + featureGroup + }); + EntitlementPoolsActionHelper.fetchEntitlementPoolsList( + dispatch, + { licenseModelId, version } + ); + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList( + dispatch, + { licenseModelId, version } + ); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } else { + return addFeatureGroup(licenseModelId, featureGroup, version).then( + response => { + dispatch({ + type: featureGroupsActionConstants.ADD_FEATURE_GROUPS, + featureGroup: { + ...featureGroup, + id: response.value, + referencingLicenseAgreements: [] + } + }); + EntitlementPoolsActionHelper.fetchEntitlementPoolsList( + dispatch, + { licenseModelId, version } + ); + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList( + dispatch, + { licenseModelId, version } + ); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + } + ); + } + }, - selectEntitlementPoolsEditorTab(dispatch, {tab}) { - dispatch({ - type: featureGroupsActionConstants.featureGroupsEditor.SELECT_TAB, - tab - }); - }, + selectEntitlementPoolsEditorTab(dispatch, { tab }) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.SELECT_TAB, + tab + }); + }, - openFeatureGroupsEditor(dispatch, {featureGroup, licenseModelId, version}) { - return Promise.all([ - EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, {licenseModelId, version}), - LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}) - ]).then(() => { - dispatch({ - type: featureGroupsActionConstants.featureGroupsEditor.OPEN, - featureGroup - }); - }); - }, + openFeatureGroupsEditor( + dispatch, + { featureGroup, licenseModelId, version } + ) { + return Promise.all([ + EntitlementPoolsActionHelper.fetchEntitlementPoolsList(dispatch, { + licenseModelId, + version + }), + LicenseKeyGroupsActionHelper.fetchLicenseKeyGroupsList(dispatch, { + licenseModelId, + version + }) + ]).then(() => { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.OPEN, + featureGroup + }); + }); + }, - closeFeatureGroupsEditor(dispatch) { - dispatch({ - type: featureGroupsActionConstants.featureGroupsEditor.CLOSE - }); - } + closeFeatureGroupsEditor(dispatch) { + dispatch({ + type: featureGroupsActionConstants.featureGroupsEditor.CLOSE + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js index 4c5a94f239..feeb5b6c39 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsConstants.js @@ -16,27 +16,27 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FEATURE_GROUPS_LIST_LOADED: null, - ADD_FEATURE_GROUPS: null, - EDIT_FEATURE_GROUPS: null, - DELETE_FEATURE_GROUPS: null, + FEATURE_GROUPS_LIST_LOADED: null, + ADD_FEATURE_GROUPS: null, + EDIT_FEATURE_GROUPS: null, + DELETE_FEATURE_GROUPS: null, - ENTITLEMENT_POOLS_LIST_LOADED: null, + ENTITLEMENT_POOLS_LIST_LOADED: null, - featureGroupsEditor: { - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, - SELECT_TAB: null - } + featureGroupsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + SELECT_TAB: null + } }); export const FG_EDITOR_FORM = 'FG_EDITOR_FORM'; export const state = keyMirror({ - SELECTED_FEATURE_GROUP_TAB: { - GENERAL: 1, - ENTITLEMENT_POOLS: 2, - LICENSE_KEY_GROUPS: 3 - } + SELECTED_FEATURE_GROUP_TAB: { + GENERAL: 1, + ENTITLEMENT_POOLS: 2, + LICENSE_KEY_GROUPS: 3 + } }); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js index 5688fc0f16..aa1081ed20 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsEditorReducer.js @@ -14,65 +14,82 @@ * permissions and limitations under the License. */ -import {actionTypes, FG_EDITOR_FORM, state as FeatureGroupStateConstants} from './FeatureGroupsConstants.js'; - - +import { + actionTypes, + FG_EDITOR_FORM, + state as FeatureGroupStateConstants +} from './FeatureGroupsConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.featureGroupsEditor.OPEN: - return { - ...state, - data: action.featureGroup || {}, - formReady: null, - formName: FG_EDITOR_FORM, - genericFieldInfo: { - 'description': { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}], - tabId: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL - }, - 'partNumber': { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}], - tabId: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL - }, - 'manufacturerReferenceNumber': { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 100}], - tabId: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL - }, - 'name': { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}], - tabId: FeatureGroupStateConstants.SELECTED_FEATURE_GROUP_TAB.GENERAL - } - } - }; - case actionTypes.featureGroupsEditor.CLOSE: - return {}; - case actionTypes.featureGroupsEditor.SELECT_TAB: - return { - ...state, - selectedTab: action.tab - }; - - case actionTypes.featureGroupsEditor.SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: - return { - ...state, - selectedEntitlementPoolsButtonTab: action.buttonTab - }; - case actionTypes.featureGroupsEditor.SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB: - return { - ...state, - selectedLicenseKeyGroupsButtonTab: action.buttonTab - }; - default: - return state; - } + switch (action.type) { + case actionTypes.featureGroupsEditor.OPEN: + return { + ...state, + data: action.featureGroup || {}, + formReady: null, + formName: FG_EDITOR_FORM, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }], + tabId: + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB.GENERAL + }, + partNumber: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }], + tabId: + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB.GENERAL + }, + manufacturerReferenceNumber: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 100 } + ], + tabId: + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB.GENERAL + }, + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ], + tabId: + FeatureGroupStateConstants + .SELECTED_FEATURE_GROUP_TAB.GENERAL + } + } + }; + case actionTypes.featureGroupsEditor.CLOSE: + return {}; + case actionTypes.featureGroupsEditor.SELECT_TAB: + return { + ...state, + selectedTab: action.tab + }; + case actionTypes.featureGroupsEditor + .SELECTED_ENTITLEMENT_POOLS_BUTTONTAB: + return { + ...state, + selectedEntitlementPoolsButtonTab: action.buttonTab + }; + case actionTypes.featureGroupsEditor + .SELECTED_LICENSE_KEY_GROUPS_BUTTONTAB: + return { + ...state, + selectedLicenseKeyGroupsButtonTab: action.buttonTab + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js index 3b5f1c55e4..072bba403d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsListReducer.js @@ -13,19 +13,27 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './FeatureGroupsConstants.js'; +import { actionTypes } from './FeatureGroupsConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FEATURE_GROUPS_LIST_LOADED: - return [...action.response.results]; - case actionTypes.ADD_FEATURE_GROUPS: - return [...state, action.featureGroup]; - case actionTypes.EDIT_FEATURE_GROUPS: - const indexForEdit = state.findIndex(featureGroup => featureGroup.id === action.featureGroup.id); - return [...state.slice(0, indexForEdit), action.featureGroup, ...state.slice(indexForEdit + 1)]; - case actionTypes.DELETE_FEATURE_GROUPS: - return state.filter(featureGroup => featureGroup.id !== action.featureGroupId); - default: - return state; - } + switch (action.type) { + case actionTypes.FEATURE_GROUPS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.ADD_FEATURE_GROUPS: + return [...state, action.featureGroup]; + case actionTypes.EDIT_FEATURE_GROUPS: + const indexForEdit = state.findIndex( + featureGroup => featureGroup.id === action.featureGroup.id + ); + return [ + ...state.slice(0, indexForEdit), + action.featureGroup, + ...state.slice(indexForEdit + 1) + ]; + case actionTypes.DELETE_FEATURE_GROUPS: + return state.filter( + featureGroup => featureGroup.id !== action.featureGroupId + ); + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js index b1b4ee8fdd..e07777f69e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js @@ -15,109 +15,181 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes as licenseAgreementActionTypes} from './LicenseAgreementConstants.js'; +import { actionTypes as licenseAgreementActionTypes } from './LicenseAgreementConstants.js'; import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; function baseUrl(licenseModelId, version) { - const restPrefix = Configuration.get('restPrefix'); - const {id: versionId} = version; - return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/license-agreements`; + const restPrefix = Configuration.get('restPrefix'); + const { id: versionId } = version; + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/license-agreements`; } function fetchLicenseAgreementList(licenseModelId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); } function fetchLicenseAgreement(licenseModelId, licenseAgreementId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}/${licenseAgreementId}`); + return RestAPIUtil.fetch( + `${baseUrl(licenseModelId, version)}/${licenseAgreementId}` + ); } function postLicenseAgreement(licenseModelId, licenseAgreement, version) { - return RestAPIUtil.post(baseUrl(licenseModelId, version), { - name: licenseAgreement.name, - description: licenseAgreement.description, - licenseTerm: licenseAgreement.licenseTerm, - requirementsAndConstrains: licenseAgreement.requirementsAndConstrains, - addedFeatureGroupsIds: licenseAgreement.featureGroupsIds - }); + return RestAPIUtil.post(baseUrl(licenseModelId, version), { + name: licenseAgreement.name, + description: licenseAgreement.description, + licenseTerm: licenseAgreement.licenseTerm, + requirementsAndConstrains: licenseAgreement.requirementsAndConstrains, + addedFeatureGroupsIds: licenseAgreement.featureGroupsIds + }); } -function putLicenseAgreement(licenseModelId, previousLicenseAgreement, licenseAgreement, version) { - const {featureGroupsIds = []} = licenseAgreement; - const {featureGroupsIds: prevFeatureGroupsIds = []} = previousLicenseAgreement; - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${licenseAgreement.id}`, { - name: licenseAgreement.name, - description: licenseAgreement.description, - licenseTerm: licenseAgreement.licenseTerm, - requirementsAndConstrains: licenseAgreement.requirementsAndConstrains, - addedFeatureGroupsIds: featureGroupsIds.filter(featureGroupId => prevFeatureGroupsIds.indexOf(featureGroupId) === -1), - removedFeatureGroupsIds: prevFeatureGroupsIds.filter(prevFeatureGroupsId => featureGroupsIds.indexOf(prevFeatureGroupsId) === -1) - }); +function putLicenseAgreement( + licenseModelId, + previousLicenseAgreement, + licenseAgreement, + version +) { + const { featureGroupsIds = [] } = licenseAgreement; + const { + featureGroupsIds: prevFeatureGroupsIds = [] + } = previousLicenseAgreement; + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${licenseAgreement.id}`, + { + name: licenseAgreement.name, + description: licenseAgreement.description, + licenseTerm: licenseAgreement.licenseTerm, + requirementsAndConstrains: + licenseAgreement.requirementsAndConstrains, + addedFeatureGroupsIds: featureGroupsIds.filter( + featureGroupId => + prevFeatureGroupsIds.indexOf(featureGroupId) === -1 + ), + removedFeatureGroupsIds: prevFeatureGroupsIds.filter( + prevFeatureGroupsId => + featureGroupsIds.indexOf(prevFeatureGroupsId) === -1 + ) + } + ); } function deleteLicenseAgreement(licenseModelId, licenseAgreementId, version) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${licenseAgreementId}`); + return RestAPIUtil.destroy( + `${baseUrl(licenseModelId, version)}/${licenseAgreementId}` + ); } export default { + fetchLicenseAgreementList(dispatch, { licenseModelId, version }) { + return fetchLicenseAgreementList(licenseModelId, version).then( + response => + dispatch({ + type: + licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED, + response + }) + ); + }, - fetchLicenseAgreementList(dispatch, {licenseModelId, version}) { - return fetchLicenseAgreementList(licenseModelId, version).then(response => dispatch({ - type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED, - response - })); - }, + fetchLicenseAgreement( + dispatch, + { licenseModelId, licenseAgreementId, version } + ) { + return fetchLicenseAgreement( + licenseModelId, + licenseAgreementId, + version + ); + }, - fetchLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId, version}) { - return fetchLicenseAgreement(licenseModelId, licenseAgreementId, version); - }, + openLicenseAgreementEditor( + dispatch, + { licenseModelId, licenseAgreement, version } + ) { + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId, + version + }); + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.OPEN, + licenseAgreement + }); + }, - openLicenseAgreementEditor(dispatch, {licenseModelId, licenseAgreement, version}) { - FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version}); - dispatch({ - type: licenseAgreementActionTypes.licenseAgreementEditor.OPEN, - licenseAgreement - }); - }, + closeLicenseAgreementEditor(dispatch) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.CLOSE + }); + }, - closeLicenseAgreementEditor(dispatch) { - dispatch({ - type: licenseAgreementActionTypes.licenseAgreementEditor.CLOSE - }); - }, + saveLicenseAgreement( + dispatch, + { licenseModelId, previousLicenseAgreement, licenseAgreement, version } + ) { + if (previousLicenseAgreement) { + return putLicenseAgreement( + licenseModelId, + previousLicenseAgreement, + licenseAgreement, + version + ).then(() => { + this.fetchLicenseAgreementList(dispatch, { + licenseModelId, + version + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } else { + return postLicenseAgreement( + licenseModelId, + licenseAgreement, + version + ).then(() => { + this.fetchLicenseAgreementList(dispatch, { + licenseModelId, + version + }); + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId, + version + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } + }, + deleteLicenseAgreement( + dispatch, + { licenseModelId, licenseAgreementId, version } + ) { + return deleteLicenseAgreement( + licenseModelId, + licenseAgreementId, + version + ).then(() => { + dispatch({ + type: licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT, + licenseAgreementId + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + }, - saveLicenseAgreement(dispatch, {licenseModelId, previousLicenseAgreement, licenseAgreement, version}) { - if (previousLicenseAgreement) { - return putLicenseAgreement(licenseModelId, previousLicenseAgreement, licenseAgreement, version).then(() => { - this.fetchLicenseAgreementList(dispatch, {licenseModelId, version}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - else { - return postLicenseAgreement(licenseModelId, licenseAgreement, version).then(() => { - this.fetchLicenseAgreementList(dispatch, {licenseModelId, version}); - FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - }, - - deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId, version}) { - return deleteLicenseAgreement(licenseModelId, licenseAgreementId, version).then(() => { - dispatch({ - type: licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT, - licenseAgreementId - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, - - selectLicenseAgreementEditorTab(dispatch, {tab}) { - dispatch({ - type: licenseAgreementActionTypes.licenseAgreementEditor.SELECT_TAB, - tab - }); - } + selectLicenseAgreementEditorTab(dispatch, { tab }) { + dispatch({ + type: licenseAgreementActionTypes.licenseAgreementEditor.SELECT_TAB, + tab + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js index 181171d4cd..65a45348ca 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementConstants.js @@ -15,49 +15,54 @@ */ import keyMirror from 'nfvo-utils/KeyMirror.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import InputOptions, {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import InputOptions, { + other as optionInputOther +} from 'nfvo-components/input/validation/InputOptions.jsx'; export const actionTypes = keyMirror({ - LICENSE_AGREEMENT_LIST_LOADED: null, - DELETE_LICENSE_AGREEMENT: null, - - licenseAgreementEditor: { - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, - SELECT_TAB: null - } + LICENSE_AGREEMENT_LIST_LOADED: null, + DELETE_LICENSE_AGREEMENT: null, + licenseAgreementEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + SELECT_TAB: null + } }); export const LA_EDITOR_FORM = 'LA_EDITOR_FORM'; export const enums = keyMirror({ - SELECTED_LICENSE_AGREEMENT_TAB: { - GENERAL: 1, - FEATURE_GROUPS: 2 - } + SELECTED_LICENSE_AGREEMENT_TAB: { + GENERAL: 1, + FEATURE_GROUPS: 2 + } }); export const defaultState = { - LICENSE_AGREEMENT_EDITOR_DATA: { - licenseTerm: {choice: '', other: ''} - } + LICENSE_AGREEMENT_EDITOR_DATA: { + licenseTerm: { choice: '', other: '' } + } }; export const optionsInputValues = { - LICENSE_MODEL_TYPE: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Fixed_Term', title: 'Fixed Term'}, - {enum: 'Perpetual', title: 'Perpetual'}, - {enum: 'Unlimited', title: 'Unlimited'} - ] + LICENSE_MODEL_TYPE: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Fixed_Term', title: 'Fixed Term' }, + { enum: 'Perpetual', title: 'Perpetual' }, + { enum: 'Unlimited', title: 'Unlimited' } + ] }; -export const extractValue = (item) => { - if (item === undefined) { - return ''; - } //TODO fix it later +export const extractValue = item => { + if (item === undefined) { + return ''; + } //TODO fix it later - return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; + return item + ? item.choice === optionInputOther.OTHER + ? item.other + : InputOptions.getTitleByName(optionsInputValues, item.choice) + : ''; }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js index 7d70da6ea5..735531a175 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditor.js @@ -13,66 +13,93 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import LicenseAgreementActionHelper from './LicenseAgreementActionHelper.js'; import LicenseAgreementEditorView from './LicenseAgreementEditorView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -export const mapStateToProps = ({licenseModel: {licenseAgreement, featureGroup}}) => { +export const mapStateToProps = ({ + licenseModel: { licenseAgreement, featureGroup } +}) => { + let { + data, + selectedTab, + genericFieldInfo, + formReady + } = licenseAgreement.licenseAgreementEditor; + const list = licenseAgreement.licenseAgreementList; + const LANames = {}; + let previousData; + const licenseAgreementId = data ? data.id : null; + if (licenseAgreementId) { + previousData = licenseAgreement.licenseAgreementList.find( + licenseAgreement => licenseAgreement.id === licenseAgreementId + ); + } - let {data, selectedTab, genericFieldInfo, formReady} = licenseAgreement.licenseAgreementEditor; - const list = licenseAgreement.licenseAgreementList; - const LANames = {}; + for (let i = 0; i < list.length; i++) { + LANames[list[i].name.toLowerCase()] = list[i].id; + } - let previousData; - const licenseAgreementId = data ? data.id : null; - if(licenseAgreementId) { - previousData = licenseAgreement.licenseAgreementList.find(licenseAgreement => licenseAgreement.id === licenseAgreementId); - } + const { featureGroupsList = [] } = featureGroup; - for (let i = 0; i < list.length; i++) { - LANames[list[i].name.toLowerCase()] = list[i].id; - } + let isFormValid = true; + let invalidTabs = []; + for (let field in genericFieldInfo) { + if (!genericFieldInfo[field].isValid) { + isFormValid = false; + let tabId = genericFieldInfo[field].tabId; + if (invalidTabs.indexOf(tabId) === -1) { + invalidTabs[invalidTabs.length] = genericFieldInfo[field].tabId; + } + } + } - const {featureGroupsList = []} = featureGroup; - - let isFormValid = true; - let invalidTabs = []; - for (let field in genericFieldInfo) { - if (!genericFieldInfo[field].isValid) { - isFormValid = false; - let tabId = genericFieldInfo[field].tabId; - if (invalidTabs.indexOf(tabId) === -1) { - invalidTabs[invalidTabs.length] = genericFieldInfo[field].tabId; - } - } - } - - return { - data, - previousData, - selectedTab, - featureGroupsList, - LANames, - genericFieldInfo, - isFormValid, - formReady, - invalidTabs - }; + return { + data, + previousData, + selectedTab, + featureGroupsList, + LANames, + genericFieldInfo, + isFormValid, + formReady, + invalidTabs + }; }; -export const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onTabSelect: tab => LicenseAgreementActionHelper.selectLicenseAgreementEditorTab(dispatch, {tab}), - onCancel: () => LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch), - onSubmit: ({previousLicenseAgreement, licenseAgreement}) => { - LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch); - LicenseAgreementActionHelper.saveLicenseAgreement(dispatch, {licenseModelId, previousLicenseAgreement, licenseAgreement, version}); - }, - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; +export const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onTabSelect: tab => + LicenseAgreementActionHelper.selectLicenseAgreementEditorTab( + dispatch, + { + tab + } + ), + onCancel: () => + LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch), + onSubmit: ({ previousLicenseAgreement, licenseAgreement }) => { + LicenseAgreementActionHelper.closeLicenseAgreementEditor(dispatch); + LicenseAgreementActionHelper.saveLicenseAgreement(dispatch, { + licenseModelId, + previousLicenseAgreement, + licenseAgreement, + version + }); + }, + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseAgreementEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseAgreementEditorView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js index 9cff2792ff..0d3fb2a3b6 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorReducer.js @@ -13,53 +13,76 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, defaultState, LA_EDITOR_FORM, enums as LicenseAgreementEnums} from './LicenseAgreementConstants.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { + actionTypes, + defaultState, + LA_EDITOR_FORM, + enums as LicenseAgreementEnums +} from './LicenseAgreementConstants.js'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.licenseAgreementEditor.OPEN: - return { - ...state, - formReady: null, - formName: LA_EDITOR_FORM, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}], - tabId: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL - }, - 'requirementsAndConstrains' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}], - tabId: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL - }, - 'licenseTerm' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'requiredChoiceWithOther', data: optionInputOther.OTHER}], - tabId: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL - }, - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 25}], - tabId: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL - } - }, - data: action.licenseAgreement ? { ...action.licenseAgreement } : defaultState.LICENSE_AGREEMENT_EDITOR_DATA - }; - case actionTypes.licenseAgreementEditor.CLOSE: - return {}; - case actionTypes.licenseAgreementEditor.SELECT_TAB: - return { - ...state, - selectedTab: action.tab - }; - default: - return state; - } - + switch (action.type) { + case actionTypes.licenseAgreementEditor.OPEN: + return { + ...state, + formReady: null, + formName: LA_EDITOR_FORM, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }], + tabId: + LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB + .GENERAL + }, + requirementsAndConstrains: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }], + tabId: + LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB + .GENERAL + }, + licenseTerm: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { + type: 'requiredChoiceWithOther', + data: optionInputOther.OTHER + } + ], + tabId: + LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB + .GENERAL + }, + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 25 } + ], + tabId: + LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB + .GENERAL + } + }, + data: action.licenseAgreement + ? { ...action.licenseAgreement } + : defaultState.LICENSE_AGREEMENT_EDITOR_DATA + }; + case actionTypes.licenseAgreementEditor.CLOSE: + return {}; + case actionTypes.licenseAgreementEditor.SELECT_TAB: + return { + ...state, + selectedTab: action.tab + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx index a3e73f4f14..cc16dd996d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementEditorView.jsx @@ -17,7 +17,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -import {TabsForm as Form} from 'nfvo-components/input/validation/Form.jsx'; +import { TabsForm as Form } from 'nfvo-components/input/validation/Form.jsx'; import Tabs from 'nfvo-components/input/validation/Tabs.jsx'; import Tab from 'sdc-ui/lib/react/Tab.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; @@ -25,176 +25,278 @@ import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; import DualListboxView from 'nfvo-components/input/dualListbox/DualListboxView.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Validator from 'nfvo-utils/Validator.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; -import {enums as LicenseAgreementEnums, optionsInputValues as LicenseAgreementOptionsInputValues, LA_EDITOR_FORM} from './LicenseAgreementConstants.js'; +import { + enums as LicenseAgreementEnums, + optionsInputValues as LicenseAgreementOptionsInputValues, + LA_EDITOR_FORM +} from './LicenseAgreementConstants.js'; const dualBoxFilterTitle = { - left: i18n('Available Feature Groups'), - right: i18n('Selected Feature Groups') + left: i18n('Available Feature Groups'), + right: i18n('Selected Feature Groups') }; const LicenseAgreementPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - requirementsAndConstrains: PropTypes.string, - licenseTerm: PropTypes.object, - featureGroupsIds: PropTypes.arrayOf(PropTypes.string), - version: PropTypes.object + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + requirementsAndConstrains: PropTypes.string, + licenseTerm: PropTypes.object, + featureGroupsIds: PropTypes.arrayOf(PropTypes.string), + version: PropTypes.object }); - -const GeneralTabContent = ({data, genericFieldInfo, onDataChanged, validateName}) => { - let {name, description, requirementsAndConstrains, licenseTerm} = data; - return ( - <GridSection hasLastColSet> - <GridItem colSpan={2}> - <Input - isValid={genericFieldInfo.name.isValid} - errorText={genericFieldInfo.name.errorText} - onChange={name => onDataChanged({name}, LA_EDITOR_FORM, { name: validateName })} - label={i18n('Name')} - value={name} - data-test-id='create-la-name' - name='license-agreement-name' - isRequired={true} - type='text'/> - <Input - isValid={genericFieldInfo.requirementsAndConstrains.isValid} - errorText={genericFieldInfo.requirementsAndConstrains.errorText} - onChange={requirementsAndConstrains => onDataChanged({requirementsAndConstrains}, LA_EDITOR_FORM)} - label={i18n('Requirements and Constraints')} - value={requirementsAndConstrains} - data-test-id='create-la-requirements-constants' - name='license-agreement-requirements-and-constraints' - type='textarea'/> - <InputOptions - onInputChange={()=>{}} - isMultiSelect={false} - onEnumChange={licenseTerm => onDataChanged({licenseTerm:{choice: licenseTerm, other: ''}}, - LA_EDITOR_FORM)} - onOtherChange={licenseTerm => onDataChanged({licenseTerm:{choice: optionInputOther.OTHER, - other: licenseTerm}}, LA_EDITOR_FORM)} - label={i18n('License Term')} - data-test-id='create-la-license-term' - isRequired={true} - type='select' - selectedEnum={licenseTerm && licenseTerm.choice} - otherValue={licenseTerm && licenseTerm.other} - values={LicenseAgreementOptionsInputValues.LICENSE_MODEL_TYPE} - isValid={genericFieldInfo.licenseTerm.isValid} - errorText={genericFieldInfo.licenseTerm.errorText} /> - </GridItem> - <GridItem colSpan={2} stretch lastColInRow> - <Input - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - onChange={description => onDataChanged({description}, LA_EDITOR_FORM)} - label={i18n('Description')} - value={description} - overlayPos='bottom' - data-test-id='create-la-description' - name='license-agreement-description' - type='textarea'/> - </GridItem> - </GridSection> - ); +const GeneralTabContent = ({ + data, + genericFieldInfo, + onDataChanged, + validateName +}) => { + let { name, description, requirementsAndConstrains, licenseTerm } = data; + return ( + <GridSection hasLastColSet> + <GridItem colSpan={2}> + <Input + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + onChange={name => + onDataChanged({ name }, LA_EDITOR_FORM, { + name: validateName + }) + } + label={i18n('Name')} + value={name} + data-test-id="create-la-name" + name="license-agreement-name" + isRequired={true} + type="text" + /> + <Input + isValid={genericFieldInfo.requirementsAndConstrains.isValid} + errorText={ + genericFieldInfo.requirementsAndConstrains.errorText + } + onChange={requirementsAndConstrains => + onDataChanged( + { requirementsAndConstrains }, + LA_EDITOR_FORM + ) + } + label={i18n('Requirements and Constraints')} + value={requirementsAndConstrains} + data-test-id="create-la-requirements-constants" + name="license-agreement-requirements-and-constraints" + type="textarea" + /> + <InputOptions + onInputChange={() => {}} + isMultiSelect={false} + onEnumChange={licenseTerm => + onDataChanged( + { licenseTerm: { choice: licenseTerm, other: '' } }, + LA_EDITOR_FORM + ) + } + onOtherChange={licenseTerm => + onDataChanged( + { + licenseTerm: { + choice: optionInputOther.OTHER, + other: licenseTerm + } + }, + LA_EDITOR_FORM + ) + } + label={i18n('License Term')} + data-test-id="create-la-license-term" + isRequired={true} + type="select" + selectedEnum={licenseTerm && licenseTerm.choice} + otherValue={licenseTerm && licenseTerm.other} + values={ + LicenseAgreementOptionsInputValues.LICENSE_MODEL_TYPE + } + isValid={genericFieldInfo.licenseTerm.isValid} + errorText={genericFieldInfo.licenseTerm.errorText} + /> + </GridItem> + <GridItem colSpan={2} stretch lastColInRow> + <Input + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + onChange={description => + onDataChanged({ description }, LA_EDITOR_FORM) + } + label={i18n('Description')} + value={description} + overlayPos="bottom" + data-test-id="create-la-description" + name="license-agreement-description" + type="textarea" + /> + </GridItem> + </GridSection> + ); }; class LicenseAgreementEditorView extends React.Component { + static propTypes = { + data: LicenseAgreementPropType, + previousData: LicenseAgreementPropType, + LANames: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, - static propTypes = { - data: LicenseAgreementPropType, - previousData: LicenseAgreementPropType, - LANames: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired, - - selectedTab: PropTypes.number, - onTabSelect: PropTypes.func, + selectedTab: PropTypes.number, + onTabSelect: PropTypes.func, - selectedFeatureGroupsButtonTab: PropTypes.number, - onFeatureGroupsButtonTabSelect: PropTypes.func, - featureGroupsList: DualListboxView.propTypes.availableList - }; + selectedFeatureGroupsButtonTab: PropTypes.number, + onFeatureGroupsButtonTabSelect: PropTypes.func, + featureGroupsList: DualListboxView.propTypes.availableList + }; - static defaultProps = { - selectedTab: LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL, - data: {} - }; + static defaultProps = { + selectedTab: + LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL, + data: {} + }; - state = { - localFeatureGroupsListFilter: '' - }; + state = { + localFeatureGroupsListFilter: '' + }; - render() { - let {selectedTab, onTabSelect, isReadOnlyMode, featureGroupsList, data, onDataChanged, genericFieldInfo} = this.props; - return ( - <div> - {genericFieldInfo && <Form - ref='validationForm' - hasButtons={true} - onSubmit={ () => this.submit() } - onReset={ () => this.props.onCancel() } - labledButtons={true} - isReadOnlyMode={isReadOnlyMode} - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.props.onValidateForm(LA_EDITOR_FORM) } - className='license-model-form license-agreement-form'> - <Tabs activeTab={onTabSelect ? selectedTab : undefined} onTabClick={onTabSelect} invalidTabs={this.props.invalidTabs} > - <Tab - tabId={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.GENERAL} - data-test-id='general-tab' - title={i18n('General')}> - <fieldset disabled={isReadOnlyMode}> - <GeneralTabContent data={data} genericFieldInfo={genericFieldInfo} onDataChanged={onDataChanged} validateLTChoice={(value)=>this.validateLTChoice(value)} - validateName={(value)=>this.validateName(value)}/> - </fieldset> - </Tab> - <Tab - tabId={LicenseAgreementEnums.SELECTED_LICENSE_AGREEMENT_TAB.FEATURE_GROUPS} - data-test-id='feature-group-tab' - title={i18n('Feature Groups')}> - <fieldset disabled={isReadOnlyMode}> - {featureGroupsList.length > 0 ? - <DualListboxView - isReadOnlyMode={isReadOnlyMode} - filterTitle={dualBoxFilterTitle} - selectedValuesList={data.featureGroupsIds} - availableList={featureGroupsList} - onChange={ selectedValuesList => onDataChanged( { featureGroupsIds: selectedValuesList }, LA_EDITOR_FORM )}/> : - <p>{i18n('There are no available feature groups')}</p>} - </fieldset> - </Tab> - </Tabs> - </Form>} - </div> - ); - } + render() { + let { + selectedTab, + onTabSelect, + isReadOnlyMode, + featureGroupsList, + data, + onDataChanged, + genericFieldInfo + } = this.props; + return ( + <div> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={true} + onSubmit={() => this.submit()} + onReset={() => this.props.onCancel()} + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => + this.props.onValidateForm(LA_EDITOR_FORM) + } + className="license-model-form license-agreement-form"> + <Tabs + activeTab={onTabSelect ? selectedTab : undefined} + onTabClick={onTabSelect} + invalidTabs={this.props.invalidTabs}> + <Tab + tabId={ + LicenseAgreementEnums + .SELECTED_LICENSE_AGREEMENT_TAB.GENERAL + } + data-test-id="general-tab" + title={i18n('General')}> + <fieldset disabled={isReadOnlyMode}> + <GeneralTabContent + data={data} + genericFieldInfo={genericFieldInfo} + onDataChanged={onDataChanged} + validateLTChoice={value => + this.validateLTChoice(value) + } + validateName={value => + this.validateName(value) + } + /> + </fieldset> + </Tab> + <Tab + tabId={ + LicenseAgreementEnums + .SELECTED_LICENSE_AGREEMENT_TAB + .FEATURE_GROUPS + } + data-test-id="feature-group-tab" + title={i18n('Feature Groups')}> + <fieldset disabled={isReadOnlyMode}> + {featureGroupsList.length > 0 ? ( + <DualListboxView + isReadOnlyMode={isReadOnlyMode} + filterTitle={dualBoxFilterTitle} + selectedValuesList={ + data.featureGroupsIds + } + availableList={featureGroupsList} + onChange={selectedValuesList => + onDataChanged( + { + featureGroupsIds: selectedValuesList + }, + LA_EDITOR_FORM + ) + } + /> + ) : ( + <p> + {i18n( + 'There are no available feature groups' + )} + </p> + )} + </fieldset> + </Tab> + </Tabs> + </Form> + )} + </div> + ); + } - submit() { - const {data: licenseAgreement, previousData: previousLicenseAgreement} = this.props; - this.props.onSubmit({licenseAgreement, previousLicenseAgreement}); - } + submit() { + const { + data: licenseAgreement, + previousData: previousLicenseAgreement + } = this.props; + this.props.onSubmit({ licenseAgreement, previousLicenseAgreement }); + } - validateLTChoice(value) { - if (!value.choice) { - return {isValid: false, errorText: i18n('Field is required')}; - } - return {isValid: true, errorText: ''}; - } + validateLTChoice(value) { + if (!value.choice) { + return { isValid: false, errorText: i18n('Field is required') }; + } + return { isValid: true, errorText: '' }; + } - validateName(value) { - const {data: {id}, LANames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: LANames}); + validateName(value) { + const { data: { id }, LANames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: LANames + }); - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('License Agreement by the name \'' + value + '\' already exists. License agreement name must be unique')}; - } + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "License Agreement by the name '" + + value + + "' already exists. License agreement name must be unique" + ) + }; + } } export default LicenseAgreementEditorView; 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 72474ecdd3..cba39731b5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditor.js @@ -13,42 +13,64 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import LicenseAgreementActionHelper from './LicenseAgreementActionHelper.js'; import LicenseAgreementListEditorView from './LicenseAgreementListEditorView.jsx'; -import {actionTypes as globalMoadlActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as globalMoadlActions } from 'nfvo-components/modal/GlobalModalConstants.js'; -const mapStateToProps = ({licenseModel: {licenseAgreement, licenseModelEditor}}) => { - - let {licenseAgreementList} = licenseAgreement; - let {data} = licenseAgreement.licenseAgreementEditor; - let {vendorName, version} = licenseModelEditor.data; - - return { - vendorName, - version, - licenseAgreementList, - isDisplayModal: Boolean(data), - isModalInEditMode: Boolean(data && data.id) - }; +const mapStateToProps = ({ + licenseModel: { licenseAgreement, licenseModelEditor } +}) => { + let { licenseAgreementList } = licenseAgreement; + let { data } = licenseAgreement.licenseAgreementEditor; + let { vendorName, version } = licenseModelEditor.data; + return { + vendorName, + version, + licenseAgreementList, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; }; -const mapActionsToProps = (dispatch, {licenseModelId}) => { - return { - onAddLicenseAgreementClick: (version) => LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, {licenseModelId, version}), - onEditLicenseAgreementClick: (licenseAgreement, version) => LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, {licenseModelId, licenseAgreement, version}), - onDeleteLicenseAgreement: (licenseAgreement, version) => dispatch({ - type: globalMoadlActions.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: licenseAgreement.name}), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=>LicenseAgreementActionHelper.deleteLicenseAgreement(dispatch, {licenseModelId, licenseAgreementId: licenseAgreement.id, version}) - } - }) - }; +const mapActionsToProps = (dispatch, { licenseModelId }) => { + return { + onAddLicenseAgreementClick: version => + LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, { + licenseModelId, + version + }), + onEditLicenseAgreementClick: (licenseAgreement, version) => + LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, { + licenseModelId, + licenseAgreement, + version + }), + onDeleteLicenseAgreement: (licenseAgreement, version) => + dispatch({ + type: globalMoadlActions.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete "{name}"?', { + name: licenseAgreement.name + }), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + LicenseAgreementActionHelper.deleteLicenseAgreement( + dispatch, + { + licenseModelId, + licenseAgreementId: licenseAgreement.id, + version + } + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseAgreementListEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseAgreementListEditorView +); 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 ad3cdb0b58..acec1e0ddb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListEditorView.jsx @@ -21,107 +21,151 @@ import Modal from 'nfvo-components/modal/Modal.jsx'; import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; import LicenseAgreementEditor from './LicenseAgreementEditor.js'; -import {extractValue} from './LicenseAgreementConstants'; +import { extractValue } from './LicenseAgreementConstants'; class LicenseAgreementListEditorView extends React.Component { - static propTypes = { - vendorName: PropTypes.string, - licenseModelId: PropTypes.string.isRequired, - licenseAgreementList: PropTypes.array, - isReadOnlyMode: PropTypes.bool.isRequired, - isDisplayModal: PropTypes.bool, - isModalInEditMode: PropTypes.bool, - onAddLicenseAgreementClick: PropTypes.func, - onEditLicenseAgreementClick: PropTypes.func, - onDeleteLicenseAgreement: PropTypes.func, - }; + static propTypes = { + vendorName: PropTypes.string, + licenseModelId: PropTypes.string.isRequired, + licenseAgreementList: PropTypes.array, + isReadOnlyMode: PropTypes.bool.isRequired, + isDisplayModal: PropTypes.bool, + isModalInEditMode: PropTypes.bool, + onAddLicenseAgreementClick: PropTypes.func, + onEditLicenseAgreementClick: PropTypes.func, + onDeleteLicenseAgreement: PropTypes.func + }; - static defaultProps = { - licenseAgreementList: [] - }; + static defaultProps = { + licenseAgreementList: [] + }; - state = { - localFilter: '' - }; + state = { + localFilter: '' + }; - render() { - const {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; - const {onAddLicenseAgreementClick} = this.props; - const {localFilter} = this.state; + render() { + const { + licenseModelId, + isReadOnlyMode, + isDisplayModal, + isModalInEditMode, + version + } = this.props; + const { onAddLicenseAgreementClick } = this.props; + const { localFilter } = this.state; - return ( - <div className='license-model-list-editor license-agreement-list-editor'> - <ListEditorView - title={i18n('License Agreements')} - plusButtonTitle={i18n('Add License Agreement')} - onAdd={() => onAddLicenseAgreementClick(version)} - filterValue={localFilter} - onFilter={value => this.setState({localFilter: value})} - isReadOnlyMode={isReadOnlyMode}> - {this.filterList().map(licenseAgreement => this.renderLicenseAgreementListItem(licenseAgreement, isReadOnlyMode, version))} - </ListEditorView> - <Modal show={isDisplayModal} bsSize='large' animation={true} className='onborading-modal license-model-modal license-agreement-modal'> - <Modal.Header> - <Modal.Title>{`${isModalInEditMode ? i18n('Edit License Agreement') : i18n('Create New License Agreement')}`}</Modal.Title> - </Modal.Header> - <Modal.Body> - { - isDisplayModal && ( - <LicenseAgreementEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode} /> - ) - } - </Modal.Body> - </Modal> - </div> - ); - } + return ( + <div className="license-model-list-editor license-agreement-list-editor"> + <ListEditorView + title={i18n('License Agreements')} + plusButtonTitle={i18n('Add License Agreement')} + onAdd={() => onAddLicenseAgreementClick(version)} + filterValue={localFilter} + onFilter={value => this.setState({ localFilter: value })} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(licenseAgreement => + this.renderLicenseAgreementListItem( + licenseAgreement, + isReadOnlyMode, + version + ) + )} + </ListEditorView> + <Modal + show={isDisplayModal} + bsSize="large" + animation={true} + className="onborading-modal license-model-modal license-agreement-modal"> + <Modal.Header> + <Modal.Title>{`${ + isModalInEditMode + ? i18n('Edit License Agreement') + : i18n('Create New License Agreement') + }`}</Modal.Title> + </Modal.Header> + <Modal.Body> + {isDisplayModal && ( + <LicenseAgreementEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </Modal.Body> + </Modal> + </div> + ); + } - filterList() { - let {licenseAgreementList} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return licenseAgreementList.filter(({name = '', description = '', licenseTerm = ''}) => { - return escape(name).match(filter) || escape(description).match(filter) || escape(extractValue(licenseTerm)).match(filter); - }); - } - else { - return licenseAgreementList; - } - } + filterList() { + let { licenseAgreementList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return licenseAgreementList.filter( + ({ name = '', description = '', licenseTerm = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) || + escape(extractValue(licenseTerm)).match(filter) + ); + } + ); + } else { + return licenseAgreementList; + } + } - renderLicenseAgreementListItem(licenseAgreement, isReadOnlyMode, version) { - let {id, name, description, licenseTerm, featureGroupsIds = []} = licenseAgreement; - let {onEditLicenseAgreementClick, onDeleteLicenseAgreement} = this.props; - return ( - <ListEditorItemView - key={id} - onSelect={() => onEditLicenseAgreementClick(licenseAgreement, version)} - onDelete={() => onDeleteLicenseAgreement(licenseAgreement, version)} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode}> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Name')}</div> - <div className='text name'>{name}</div> - </div> - <div className='list-editor-item-view-field'> - <div className='list-editor-item-view-field-tight'> - <div className='title'>{i18n('Type')}</div> - <div className='text type'>{extractValue(licenseTerm)}</div> - </div> - <div className='list-editor-item-view-field-tight'> - <div className='title'>{i18n('Feature')}</div> - <div className='title'>{i18n('Groups')}</div> - <div className='feature-groups-count'>{featureGroupsIds.length}</div> - </div> - </div> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Description')}</div> - <div className='text description'>{description}</div> - </div> - </ListEditorItemView> - ); - } + renderLicenseAgreementListItem(licenseAgreement, isReadOnlyMode, version) { + let { + id, + name, + description, + licenseTerm, + featureGroupsIds = [] + } = licenseAgreement; + let { + onEditLicenseAgreementClick, + onDeleteLicenseAgreement + } = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => + onEditLicenseAgreementClick(licenseAgreement, version) + } + onDelete={() => + onDeleteLicenseAgreement(licenseAgreement, version) + } + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div className="text name">{name}</div> + </div> + <div className="list-editor-item-view-field"> + <div className="list-editor-item-view-field-tight"> + <div className="title">{i18n('Type')}</div> + <div className="text type"> + {extractValue(licenseTerm)} + </div> + </div> + <div className="list-editor-item-view-field-tight"> + <div className="title">{i18n('Feature')}</div> + <div className="title">{i18n('Groups')}</div> + <div className="feature-groups-count"> + {featureGroupsIds.length} + </div> + </div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Description')}</div> + <div className="text description">{description}</div> + </div> + </ListEditorItemView> + ); + } } export default LicenseAgreementListEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js index 7d1a5ef8ee..213a63d565 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementListReducer.js @@ -13,15 +13,18 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes as licenseAgreementActionTypes} from './LicenseAgreementConstants'; +import { actionTypes as licenseAgreementActionTypes } from './LicenseAgreementConstants'; export default (state = [], action) => { - switch (action.type) { - case licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED: - return [...action.response.results]; - case licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT: - return state.filter(licenseAgreement => licenseAgreement.id !== action.licenseAgreementId); - default: - return state; - } + switch (action.type) { + case licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED: + return [...action.response.results]; + case licenseAgreementActionTypes.DELETE_LICENSE_AGREEMENT: + return state.filter( + licenseAgreement => + licenseAgreement.id !== action.licenseAgreementId + ); + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js index 674c329515..ebbe84abd3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsActionHelper.js @@ -15,191 +15,268 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes as licenseKeyGroupsConstants} from './LicenseKeyGroupsConstants.js'; -import {actionTypes as limitEditorActions} from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; -import {default as getValue, getStrValue} from 'nfvo-utils/getValue.js'; +import { actionTypes as licenseKeyGroupsConstants } from './LicenseKeyGroupsConstants.js'; +import { actionTypes as limitEditorActions } from 'sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js'; +import { default as getValue, getStrValue } from 'nfvo-utils/getValue.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; function baseUrl(licenseModelId, version) { - const restPrefix = Configuration.get('restPrefix'); - const {id: versionId} = version; - return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/license-key-groups`; + const restPrefix = Configuration.get('restPrefix'); + const { id: versionId } = version; + return `${restPrefix}/v1.0/vendor-license-models/${licenseModelId}/versions/${versionId}/license-key-groups`; } function fetchLicenseKeyGroupsList(licenseModelId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}`); } function deleteLicenseKeyGroup(licenseModelId, licenseKeyGroupId, version) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}`); + return RestAPIUtil.destroy( + `${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}` + ); } function postLicenseKeyGroup(licenseModelId, licenseKeyGroup, version) { - return RestAPIUtil.post(baseUrl(licenseModelId, version), { - name: licenseKeyGroup.name, - description: licenseKeyGroup.description, - operationalScope: getValue(licenseKeyGroup.operationalScope), - type: licenseKeyGroup.type, - increments: licenseKeyGroup.increments, - thresholdValue: licenseKeyGroup.thresholdValue, - thresholdUnits: getValue(licenseKeyGroup.thresholdUnits), - startDate: licenseKeyGroup.startDate, - expiryDate: licenseKeyGroup.expiryDate - }); + return RestAPIUtil.post(baseUrl(licenseModelId, version), { + name: licenseKeyGroup.name, + description: licenseKeyGroup.description, + operationalScope: getValue(licenseKeyGroup.operationalScope), + type: licenseKeyGroup.type, + increments: licenseKeyGroup.increments, + thresholdValue: licenseKeyGroup.thresholdValue, + thresholdUnits: getValue(licenseKeyGroup.thresholdUnits), + startDate: licenseKeyGroup.startDate, + expiryDate: licenseKeyGroup.expiryDate + }); } function putLicenseKeyGroup(licenseModelId, licenseKeyGroup, version) { - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${licenseKeyGroup.id}`, { - name: licenseKeyGroup.name, - description: licenseKeyGroup.description, - operationalScope: getValue(licenseKeyGroup.operationalScope), - type: licenseKeyGroup.type, - increments: licenseKeyGroup.increments, - thresholdValue: licenseKeyGroup.thresholdValue, - thresholdUnits: getValue(licenseKeyGroup.thresholdUnits), - startDate: licenseKeyGroup.startDate, - expiryDate: licenseKeyGroup.expiryDate - }); + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${licenseKeyGroup.id}`, + { + name: licenseKeyGroup.name, + description: licenseKeyGroup.description, + operationalScope: getValue(licenseKeyGroup.operationalScope), + type: licenseKeyGroup.type, + increments: licenseKeyGroup.increments, + thresholdValue: licenseKeyGroup.thresholdValue, + thresholdUnits: getValue(licenseKeyGroup.thresholdUnits), + startDate: licenseKeyGroup.startDate, + expiryDate: licenseKeyGroup.expiryDate + } + ); } function fetchLimitsList(licenseModelId, licenseKeyGroupId, version) { - return RestAPIUtil.fetch(`${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits`); + return RestAPIUtil.fetch( + `${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits` + ); } function deleteLimit(licenseModelId, licenseKeyGroupId, version, limitId) { - return RestAPIUtil.destroy(`${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits/${limitId}`); + return RestAPIUtil.destroy( + `${baseUrl( + licenseModelId, + version + )}/${licenseKeyGroupId}/limits/${limitId}` + ); } function postLimit(licenseModelId, licenseKeyGroupId, version, limit) { - return RestAPIUtil.post(`${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits`, { - name: limit.name, - type: limit.type, - description: limit.description, - metric: getStrValue(limit.metric), - value: limit.value, - unit: getStrValue(limit.unit), - aggregationFunction: getValue(limit.aggregationFunction), - time: getValue(limit.time) - }); + return RestAPIUtil.post( + `${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits`, + { + name: limit.name, + type: limit.type, + description: limit.description, + metric: getStrValue(limit.metric), + value: limit.value, + unit: getStrValue(limit.unit), + aggregationFunction: getValue(limit.aggregationFunction), + time: getValue(limit.time) + } + ); } function putLimit(licenseModelId, licenseKeyGroupId, version, limit) { - - return RestAPIUtil.put(`${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits/${limit.id}`, { - name: limit.name, - type: limit.type, - description: limit.description, - metric: getStrValue(limit.metric), - value: limit.value, - unit: getStrValue(limit.unit), - aggregationFunction: getValue(limit.aggregationFunction), - time: getValue(limit.time) - }); + return RestAPIUtil.put( + `${baseUrl(licenseModelId, version)}/${licenseKeyGroupId}/limits/${ + limit.id + }`, + { + name: limit.name, + type: limit.type, + description: limit.description, + metric: getStrValue(limit.metric), + value: limit.value, + unit: getStrValue(limit.unit), + aggregationFunction: getValue(limit.aggregationFunction), + time: getValue(limit.time) + } + ); } export default { - fetchLicenseKeyGroupsList(dispatch, {licenseModelId, version}) { - return fetchLicenseKeyGroupsList(licenseModelId, version).then(response => dispatch({ - type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_LIST_LOADED, - response - })); - }, - - openLicenseKeyGroupsEditor(dispatch, {licenseKeyGroup, licenseModelId, version} = {}) { - if (licenseModelId && version) { - this.fetchLimits(dispatch, {licenseModelId, version, licenseKeyGroup}); - } - dispatch({ - type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.OPEN, - licenseKeyGroup - }); - }, - - closeLicenseKeyGroupEditor(dispatch){ - dispatch({ - type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.CLOSE - }); - }, - - saveLicenseKeyGroup(dispatch, {licenseModelId, previousLicenseKeyGroup, licenseKeyGroup, version}) { - if (previousLicenseKeyGroup) { - return putLicenseKeyGroup(licenseModelId, licenseKeyGroup, version).then(() => { - dispatch({ - type: licenseKeyGroupsConstants.EDIT_LICENSE_KEY_GROUP, - licenseKeyGroup - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - else { - return postLicenseKeyGroup(licenseModelId, licenseKeyGroup, version).then(response => { - dispatch({ - type: licenseKeyGroupsConstants.ADD_LICENSE_KEY_GROUP, - licenseKeyGroup: { - ...licenseKeyGroup, - referencingFeatureGroups: [], - id: response.value - } - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } - - - }, - - deleteLicenseKeyGroup(dispatch, {licenseModelId, licenseKeyGroupId, version}){ - return deleteLicenseKeyGroup(licenseModelId, licenseKeyGroupId, version).then(()=> { - dispatch({ - type: licenseKeyGroupsConstants.DELETE_LICENSE_KEY_GROUP, - licenseKeyGroupId - }); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, - - hideDeleteConfirm(dispatch) { - dispatch({ - type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, - licenseKeyGroupToDelete: false - }); - }, - - openDeleteLicenseAgreementConfirm(dispatch, {licenseKeyGroup}) { - dispatch({ - type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, - licenseKeyGroupToDelete: licenseKeyGroup - }); - }, - - - fetchLimits(dispatch, {licenseModelId, version, licenseKeyGroup}) { - return fetchLimitsList(licenseModelId, licenseKeyGroup.id, version).then(response => { - dispatch({ - type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.LIMITS_LIST_LOADED, - response - }); - }); - }, - - submitLimit(dispatch, {licenseModelId, version, licenseKeyGroup, limit}) { - const promise = limit.id ? putLimit(licenseModelId,licenseKeyGroup.id, version, limit) : - postLimit(licenseModelId,licenseKeyGroup.id, version, limit); - return promise.then(() => { - dispatch({ - type: limitEditorActions.CLOSE - }); - this.fetchLimits(dispatch, {licenseModelId, version, licenseKeyGroup}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - }, - - deleteLimit(dispatch, {licenseModelId, version, licenseKeyGroup, limit}) { - return deleteLimit(licenseModelId,licenseKeyGroup.id, version, limit.id).then(() => { - this.fetchLimits(dispatch, {licenseModelId, version, licenseKeyGroup}); - return ItemsHelper.checkItemStatus(dispatch, {itemId: licenseModelId, versionId: version.id}); - }); - } + fetchLicenseKeyGroupsList(dispatch, { licenseModelId, version }) { + return fetchLicenseKeyGroupsList(licenseModelId, version).then( + response => + dispatch({ + type: + licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_LIST_LOADED, + response + }) + ); + }, + + openLicenseKeyGroupsEditor( + dispatch, + { licenseKeyGroup, licenseModelId, version } = {} + ) { + if (licenseModelId && version) { + this.fetchLimits(dispatch, { + licenseModelId, + version, + licenseKeyGroup + }); + } + dispatch({ + type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.OPEN, + licenseKeyGroup + }); + }, + + closeLicenseKeyGroupEditor(dispatch) { + dispatch({ + type: licenseKeyGroupsConstants.licenseKeyGroupsEditor.CLOSE + }); + }, + + saveLicenseKeyGroup( + dispatch, + { licenseModelId, previousLicenseKeyGroup, licenseKeyGroup, version } + ) { + if (previousLicenseKeyGroup) { + return putLicenseKeyGroup( + licenseModelId, + licenseKeyGroup, + version + ).then(() => { + dispatch({ + type: licenseKeyGroupsConstants.EDIT_LICENSE_KEY_GROUP, + licenseKeyGroup + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } else { + return postLicenseKeyGroup( + licenseModelId, + licenseKeyGroup, + version + ).then(response => { + dispatch({ + type: licenseKeyGroupsConstants.ADD_LICENSE_KEY_GROUP, + licenseKeyGroup: { + ...licenseKeyGroup, + referencingFeatureGroups: [], + id: response.value + } + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } + }, + + deleteLicenseKeyGroup( + dispatch, + { licenseModelId, licenseKeyGroupId, version } + ) { + return deleteLicenseKeyGroup( + licenseModelId, + licenseKeyGroupId, + version + ).then(() => { + dispatch({ + type: licenseKeyGroupsConstants.DELETE_LICENSE_KEY_GROUP, + licenseKeyGroupId + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, + licenseKeyGroupToDelete: false + }); + }, + + openDeleteLicenseAgreementConfirm(dispatch, { licenseKeyGroup }) { + dispatch({ + type: licenseKeyGroupsConstants.LICENSE_KEY_GROUPS_DELETE_CONFIRM, + licenseKeyGroupToDelete: licenseKeyGroup + }); + }, + + fetchLimits(dispatch, { licenseModelId, version, licenseKeyGroup }) { + return fetchLimitsList( + licenseModelId, + licenseKeyGroup.id, + version + ).then(response => { + dispatch({ + type: + licenseKeyGroupsConstants.licenseKeyGroupsEditor + .LIMITS_LIST_LOADED, + response + }); + }); + }, + submitLimit(dispatch, { licenseModelId, version, licenseKeyGroup, limit }) { + const promise = limit.id + ? putLimit(licenseModelId, licenseKeyGroup.id, version, limit) + : postLimit(licenseModelId, licenseKeyGroup.id, version, limit); + return promise.then(() => { + dispatch({ + type: limitEditorActions.CLOSE + }); + this.fetchLimits(dispatch, { + licenseModelId, + version, + licenseKeyGroup + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + }, + deleteLimit(dispatch, { licenseModelId, version, licenseKeyGroup, limit }) { + return deleteLimit( + licenseModelId, + licenseKeyGroup.id, + version, + limit.id + ).then(() => { + this.fetchLimits(dispatch, { + licenseModelId, + version, + licenseKeyGroup + }); + return ItemsHelper.checkItemStatus(dispatch, { + itemId: licenseModelId, + versionId: version.id + }); + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js index c376cb3fbc..aad0a0b1fb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsConstants.js @@ -15,73 +15,88 @@ */ import keyMirror from 'nfvo-utils/KeyMirror.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import InputOptions, {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import InputOptions, { + other as optionInputOther +} from 'nfvo-components/input/validation/InputOptions.jsx'; export const actionTypes = keyMirror({ - - LICENSE_KEY_GROUPS_LIST_LOADED: null, - DELETE_LICENSE_KEY_GROUP: null, - EDIT_LICENSE_KEY_GROUP: null, - ADD_LICENSE_KEY_GROUP: null, - LICENSE_KEY_GROUPS_DELETE_CONFIRM: null, - licenseKeyGroupsEditor: { - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, - LIMITS_LIST_LOADED: null - } + LICENSE_KEY_GROUPS_LIST_LOADED: null, + DELETE_LICENSE_KEY_GROUP: null, + EDIT_LICENSE_KEY_GROUP: null, + ADD_LICENSE_KEY_GROUP: null, + LICENSE_KEY_GROUPS_DELETE_CONFIRM: null, + licenseKeyGroupsEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + LIMITS_LIST_LOADED: null + } }); export const defaultState = { - licenseKeyGroupsEditor: { - type: '', - operationalScope: {choices: [], other: ''} - } + licenseKeyGroupsEditor: { + type: '', + operationalScope: { choices: [], other: '' } + } }; export const LKG_FORM_NAME = 'LKGFORM'; export const optionsInputValues = { - OPERATIONAL_SCOPE: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Network_Wide', title: 'Network Wide'}, - {enum: 'Availability_Zone', title: 'Availability Zone'}, - {enum: 'Data_Center', title: 'Data Center'}, - {enum: 'Tenant', title: 'Tenant'}, - {enum: 'VM', title: 'VM'}, - {enum: 'CPU', title: 'CPU'}, - {enum: 'Core', title: 'Core'} - ], - TYPE: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Universal', title: 'Universal'}, - {enum: 'Unique', title: 'Unique'}, - {enum: 'One_Time', title: 'One Time'} - ] + OPERATIONAL_SCOPE: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Network_Wide', title: 'Network Wide' }, + { enum: 'Availability_Zone', title: 'Availability Zone' }, + { enum: 'Data_Center', title: 'Data Center' }, + { enum: 'Tenant', title: 'Tenant' }, + { enum: 'VM', title: 'VM' }, + { enum: 'CPU', title: 'CPU' }, + { enum: 'Core', title: 'Core' } + ], + TYPE: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Universal', title: 'Universal' }, + { enum: 'Unique', title: 'Unique' }, + { enum: 'One_Time', title: 'One Time' } + ] }; -export const extractValue = (item) => { - if (item === undefined) {return '';} //TODO fix it later +export const extractValue = item => { + if (item === undefined) { + return ''; + } //TODO fix it later - return item ? item === optionInputOther.OTHER ? item : InputOptions.getTitleByName(optionsInputValues, item) : ''; + return item + ? item === optionInputOther.OTHER + ? item + : InputOptions.getTitleByName(optionsInputValues, item) + : ''; }; -export const getOperationalScopes = (operationalScope) => { - if(operationalScope.choices.toString() === i18n(optionInputOther.OTHER) && operationalScope.other !== '') { - return operationalScope.other; - } - else { - let allOpScopes = ''; - for (let opScope of operationalScope.choices) { - allOpScopes += allOpScopes === '' ? InputOptions.getTitleByName(optionsInputValues, opScope) : `, ${InputOptions.getTitleByName(optionsInputValues, opScope)}`; - } - return allOpScopes; - } +export const getOperationalScopes = operationalScope => { + if ( + operationalScope.choices.toString() === i18n(optionInputOther.OTHER) && + operationalScope.other !== '' + ) { + return operationalScope.other; + } else { + let allOpScopes = ''; + for (let opScope of operationalScope.choices) { + allOpScopes += + allOpScopes === '' + ? InputOptions.getTitleByName(optionsInputValues, opScope) + : `, ${InputOptions.getTitleByName( + optionsInputValues, + opScope + )}`; + } + return allOpScopes; + } }; export const tabIds = { - GENERAL: 'GENERAL', - SP_LIMITS: 'SP_LIMITS', - VENDOR_LIMITS: 'VENDOR_LIMITS', - ADD_LIMIT_BUTTON: 'ADD_LIMIT_BUTTON' + GENERAL: 'GENERAL', + SP_LIMITS: 'SP_LIMITS', + VENDOR_LIMITS: 'VENDOR_LIMITS', + ADD_LIMIT_BUTTON: 'ADD_LIMIT_BUTTON' }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js index 028fa9d3e4..fa62bba669 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditor.js @@ -13,53 +13,79 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; import LicenseKeyGroupsEditorView from './LicenseKeyGroupsEditorView.jsx'; import LimitEditorActionHelper from '../limits/LimitEditorActionHelper.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -const mapStateToProps = ({licenseModel: {licenseKeyGroup}}) => { +const mapStateToProps = ({ licenseModel: { licenseKeyGroup } }) => { + let { + data, + genericFieldInfo, + formReady, + limitsList + } = licenseKeyGroup.licenseKeyGroupsEditor; + let previousData, + LKGNames = {}; + const licenseKeyGroupId = data ? data.id : null; + if (licenseKeyGroupId) { + previousData = licenseKeyGroup.licenseKeyGroupsList.find( + licenseKeyGroup => licenseKeyGroup.id === licenseKeyGroupId + ); + } - let {data, genericFieldInfo, formReady, limitsList} = licenseKeyGroup.licenseKeyGroupsEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let previousData, LKGNames = {}; - const licenseKeyGroupId = data ? data.id : null; - if(licenseKeyGroupId) { - previousData = licenseKeyGroup.licenseKeyGroupsList.find(licenseKeyGroup => licenseKeyGroup.id === licenseKeyGroupId); - } + const list = licenseKeyGroup.licenseKeyGroupsList; + for (let i = 0; i < list.length; i++) { + LKGNames[list[i].name.toLowerCase()] = list[i].id; + } - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - - const list = licenseKeyGroup.licenseKeyGroupsList; - for (let i = 0; i < list.length; i++) { - LKGNames[list[i].name.toLowerCase()] = list[i].id; - } - - return { - data, - previousData, - genericFieldInfo, - isFormValid, - formReady, - LKGNames, - limitsList - }; + return { + data, + previousData, + genericFieldInfo, + isFormValid, + formReady, + LKGNames, + limitsList + }; }; -const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onCancel: () => LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor(dispatch), - onSubmit: ({previousLicenseKeyGroup, licenseKeyGroup, keepOpen}) => { - if (!keepOpen) {LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor(dispatch);} - LicenseKeyGroupsActionHelper.saveLicenseKeyGroup(dispatch, {licenseModelId, previousLicenseKeyGroup, licenseKeyGroup, version}); - }, - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName), - onCloseLimitEditor: () => LimitEditorActionHelper.closeLimitsEditor(dispatch), - onOpenLimitEditor: (limit) => LimitEditorActionHelper.openLimitsEditor(dispatch, {limit}) - }; +const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onCancel: () => + LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor(dispatch), + onSubmit: ({ previousLicenseKeyGroup, licenseKeyGroup, keepOpen }) => { + if (!keepOpen) { + LicenseKeyGroupsActionHelper.closeLicenseKeyGroupEditor( + dispatch + ); + } + LicenseKeyGroupsActionHelper.saveLicenseKeyGroup(dispatch, { + licenseModelId, + previousLicenseKeyGroup, + licenseKeyGroup, + version + }); + }, + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName), + onCloseLimitEditor: () => + LimitEditorActionHelper.closeLimitsEditor(dispatch), + onOpenLimitEditor: limit => + LimitEditorActionHelper.openLimitsEditor(dispatch, { limit }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseKeyGroupsEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseKeyGroupsEditorView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js index b1a22f3d9a..e948e9cef8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorReducer.js @@ -13,82 +13,97 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, defaultState, LKG_FORM_NAME} from './LicenseKeyGroupsConstants.js'; +import { + actionTypes, + defaultState, + LKG_FORM_NAME +} from './LicenseKeyGroupsConstants.js'; import moment from 'moment'; -import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { DATE_FORMAT } from 'sdc-app/onboarding/OnboardingConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.licenseKeyGroupsEditor.OPEN: - let licenseKeyGroupData = {...action.licenseKeyGroup}; - let {startDate, expiryDate} = licenseKeyGroupData; - if (startDate) { - licenseKeyGroupData.startDate = moment(startDate, DATE_FORMAT).format(DATE_FORMAT); - } - if (expiryDate) { - licenseKeyGroupData.expiryDate = moment(expiryDate, DATE_FORMAT).format(DATE_FORMAT); - } - return { - ...state, - data: action.licenseKeyGroup ? licenseKeyGroupData : defaultState.licenseKeyGroupsEditor, - formReady: null, - formName: LKG_FORM_NAME, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}] - }, - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - 'type' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - 'operationalScope' : { - isValid: true, - errorText: '', - validations: [] - }, - 'thresholdUnits' : { - isValid: true, - errorText: '', - validations: [] - }, - 'thresholdValue' : { - isValid: true, - errorText: '', - validations: [] - }, - 'increments' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 120}] - }, - 'startDate': { - isValid: true, - errorText: '', - validations: [] - }, - 'expiryDate': { - isValid: true, - errorText: '', - validations: [] - } - } - }; - case actionTypes.licenseKeyGroupsEditor.LIMITS_LIST_LOADED: - return { - ...state, - limitsList: action.response.results - }; - case actionTypes.licenseKeyGroupsEditor.CLOSE: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.licenseKeyGroupsEditor.OPEN: + let licenseKeyGroupData = { ...action.licenseKeyGroup }; + let { startDate, expiryDate } = licenseKeyGroupData; + if (startDate) { + licenseKeyGroupData.startDate = moment( + startDate, + DATE_FORMAT + ).format(DATE_FORMAT); + } + if (expiryDate) { + licenseKeyGroupData.expiryDate = moment( + expiryDate, + DATE_FORMAT + ).format(DATE_FORMAT); + } + return { + ...state, + data: action.licenseKeyGroup + ? licenseKeyGroupData + : defaultState.licenseKeyGroupsEditor, + formReady: null, + formName: LKG_FORM_NAME, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }] + }, + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + type: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + operationalScope: { + isValid: true, + errorText: '', + validations: [] + }, + thresholdUnits: { + isValid: true, + errorText: '', + validations: [] + }, + thresholdValue: { + isValid: true, + errorText: '', + validations: [] + }, + increments: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 120 }] + }, + startDate: { + isValid: true, + errorText: '', + validations: [] + }, + expiryDate: { + isValid: true, + errorText: '', + validations: [] + } + } + }; + case actionTypes.licenseKeyGroupsEditor.LIMITS_LIST_LOADED: + return { + ...state, + limitsList: action.response.results + }; + case actionTypes.licenseKeyGroupsEditor.CLOSE: + return {}; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx index 7cbab61a8a..a820f28dfd 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsEditorView.jsx @@ -26,328 +26,498 @@ 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 {optionsInputValues as licenseKeyGroupOptionsInputValues, LKG_FORM_NAME, tabIds} from './LicenseKeyGroupsConstants.js'; -import {optionsInputValues as LicenseModelOptionsInputValues} from '../LicenseModelConstants.js'; -import {validateStartDate, thresholdValueValidation} from '../LicenseModelValidations.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { + optionsInputValues as licenseKeyGroupOptionsInputValues, + LKG_FORM_NAME, + tabIds +} from './LicenseKeyGroupsConstants.js'; +import { optionsInputValues as LicenseModelOptionsInputValues } from '../LicenseModelConstants.js'; +import { + validateStartDate, + thresholdValueValidation +} from '../LicenseModelValidations.js'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; -import {DATE_FORMAT} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { DATE_FORMAT } from 'sdc-app/onboarding/OnboardingConstants.js'; import LicenseKeyGroupsLimits from './LicenseKeyGroupsLimits.js'; -import {limitType, NEW_LIMIT_TEMP_ID} from '../limits/LimitEditorConstants.js'; +import { + limitType, + NEW_LIMIT_TEMP_ID +} from '../limits/LimitEditorConstants.js'; - const LicenseKeyGroupPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - increments: PropTypes.string, - operationalScope: PropTypes.shape({ - choices: PropTypes.array, - other: PropTypes.string - }), - type: PropTypes.string, - thresholdUnits: PropTypes.string, - thresholdValue: PropTypes.number, - startDate: PropTypes.string, - expiryDate: PropTypes.string +const LicenseKeyGroupPropType = PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + increments: PropTypes.string, + operationalScope: PropTypes.shape({ + choices: PropTypes.array, + other: PropTypes.string + }), + type: PropTypes.string, + thresholdUnits: PropTypes.string, + thresholdValue: PropTypes.number, + startDate: PropTypes.string, + expiryDate: PropTypes.string }); -const LicenseKeyGroupFormContent = ({data, onDataChanged, genericFieldInfo, validateName, validateStartDate, thresholdValueValidation}) => { - let {name, description, increments, operationalScope, type, thresholdUnits, thresholdValue, startDate, expiryDate} = data; - return ( - <GridSection hasLostColSet> - <GridItem colSpan={2}> - <Input - onChange={name => onDataChanged({name}, LKG_FORM_NAME, {name: validateName})} - label={i18n('Name')} - data-test-id='create-lkg-name' - value={name} - isValid={genericFieldInfo.name.isValid} - errorText={genericFieldInfo.name.errorText} - isRequired={true} - type='text'/> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <InputOptions - onInputChange={()=>{}} - isMultiSelect={true} - onEnumChange={operationalScope => onDataChanged({operationalScope:{choices: operationalScope, other: ''}}, - LKG_FORM_NAME)} - onOtherChange={operationalScope => onDataChanged({operationalScope:{choices: [optionInputOther.OTHER], - other: operationalScope}}, LKG_FORM_NAME)} - label={i18n('Operational Scope')} - data-test-id='create-lkg-operational-scope' - type='select' - multiSelectedEnum={operationalScope && operationalScope.choices} - otherValue={operationalScope && operationalScope.other} - values={licenseKeyGroupOptionsInputValues.OPERATIONAL_SCOPE} - isValid={genericFieldInfo.operationalScope.isValid} - errorText={genericFieldInfo.operationalScope.errorText} /> - </GridItem> - <GridItem colSpan={2}> - <Input - onChange={description => onDataChanged({description}, LKG_FORM_NAME)} - label={i18n('Description')} - data-test-id='create-lkg-description' - value={description} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - type='textarea' - overlayPos='bottom' /> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - isRequired={true} - onChange={e => { const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({type: val}, LKG_FORM_NAME);}} - value={type} - label={i18n('Type')} - data-test-id='create-lkg-type' - isValid={genericFieldInfo.type.isValid} - errorText={genericFieldInfo.type.errorText} - groupClassName='bootstrap-input-options' - className='input-options-select' - overlayPos='bottom' - type='select' > - { - licenseKeyGroupOptionsInputValues.TYPE.map(type => - (<option key={type.enum} value={type.enum}>{type.title}</option>)) - } - </Input> - </GridItem> - <GridItem> - <Input - onChange={e => { - // setting the unit to the correct value - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({thresholdUnits: val}, LKG_FORM_NAME); - // TODO make sure that the value is valid too - onDataChanged({thresholdValue: thresholdValue}, LKG_FORM_NAME,{thresholdValue : thresholdValueValidation});} - - } - value={thresholdUnits} - label={i18n('Threshold Units')} - data-test-id='create-ep-threshold-units' - isValid={genericFieldInfo.thresholdUnits.isValid} - errorText={genericFieldInfo.thresholdUnits.errorText} - groupClassName='bootstrap-input-options' - className='input-options-select' - type='select' > - {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map(mtype => - <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)} - </Input> - </GridItem> - <GridItem> - <Input - className='entitlement-pools-form-row-threshold-value' - onChange={thresholdValue => onDataChanged({thresholdValue}, LKG_FORM_NAME, - {thresholdValue : thresholdValueValidation})} - label={i18n('Threshold Value')} - isValid={genericFieldInfo.thresholdValue.isValid} - errorText={genericFieldInfo.thresholdValue.errorText} - data-test-id='create-ep-threshold-value' - value={thresholdValue} - type='text'/> - </GridItem> - <GridItem> - <Input - type='date' - label={i18n('Start Date')} - value={startDate} - dateFormat={DATE_FORMAT} - startDate={startDate} - endDate={expiryDate} - onChange={startDate => onDataChanged( - {startDate: startDate ? startDate.format(DATE_FORMAT) : ''}, - LKG_FORM_NAME, - {startDate: validateStartDate} - )} - isValid={genericFieldInfo.startDate.isValid} - errorText={genericFieldInfo.startDate.errorText} - selectsStart/> - </GridItem> - <GridItem lastColInRow> - <Input - type='date' - label={i18n('Expiry Date')} - value={expiryDate} - dateFormat={DATE_FORMAT} - startDate={startDate} - endDate={expiryDate} - onChange={expiryDate => { - onDataChanged({expiryDate: expiryDate ? expiryDate.format(DATE_FORMAT) : ''}, LKG_FORM_NAME); - onDataChanged({startDate}, LKG_FORM_NAME, {startDate: validateStartDate}); - }} - isValid={genericFieldInfo.expiryDate.isValid} - errorText={genericFieldInfo.expiryDate.errorText} - selectsEnd/> - </GridItem> - <GridItem colSpan={2}> - <Input - onChange={increments => onDataChanged({increments}, LKG_FORM_NAME)} - label={i18n('Increments')} - value={increments} - data-test-id='create-ep-increments' - type='text'/> - </GridItem> - </GridSection> - ); +const LicenseKeyGroupFormContent = ({ + data, + onDataChanged, + genericFieldInfo, + validateName, + validateStartDate, + thresholdValueValidation +}) => { + let { + name, + description, + increments, + operationalScope, + type, + thresholdUnits, + thresholdValue, + startDate, + expiryDate + } = data; + return ( + <GridSection hasLostColSet> + <GridItem colSpan={2}> + <Input + onChange={name => + onDataChanged({ name }, LKG_FORM_NAME, { + name: validateName + }) + } + label={i18n('Name')} + data-test-id="create-lkg-name" + value={name} + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + isRequired={true} + type="text" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <InputOptions + onInputChange={() => {}} + isMultiSelect={true} + onEnumChange={operationalScope => + onDataChanged( + { + operationalScope: { + choices: operationalScope, + other: '' + } + }, + LKG_FORM_NAME + ) + } + onOtherChange={operationalScope => + onDataChanged( + { + operationalScope: { + choices: [optionInputOther.OTHER], + other: operationalScope + } + }, + LKG_FORM_NAME + ) + } + label={i18n('Operational Scope')} + data-test-id="create-lkg-operational-scope" + type="select" + multiSelectedEnum={ + operationalScope && operationalScope.choices + } + otherValue={operationalScope && operationalScope.other} + values={licenseKeyGroupOptionsInputValues.OPERATIONAL_SCOPE} + isValid={genericFieldInfo.operationalScope.isValid} + errorText={genericFieldInfo.operationalScope.errorText} + /> + </GridItem> + <GridItem colSpan={2}> + <Input + onChange={description => + onDataChanged({ description }, LKG_FORM_NAME) + } + label={i18n('Description')} + data-test-id="create-lkg-description" + value={description} + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + type="textarea" + overlayPos="bottom" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + isRequired={true} + onChange={e => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onDataChanged({ type: val }, LKG_FORM_NAME); + }} + value={type} + label={i18n('Type')} + data-test-id="create-lkg-type" + isValid={genericFieldInfo.type.isValid} + errorText={genericFieldInfo.type.errorText} + groupClassName="bootstrap-input-options" + className="input-options-select" + overlayPos="bottom" + type="select"> + {licenseKeyGroupOptionsInputValues.TYPE.map(type => ( + <option key={type.enum} value={type.enum}> + {type.title} + </option> + ))} + </Input> + </GridItem> + <GridItem> + <Input + onChange={e => { + // setting the unit to the correct value + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onDataChanged({ thresholdUnits: val }, LKG_FORM_NAME); + // TODO make sure that the value is valid too + onDataChanged( + { thresholdValue: thresholdValue }, + LKG_FORM_NAME, + { + thresholdValue: thresholdValueValidation + } + ); + }} + value={thresholdUnits} + label={i18n('Threshold Units')} + data-test-id="create-ep-threshold-units" + isValid={genericFieldInfo.thresholdUnits.isValid} + errorText={genericFieldInfo.thresholdUnits.errorText} + groupClassName="bootstrap-input-options" + className="input-options-select" + type="select"> + {LicenseModelOptionsInputValues.THRESHOLD_UNITS.map( + mtype => ( + <option key={mtype.enum} value={mtype.enum}>{`${ + mtype.title + }`}</option> + ) + )} + </Input> + </GridItem> + <GridItem> + <Input + className="entitlement-pools-form-row-threshold-value" + onChange={thresholdValue => + onDataChanged({ thresholdValue }, LKG_FORM_NAME, { + thresholdValue: thresholdValueValidation + }) + } + label={i18n('Threshold Value')} + isValid={genericFieldInfo.thresholdValue.isValid} + errorText={genericFieldInfo.thresholdValue.errorText} + data-test-id="create-ep-threshold-value" + value={thresholdValue} + type="text" + /> + </GridItem> + <GridItem> + <Input + type="date" + label={i18n('Start Date')} + value={startDate} + dateFormat={DATE_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={startDate => + onDataChanged( + { + startDate: startDate + ? startDate.format(DATE_FORMAT) + : '' + }, + LKG_FORM_NAME, + { startDate: validateStartDate } + ) + } + isValid={genericFieldInfo.startDate.isValid} + errorText={genericFieldInfo.startDate.errorText} + selectsStart + /> + </GridItem> + <GridItem lastColInRow> + <Input + type="date" + label={i18n('Expiry Date')} + value={expiryDate} + dateFormat={DATE_FORMAT} + startDate={startDate} + endDate={expiryDate} + onChange={expiryDate => { + onDataChanged( + { + expiryDate: expiryDate + ? expiryDate.format(DATE_FORMAT) + : '' + }, + LKG_FORM_NAME + ); + onDataChanged({ startDate }, LKG_FORM_NAME, { + startDate: validateStartDate + }); + }} + isValid={genericFieldInfo.expiryDate.isValid} + errorText={genericFieldInfo.expiryDate.errorText} + selectsEnd + /> + </GridItem> + <GridItem colSpan={2}> + <Input + onChange={increments => + onDataChanged({ increments }, LKG_FORM_NAME) + } + label={i18n('Increments')} + value={increments} + data-test-id="create-ep-increments" + type="text" + /> + </GridItem> + </GridSection> + ); }; class LicenseKeyGroupsEditorView extends React.Component { - static propTypes = { - data: LicenseKeyGroupPropType, - previousData: LicenseKeyGroupPropType, - LKGNames: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; - - static defaultProps = { - data: {} - }; - - componentDidUpdate(prevProps) { - if (this.props.formReady && this.props.formReady !== prevProps.formReady) { // if form validation succeeded -> continue with submit - this.submit(); - } - } + static propTypes = { + data: LicenseKeyGroupPropType, + previousData: LicenseKeyGroupPropType, + LKGNames: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - state = { - localFeatureGroupsListFilter: '', - selectedTab: tabIds.GENERAL, - selectedLimit: '' - }; + static defaultProps = { + data: {} + }; - render() { - let {data = {}, onDataChanged, isReadOnlyMode, onCloseLimitEditor, genericFieldInfo, limitsList = []} = this.props; - let {selectedTab} = this.state; - const isTabsDisabled = !data.id || !this.props.isFormValid; - return ( - <div className='license-keygroup-editor'> - <Tabs - type='menu' - activeTab={selectedTab} - onTabClick={(tabIndex)=>{ - if (tabIndex === tabIds.ADD_LIMIT_BUTTON) { - this.onAddLimit(); - } else { - this.setState({selectedTab: tabIndex}); - onCloseLimitEditor(); - this.setState({selectedLimit: ''}); - } - }} - invalidTabs={[]}> - <Tab tabId={tabIds.GENERAL} data-test-id='general-tab' title={i18n('General')}> - { genericFieldInfo && - <Form - ref='validationForm' - hasButtons={false} - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.props.onValidateForm(LKG_FORM_NAME) } - labledButtons={true} - isReadOnlyMode={isReadOnlyMode} - className='license-model-form license-key-groups-form'> - <LicenseKeyGroupFormContent - data={data} - onDataChanged={onDataChanged} - genericFieldInfo={genericFieldInfo} - validateName={(value)=> this.validateName(value)} - validateStartDate={(value, state)=> validateStartDate(value, state)} - thresholdValueValidation={(value, state) => thresholdValueValidation(value, state)}/> - </Form>} + componentDidUpdate(prevProps) { + if ( + this.props.formReady && + this.props.formReady !== prevProps.formReady + ) { + // if form validation succeeded -> continue with submit + this.submit(); + } + } - </Tab> - <Tab tabId={tabIds.SP_LIMITS} disabled={isTabsDisabled} data-test-id='general-tab' title={i18n('SP Limits')}> - {selectedTab === tabIds.SP_LIMITS && - <LicenseKeyGroupsLimits - limitType={limitType.SERVICE_PROVIDER} - limitsList={limitsList.filter(item => item.type === limitType.SERVICE_PROVIDER)} - selectedLimit={this.state.selectedLimit} - onCloseLimitEditor={() => this.onCloseLimitEditor()} - onSelectLimit={limit => this.onSelectLimit(limit)} - isReadOnlyMode={isReadOnlyMode} />} - </Tab> - <Tab tabId={tabIds.VENDOR_LIMITS} disabled={isTabsDisabled} data-test-id='general-tab' title={i18n('Vendor Limits')}> - {selectedTab === tabIds.VENDOR_LIMITS && - <LicenseKeyGroupsLimits - limitType={limitType.VENDOR} - limitsList={limitsList.filter(item => item.type === limitType.VENDOR)} - selectedLimit={this.state.selectedLimit} - onCloseLimitEditor={() => this.onCloseLimitEditor()} - onSelectLimit={limit => this.onSelectLimit(limit)} - isReadOnlyMode={isReadOnlyMode} />} - </Tab> - {selectedTab !== tabIds.GENERAL ? - <Button - className='add-limit-button' - tabId={tabIds.ADD_LIMIT_BUTTON} - btnType='link' - iconName='plus' - disabled={this.state.selectedLimit || isReadOnlyMode}> - {i18n('Add Limit')} - </Button> - : - <div key='empty_lm_tab_key'></div> // Render empty div to not break tabs - } - </Tabs> + state = { + localFeatureGroupsListFilter: '', + selectedTab: tabIds.GENERAL, + selectedLimit: '' + }; - <GridSection className='license-model-modal-buttons license-key-group-editor-buttons'> - {!this.state.selectedLimit && - <Button btnType='default' disabled={!this.props.isFormValid || isReadOnlyMode} onClick={() => this.submit()} type='reset'> - {i18n('Save')} - </Button> - } - <Button btnType={this.state.selectedLimit ? 'default' : 'outline'} onClick={() => this.props.onCancel()} type='reset'> - {i18n('Cancel')} - </Button> - </GridSection> - </div> + render() { + let { + data = {}, + onDataChanged, + isReadOnlyMode, + onCloseLimitEditor, + genericFieldInfo, + limitsList = [] + } = this.props; + let { selectedTab } = this.state; + const isTabsDisabled = !data.id || !this.props.isFormValid; + return ( + <div className="license-keygroup-editor"> + <Tabs + type="menu" + activeTab={selectedTab} + onTabClick={tabIndex => { + if (tabIndex === tabIds.ADD_LIMIT_BUTTON) { + this.onAddLimit(); + } else { + this.setState({ selectedTab: tabIndex }); + onCloseLimitEditor(); + this.setState({ selectedLimit: '' }); + } + }} + invalidTabs={[]}> + <Tab + tabId={tabIds.GENERAL} + data-test-id="general-tab" + title={i18n('General')}> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={false} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => + this.props.onValidateForm(LKG_FORM_NAME) + } + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + className="license-model-form license-key-groups-form"> + <LicenseKeyGroupFormContent + data={data} + onDataChanged={onDataChanged} + genericFieldInfo={genericFieldInfo} + validateName={value => + this.validateName(value) + } + validateStartDate={(value, state) => + validateStartDate(value, state) + } + thresholdValueValidation={(value, state) => + thresholdValueValidation(value, state) + } + /> + </Form> + )} + </Tab> + <Tab + tabId={tabIds.SP_LIMITS} + disabled={isTabsDisabled} + data-test-id="general-tab" + title={i18n('SP Limits')}> + {selectedTab === tabIds.SP_LIMITS && ( + <LicenseKeyGroupsLimits + limitType={limitType.SERVICE_PROVIDER} + limitsList={limitsList.filter( + item => + item.type === limitType.SERVICE_PROVIDER + )} + selectedLimit={this.state.selectedLimit} + onCloseLimitEditor={() => + this.onCloseLimitEditor() + } + onSelectLimit={limit => + this.onSelectLimit(limit) + } + isReadOnlyMode={isReadOnlyMode} + /> + )} + </Tab> + <Tab + tabId={tabIds.VENDOR_LIMITS} + disabled={isTabsDisabled} + data-test-id="general-tab" + title={i18n('Vendor Limits')}> + {selectedTab === tabIds.VENDOR_LIMITS && ( + <LicenseKeyGroupsLimits + limitType={limitType.VENDOR} + limitsList={limitsList.filter( + item => item.type === limitType.VENDOR + )} + selectedLimit={this.state.selectedLimit} + onCloseLimitEditor={() => + this.onCloseLimitEditor() + } + onSelectLimit={limit => + this.onSelectLimit(limit) + } + isReadOnlyMode={isReadOnlyMode} + /> + )} + </Tab> + {selectedTab !== tabIds.GENERAL ? ( + <Button + className="add-limit-button" + tabId={tabIds.ADD_LIMIT_BUTTON} + btnType="link" + iconName="plus" + disabled={ + this.state.selectedLimit || isReadOnlyMode + }> + {i18n('Add Limit')} + </Button> + ) : ( + <div key="empty_lm_tab_key" /> + ) // Render empty div to not break tabs + } + </Tabs> - ); - } + <GridSection className="license-model-modal-buttons license-key-group-editor-buttons"> + {!this.state.selectedLimit && ( + <Button + btnType="default" + disabled={!this.props.isFormValid || isReadOnlyMode} + onClick={() => this.submit()} + type="reset"> + {i18n('Save')} + </Button> + )} + <Button + btnType={ + this.state.selectedLimit ? 'default' : 'outline' + } + onClick={() => this.props.onCancel()} + type="reset"> + {i18n('Cancel')} + </Button> + </GridSection> + </div> + ); + } - submit() { - const {data: licenseKeyGroup, previousData: previousLicenseKeyGroup, formReady, onValidateForm, onSubmit} = this.props; - if (!formReady) { - onValidateForm(LKG_FORM_NAME); - } else { - onSubmit({licenseKeyGroup, previousLicenseKeyGroup}); - } - } + submit() { + const { + data: licenseKeyGroup, + previousData: previousLicenseKeyGroup, + formReady, + onValidateForm, + onSubmit + } = this.props; + if (!formReady) { + onValidateForm(LKG_FORM_NAME); + } else { + onSubmit({ licenseKeyGroup, previousLicenseKeyGroup }); + } + } - validateName(value) { - const {data: {id}, LKGNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: LKGNames}); + validateName(value) { + const { data: { id }, LKGNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: LKGNames + }); - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('License key group by the name \'' + value + '\' already exists. License key group name must be unique')}; - } + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "License key group by the name '" + + value + + "' already exists. License key group name must be unique" + ) + }; + } - onSelectLimit(limit) { - if (limit.id === this.state.selectedLimit) { - this.setState({selectedLimit: ''}); - return; - } - this.setState({selectedLimit: limit.id}); - this.props.onOpenLimitEditor(limit); - } + onSelectLimit(limit) { + if (limit.id === this.state.selectedLimit) { + this.setState({ selectedLimit: '' }); + return; + } + this.setState({ selectedLimit: limit.id }); + this.props.onOpenLimitEditor(limit); + } - onCloseLimitEditor() { - this.setState({selectedLimit: ''}); - this.props.onCloseLimitEditor(); - } + onCloseLimitEditor() { + this.setState({ selectedLimit: '' }); + this.props.onCloseLimitEditor(); + } - onAddLimit() { - this.setState({selectedLimit: NEW_LIMIT_TEMP_ID}); - this.props.onOpenLimitEditor(); - } + onAddLimit() { + this.setState({ selectedLimit: NEW_LIMIT_TEMP_ID }); + this.props.onOpenLimitEditor(); + } } export default LicenseKeyGroupsEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsLimits.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsLimits.js index bd8f21a7c5..ad14c6c249 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsLimits.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsLimits.js @@ -13,45 +13,75 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as globalModalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as globalModalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import Limits from 'sdc-app/onboarding/licenseModel/limits/Limits.jsx'; import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; -const mapStateToProps = ({licenseModel: {licenseKeyGroup: {licenseKeyGroupsEditor: {data}}, limitEditor}, currentScreen}) => { - let {props: {licenseModelId, version}} = currentScreen; - return { - parent: data, - limitEditor, - licenseModelId, - version - }; +const mapStateToProps = ({ + licenseModel: { + licenseKeyGroup: { licenseKeyGroupsEditor: { data } }, + limitEditor + }, + currentScreen +}) => { + let { props: { licenseModelId, version } } = currentScreen; + return { + parent: data, + limitEditor, + licenseModelId, + version + }; }; -const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onSubmit: (limit, licenseKeyGroup, licenseModelId, version) => LicenseKeyGroupsActionHelper.submitLimit(dispatch, - { - limit, - licenseKeyGroup, - licenseModelId, - version}), - onDelete: ({limit, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit}) => dispatch({ - type: globalModalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete {name}?', {name: limit.name}), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=> LicenseKeyGroupsActionHelper.deleteLimit(dispatch, {limit, licenseKeyGroup: parent, licenseModelId, version}).then(() => - selectedLimit === limit.id && onCloseLimitEditor() - ) - } - }) - }; +const mapActionsToProps = dispatch => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onSubmit: (limit, licenseKeyGroup, licenseModelId, version) => + LicenseKeyGroupsActionHelper.submitLimit(dispatch, { + limit, + licenseKeyGroup, + licenseModelId, + version + }), + onDelete: ({ + limit, + parent, + licenseModelId, + version, + onCloseLimitEditor, + selectedLimit + }) => + dispatch({ + type: globalModalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete {name}?', { + name: limit.name + }), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + LicenseKeyGroupsActionHelper.deleteLimit(dispatch, { + limit, + licenseKeyGroup: parent, + licenseModelId, + version + }).then( + () => + selectedLimit === limit.id && + onCloseLimitEditor() + ) + } + }) + }; }; export default connect(mapStateToProps, mapActionsToProps)(Limits); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js index 00c2092b83..6151c5997d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditor.js @@ -13,41 +13,62 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as globalMoadlActions} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as globalMoadlActions } from 'nfvo-components/modal/GlobalModalConstants.js'; import LicenseKeyGroupsActionHelper from './LicenseKeyGroupsActionHelper.js'; -import LicenseKeyGroupsListEditorView, {generateConfirmationMsg} from './LicenseKeyGroupsListEditorView.jsx'; +import LicenseKeyGroupsListEditorView, { + generateConfirmationMsg +} from './LicenseKeyGroupsListEditorView.jsx'; -const mapStateToProps = ({licenseModel: {licenseKeyGroup, licenseModelEditor}}) => { - let {licenseKeyGroupsList} = licenseKeyGroup; - let {data} = licenseKeyGroup.licenseKeyGroupsEditor; - let {vendorName} = licenseModelEditor.data; +const mapStateToProps = ({ + licenseModel: { licenseKeyGroup, licenseModelEditor } +}) => { + let { licenseKeyGroupsList } = licenseKeyGroup; + let { data } = licenseKeyGroup.licenseKeyGroupsEditor; + let { vendorName } = licenseModelEditor.data; - return { - vendorName, - licenseKeyGroupsList, - isDisplayModal: Boolean(data), - isModalInEditMode: Boolean(data && data.id) - }; + return { + vendorName, + licenseKeyGroupsList, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; }; -const mapActionsToProps = (dispatch, {licenseModelId, version}) => { - return { - onAddLicenseKeyGroupClick: () => LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch), - onEditLicenseKeyGroupClick: licenseKeyGroup => LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch, {licenseKeyGroup, licenseModelId, version}), - onDeleteLicenseKeyGroupClick: licenseKeyGroup => dispatch({ - type: globalMoadlActions.GLOBAL_MODAL_WARNING, - data:{ - msg: generateConfirmationMsg(licenseKeyGroup), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: () => LicenseKeyGroupsActionHelper.deleteLicenseKeyGroup(dispatch, {licenseModelId, licenseKeyGroupId:licenseKeyGroup.id, version}) - } - }) - }; +const mapActionsToProps = (dispatch, { licenseModelId, version }) => { + return { + onAddLicenseKeyGroupClick: () => + LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch), + onEditLicenseKeyGroupClick: licenseKeyGroup => + LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch, { + licenseKeyGroup, + licenseModelId, + version + }), + onDeleteLicenseKeyGroupClick: licenseKeyGroup => + dispatch({ + type: globalMoadlActions.GLOBAL_MODAL_WARNING, + data: { + msg: generateConfirmationMsg(licenseKeyGroup), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + LicenseKeyGroupsActionHelper.deleteLicenseKeyGroup( + dispatch, + { + licenseModelId, + licenseKeyGroupId: licenseKeyGroup.id, + version + } + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseKeyGroupsListEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseKeyGroupsListEditorView +); 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 5a98b7f575..4c8c8cee6f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListEditorView.jsx @@ -21,143 +21,205 @@ import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; import LicenseKeyGroupsEditor from './LicenseKeyGroupsEditor.js'; -import InputOptions, {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; -import {optionsInputValues} from './LicenseKeyGroupsConstants'; +import InputOptions, { + other as optionInputOther +} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { optionsInputValues } from './LicenseKeyGroupsConstants'; class LicenseKeyGroupsListEditorView extends React.Component { - static propTypes = { - vendorName: PropTypes.string, - licenseModelId: PropTypes.string.isRequired, - licenseKeyGroupsList: PropTypes.array, - isReadOnlyMode: PropTypes.bool.isRequired, - isDisplayModal: PropTypes.bool, - isModalInEditMode: PropTypes.bool, - onAddLicenseKeyGroupClick: PropTypes.func, - onEditLicenseKeyGroupClick: PropTypes.func, - onDeleteLicenseKeyGroupClick: PropTypes.func - }; - - static defaultProps = { - licenseKeyGroupsList: [] - }; - - state = { - localFilter: '' - }; - - render() { - let {licenseModelId, isReadOnlyMode, isDisplayModal, isModalInEditMode, version} = this.props; - let {onAddLicenseKeyGroupClick} = this.props; - const {localFilter} = this.state; - - return ( - <div className='license-model-list-editor license-key-groups-list-editor'> - <ListEditorView - title={i18n('License Key Groups')} - plusButtonTitle={i18n('Add License Key Group')} - onAdd={onAddLicenseKeyGroupClick} - filterValue={localFilter} - onFilter={value => this.setState({localFilter: value})} - isReadOnlyMode={isReadOnlyMode}> - {this.filterList().map(licenseKeyGroup => (this.renderLicenseKeyGroupListItem(licenseKeyGroup, isReadOnlyMode)))} - </ListEditorView> - <Modal show={isDisplayModal} bsSize='large' animation={true} className='onborading-modal license-model-modal license-key-groups-modal'> - <Modal.Header> - <Modal.Title>{`${isModalInEditMode ? i18n('Edit License Key Group') : i18n('Create New License Key Group')}`}</Modal.Title> - </Modal.Header> - <Modal.Body> - { - isDisplayModal && ( - <LicenseKeyGroupsEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/> - ) - } - </Modal.Body> - </Modal> - </div> - ); - } - - filterList() { - let {licenseKeyGroupsList} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return licenseKeyGroupsList.filter(({name = '', description = '', operationalScope = '', type = ''}) => { - return escape(name).match(filter) || escape(description).match(filter) || escape(this.extractValue(operationalScope)).match(filter) || escape(type).match(filter); - }); - } - else { - return licenseKeyGroupsList; - } - } - - renderLicenseKeyGroupListItem(licenseKeyGroup, isReadOnlyMode) { - let {id, name, description, operationalScope, type} = licenseKeyGroup; - let {onEditLicenseKeyGroupClick, onDeleteLicenseKeyGroupClick} = this.props; - return ( - <ListEditorItemView - key={id} - onSelect={() => onEditLicenseKeyGroupClick(licenseKeyGroup)} - onDelete={() => onDeleteLicenseKeyGroupClick(licenseKeyGroup)} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode}> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Name')}</div> - <div className='text name'>{name}</div> - </div> - - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Operational Scope')}</div> - <div className='text operational-scope'>{operationalScope && this.getOperationalScopes(operationalScope)}</div> - - <div className='title'>{i18n('Type')}</div> - <div className='text type'>{InputOptions.getTitleByName(optionsInputValues, type)}</div> - </div> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Description')}</div> - <div className='text description'>{description}</div> - </div> - </ListEditorItemView> - ); - } - - getOperationalScopes(operationalScope) { - - if (operationalScope.choices && operationalScope.choices.toString() === i18n(optionInputOther.OTHER)) { - return operationalScope.other; - } else if (operationalScope.choices) { - let allOpScopes = ''; - for (let opScope of operationalScope.choices) { - allOpScopes += allOpScopes === '' ? InputOptions.getTitleByName(optionsInputValues, opScope) : `, ${InputOptions.getTitleByName(optionsInputValues, opScope)}`; - } - return allOpScopes; - } else { - return ''; - } - } - - extractValue(item) { - if (item === undefined) { - return ''; - } //TODO fix it sooner rather than later - - return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; - } + static propTypes = { + vendorName: PropTypes.string, + licenseModelId: PropTypes.string.isRequired, + licenseKeyGroupsList: PropTypes.array, + isReadOnlyMode: PropTypes.bool.isRequired, + isDisplayModal: PropTypes.bool, + isModalInEditMode: PropTypes.bool, + onAddLicenseKeyGroupClick: PropTypes.func, + onEditLicenseKeyGroupClick: PropTypes.func, + onDeleteLicenseKeyGroupClick: PropTypes.func + }; + + static defaultProps = { + licenseKeyGroupsList: [] + }; + + state = { + localFilter: '' + }; + + render() { + let { + licenseModelId, + isReadOnlyMode, + isDisplayModal, + isModalInEditMode, + version + } = this.props; + let { onAddLicenseKeyGroupClick } = this.props; + const { localFilter } = this.state; + + return ( + <div className="license-model-list-editor license-key-groups-list-editor"> + <ListEditorView + title={i18n('License Key Groups')} + plusButtonTitle={i18n('Add License Key Group')} + onAdd={onAddLicenseKeyGroupClick} + filterValue={localFilter} + onFilter={value => this.setState({ localFilter: value })} + isReadOnlyMode={isReadOnlyMode}> + {this.filterList().map(licenseKeyGroup => + this.renderLicenseKeyGroupListItem( + licenseKeyGroup, + isReadOnlyMode + ) + )} + </ListEditorView> + <Modal + show={isDisplayModal} + bsSize="large" + animation={true} + className="onborading-modal license-model-modal license-key-groups-modal"> + <Modal.Header> + <Modal.Title>{`${ + isModalInEditMode + ? i18n('Edit License Key Group') + : i18n('Create New License Key Group') + }`}</Modal.Title> + </Modal.Header> + <Modal.Body> + {isDisplayModal && ( + <LicenseKeyGroupsEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </Modal.Body> + </Modal> + </div> + ); + } + + filterList() { + let { licenseKeyGroupsList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return licenseKeyGroupsList.filter( + ({ + name = '', + description = '', + operationalScope = '', + type = '' + }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) || + escape(this.extractValue(operationalScope)).match( + filter + ) || + escape(type).match(filter) + ); + } + ); + } else { + return licenseKeyGroupsList; + } + } + + renderLicenseKeyGroupListItem(licenseKeyGroup, isReadOnlyMode) { + let { id, name, description, operationalScope, type } = licenseKeyGroup; + let { + onEditLicenseKeyGroupClick, + onDeleteLicenseKeyGroupClick + } = this.props; + return ( + <ListEditorItemView + key={id} + onSelect={() => onEditLicenseKeyGroupClick(licenseKeyGroup)} + onDelete={() => onDeleteLicenseKeyGroupClick(licenseKeyGroup)} + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div className="text name">{name}</div> + </div> + + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Operational Scope')}</div> + <div className="text operational-scope"> + {operationalScope && + this.getOperationalScopes(operationalScope)} + </div> + + <div className="title">{i18n('Type')}</div> + <div className="text type"> + {InputOptions.getTitleByName(optionsInputValues, type)} + </div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Description')}</div> + <div className="text description">{description}</div> + </div> + </ListEditorItemView> + ); + } + + getOperationalScopes(operationalScope) { + if ( + operationalScope.choices && + operationalScope.choices.toString() === i18n(optionInputOther.OTHER) + ) { + return operationalScope.other; + } else if (operationalScope.choices) { + let allOpScopes = ''; + for (let opScope of operationalScope.choices) { + allOpScopes += + allOpScopes === '' + ? InputOptions.getTitleByName( + optionsInputValues, + opScope + ) + : `, ${InputOptions.getTitleByName( + optionsInputValues, + opScope + )}`; + } + return allOpScopes; + } else { + return ''; + } + } + + extractValue(item) { + if (item === undefined) { + return ''; + } //TODO fix it sooner rather than later + + return item + ? item.choice === optionInputOther.OTHER + ? item.other + : InputOptions.getTitleByName(optionsInputValues, item.choice) + : ''; + } } export default LicenseKeyGroupsListEditorView; export function generateConfirmationMsg(licenseKeyGroupToDelete) { - let name = licenseKeyGroupToDelete ? licenseKeyGroupToDelete.name : ''; - let msg = i18n('Are you sure you want to delete "{name}"?', {name: name}); - let subMsg = licenseKeyGroupToDelete.referencingFeatureGroups - && licenseKeyGroupToDelete.referencingFeatureGroups.length > 0 ? - i18n('This license key group is associated with one or more feature groups') : - ''; - return ( - <div> - <p>{msg}</p> - <p>{subMsg}</p> - </div> - ); + let name = licenseKeyGroupToDelete ? licenseKeyGroupToDelete.name : ''; + let msg = i18n('Are you sure you want to delete "{name}"?', { name: name }); + let subMsg = + licenseKeyGroupToDelete.referencingFeatureGroups && + licenseKeyGroupToDelete.referencingFeatureGroups.length > 0 + ? i18n( + 'This license key group is associated with one or more feature groups' + ) + : ''; + return ( + <div> + <p>{msg}</p> + <p>{subMsg}</p> + </div> + ); } diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js index 1f0a64e295..1cd1da0d82 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/licenseKeyGroups/LicenseKeyGroupsListReducer.js @@ -13,20 +13,29 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './LicenseKeyGroupsConstants.js'; +import { actionTypes } from './LicenseKeyGroupsConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.LICENSE_KEY_GROUPS_LIST_LOADED: - return [...action.response.results]; - case actionTypes.DELETE_LICENSE_KEY_GROUP: - return state.filter(licenseKeyGroup => licenseKeyGroup.id !== action.licenseKeyGroupId); - case actionTypes.ADD_LICENSE_KEY_GROUP: - return [...state, action.licenseKeyGroup]; - case actionTypes.EDIT_LICENSE_KEY_GROUP: - const indexForEdit = state.findIndex(licenseKeyGroup => licenseKeyGroup.id === action.licenseKeyGroup.id); - return [...state.slice(0, indexForEdit), action.licenseKeyGroup, ...state.slice(indexForEdit + 1)]; - default: - return state; - } + switch (action.type) { + case actionTypes.LICENSE_KEY_GROUPS_LIST_LOADED: + return [...action.response.results]; + case actionTypes.DELETE_LICENSE_KEY_GROUP: + return state.filter( + licenseKeyGroup => + licenseKeyGroup.id !== action.licenseKeyGroupId + ); + case actionTypes.ADD_LICENSE_KEY_GROUP: + return [...state, action.licenseKeyGroup]; + case actionTypes.EDIT_LICENSE_KEY_GROUP: + const indexForEdit = state.findIndex( + licenseKeyGroup => + licenseKeyGroup.id === action.licenseKeyGroup.id + ); + return [ + ...state.slice(0, indexForEdit), + action.licenseKeyGroup, + ...state.slice(indexForEdit + 1) + ]; + default: + return state; + } }; - diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js index d483383472..76ea36db98 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.js @@ -1,25 +1,30 @@ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import LimitEditor from './LimitEditor.jsx'; -const mapStateToProps = ({licenseModel: {limitEditor}}) => { +const mapStateToProps = ({ licenseModel: { limitEditor } }) => { + let { data, genericFieldInfo, formReady } = limitEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let {data, genericFieldInfo, formReady} = limitEditor; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - - return { - data, - genericFieldInfo, - isFormValid, - formReady - }; + return { + data, + genericFieldInfo, + isFormValid, + formReady + }; }; -const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; +const mapActionsToProps = dispatch => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LimitEditor);
\ No newline at end of file +export default connect(mapStateToProps, mapActionsToProps)(LimitEditor); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx index 54f057eaa4..0d1d4eaf10 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditor.jsx @@ -5,206 +5,349 @@ 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 {LIMITS_FORM_NAME, selectValues} from './LimitEditorConstants.js'; +import { LIMITS_FORM_NAME, selectValues } from './LimitEditorConstants.js'; import Button from 'sdc-ui/lib/react/Button.js'; import Validator from 'nfvo-utils/Validator.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; const LimitPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - metric: PropTypes.shape({ - choice: PropTypes.string, - other: PropTypes.string - }), - value: PropTypes.string, - aggregationFunction: PropTypes.string, - time: PropTypes.string, - unit: PropTypes.shape({ - choice: PropTypes.string, - other: PropTypes.string - }) + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + metric: PropTypes.shape({ + choice: PropTypes.string, + other: PropTypes.string + }), + value: PropTypes.string, + aggregationFunction: PropTypes.string, + time: PropTypes.string, + unit: PropTypes.shape({ + choice: PropTypes.string, + other: PropTypes.string + }) }); class LimitEditor extends React.Component { - static propTypes = { - data: LimitPropType, - limitsNames: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - isFormValid: PropTypes.bool, - formReady: PropTypes.bool, - genericFieldInfo: PropTypes.object.isRequired, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onValidateForm: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; + static propTypes = { + data: LimitPropType, + limitsNames: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + isFormValid: PropTypes.bool, + formReady: PropTypes.bool, + genericFieldInfo: PropTypes.object.isRequired, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onValidateForm: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - componentDidUpdate(prevProps) { - if (this.props.formReady && this.props.formReady !== prevProps.formReady) { - this.submit(); - } - } + componentDidUpdate(prevProps) { + if ( + this.props.formReady && + this.props.formReady !== prevProps.formReady + ) { + this.submit(); + } + } - render() { - let {data = {}, onDataChanged, isReadOnlyMode, genericFieldInfo, onCancel, isFormValid, formReady, onValidateForm} = this.props; - let {name, description, metric, value, aggregationFunction, time, unit} = data; - return ( - <div className='limit-editor'> - {!data.id && - <div className='limit-editor-title'> - {data.name ? data.name : i18n('NEW LIMIT')} - </div>} - { - genericFieldInfo && - <Form - ref='validationForm' - hasButtons={false} - isValid={isFormValid} - formReady={formReady} - onValidateForm={() => onValidateForm(LIMITS_FORM_NAME) } - labledButtons={false} - isReadOnlyMode={isReadOnlyMode} - className='limit-editor-form'> - <GridSection className='limit-editor-form-grid-section' hasLastColSet> - <GridItem colSpan={2}> - <Input - onChange={name => onDataChanged({name}, LIMITS_FORM_NAME, {name: () => this.validateName(name)})} - label={i18n('Name')} - data-test-id='limit-editor-name' - value={name} - isValid={genericFieldInfo.name.isValid} - errorText={genericFieldInfo.name.errorText} - isRequired={true} - type='text'/> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - onChange={description => onDataChanged({description}, LIMITS_FORM_NAME)} - label={i18n('Description')} - data-test-id='limit-editor-description' - value={description} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - isRequired={false} - type='text'/> - </GridItem> - <GridItem colSpan={2}> - <InputOptions - onInputChange={()=>{}} - isMultiSelect={false} - isRequired={true} - onEnumChange={metric => onDataChanged({metric:{choice: metric, other: ''}}, - LIMITS_FORM_NAME)} - onOtherChange={metric => onDataChanged({metric:{choice: optionInputOther.OTHER, - other: metric}}, LIMITS_FORM_NAME)} - label={i18n('Metric')} - data-test-id='limit-editor-metric' - type='select' - required={true} - selectedEnum={metric && metric.choice} - otherValue={metric && metric.other} - values={selectValues.METRIC} - isValid={genericFieldInfo.metric.isValid} - errorText={genericFieldInfo.metric.errorText} /> - </GridItem> - <GridItem> - <Input - onChange={value => onDataChanged({value}, LIMITS_FORM_NAME)} - label={i18n('Metric value')} - data-test-id='limit-editor-metric-value' - value={value} - isValid={genericFieldInfo.value.isValid} - errorText={genericFieldInfo.value.errorText} - isRequired={true} - type='text'/> - </GridItem> - <GridItem lastColInRow> - <InputOptions - onInputChange={()=>{}} - isMultiSelect={false} - isRequired={false} - onEnumChange={unit => onDataChanged({unit:{choice: unit, other: ''}}, - LIMITS_FORM_NAME)} - onOtherChange={unit => onDataChanged({unit:{choice: optionInputOther.OTHER, - other: unit}}, LIMITS_FORM_NAME)} - label={i18n('Units')} - data-test-id='limit-editor-units' - type='select' - required={false} - selectedEnum={unit && unit.choice} - otherValue={unit && unit.other} - values={selectValues.UNIT} - isValid={genericFieldInfo.unit.isValid} - errorText={genericFieldInfo.unit.errorText} /> - </GridItem> - <GridItem colSpan={2}> - <Input - onChange={e => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({aggregationFunction: val}, LIMITS_FORM_NAME);} - } - value={aggregationFunction} - label={i18n('Aggregation Function')} - data-test-id='limit-editor-aggregation-function' - isValid={genericFieldInfo.aggregationFunction.isValid} - errorText={genericFieldInfo.aggregationFunction.errorText} - groupClassName='bootstrap-input-options' - className='input-options-select' - type='select' > - {selectValues.AGGREGATION_FUNCTION.map(mtype => - <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)} - </Input> - </GridItem> - <GridItem> - <Input - onChange={e => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({time: val}, LIMITS_FORM_NAME);} - } - value={time} - label={i18n('Time')} - data-test-id='limit-editor-time' - isValid={genericFieldInfo.time.isValid} - errorText={genericFieldInfo.time.errorText} - groupClassName='bootstrap-input-options' - className='input-options-select' - type='select' > - {selectValues.TIME.map(mtype => - <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)} - </Input> - </GridItem> - </GridSection> - <GridSection className='limit-editor-buttons'> - <Button btnType='outline' disabled={!isFormValid || isReadOnlyMode} onClick={() => this.submit()} type='reset'>{i18n('Save')}</Button> - <Button btnType='outline' color='gray' onClick={onCancel} type='reset'>{i18n('Cancel')}</Button> - </GridSection> - </Form> - } - </div> - ); - } + render() { + let { + data = {}, + onDataChanged, + isReadOnlyMode, + genericFieldInfo, + onCancel, + isFormValid, + formReady, + onValidateForm + } = this.props; + let { + name, + description, + metric, + value, + aggregationFunction, + time, + unit + } = data; + return ( + <div className="limit-editor"> + {!data.id && ( + <div className="limit-editor-title"> + {data.name ? data.name : i18n('NEW LIMIT')} + </div> + )} + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={false} + isValid={isFormValid} + formReady={formReady} + onValidateForm={() => onValidateForm(LIMITS_FORM_NAME)} + labledButtons={false} + isReadOnlyMode={isReadOnlyMode} + className="limit-editor-form"> + <GridSection + className="limit-editor-form-grid-section" + hasLastColSet> + <GridItem colSpan={2}> + <Input + onChange={name => + onDataChanged( + { name }, + LIMITS_FORM_NAME, + { + name: () => + this.validateName(name) + } + ) + } + label={i18n('Name')} + data-test-id="limit-editor-name" + value={name} + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + isRequired={true} + type="text" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + onChange={description => + onDataChanged( + { description }, + LIMITS_FORM_NAME + ) + } + label={i18n('Description')} + data-test-id="limit-editor-description" + value={description} + isValid={ + genericFieldInfo.description.isValid + } + errorText={ + genericFieldInfo.description.errorText + } + isRequired={false} + type="text" + /> + </GridItem> + <GridItem colSpan={2}> + <InputOptions + onInputChange={() => {}} + isMultiSelect={false} + isRequired={true} + onEnumChange={metric => + onDataChanged( + { + metric: { + choice: metric, + other: '' + } + }, + LIMITS_FORM_NAME + ) + } + onOtherChange={metric => + onDataChanged( + { + metric: { + choice: + optionInputOther.OTHER, + other: metric + } + }, + LIMITS_FORM_NAME + ) + } + label={i18n('Metric')} + data-test-id="limit-editor-metric" + type="select" + required={true} + selectedEnum={metric && metric.choice} + otherValue={metric && metric.other} + values={selectValues.METRIC} + isValid={genericFieldInfo.metric.isValid} + errorText={ + genericFieldInfo.metric.errorText + } + /> + </GridItem> + <GridItem> + <Input + onChange={value => + onDataChanged( + { value }, + LIMITS_FORM_NAME + ) + } + label={i18n('Metric value')} + data-test-id="limit-editor-metric-value" + value={value} + isValid={genericFieldInfo.value.isValid} + errorText={genericFieldInfo.value.errorText} + isRequired={true} + type="text" + /> + </GridItem> + <GridItem lastColInRow> + <InputOptions + onInputChange={() => {}} + isMultiSelect={false} + isRequired={false} + onEnumChange={unit => + onDataChanged( + { + unit: { + choice: unit, + other: '' + } + }, + LIMITS_FORM_NAME + ) + } + onOtherChange={unit => + onDataChanged( + { + unit: { + choice: + optionInputOther.OTHER, + other: unit + } + }, + LIMITS_FORM_NAME + ) + } + label={i18n('Units')} + data-test-id="limit-editor-units" + type="select" + required={false} + selectedEnum={unit && unit.choice} + otherValue={unit && unit.other} + values={selectValues.UNIT} + isValid={genericFieldInfo.unit.isValid} + errorText={genericFieldInfo.unit.errorText} + /> + </GridItem> + <GridItem colSpan={2}> + <Input + onChange={e => { + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[selectedIndex] + .value; + onDataChanged( + { aggregationFunction: val }, + LIMITS_FORM_NAME + ); + }} + value={aggregationFunction} + label={i18n('Aggregation Function')} + data-test-id="limit-editor-aggregation-function" + isValid={ + genericFieldInfo.aggregationFunction + .isValid + } + errorText={ + genericFieldInfo.aggregationFunction + .errorText + } + groupClassName="bootstrap-input-options" + className="input-options-select" + type="select"> + {selectValues.AGGREGATION_FUNCTION.map( + mtype => ( + <option + key={mtype.enum} + value={mtype.enum}>{`${ + mtype.title + }`}</option> + ) + )} + </Input> + </GridItem> + <GridItem> + <Input + onChange={e => { + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[selectedIndex] + .value; + onDataChanged( + { time: val }, + LIMITS_FORM_NAME + ); + }} + value={time} + label={i18n('Time')} + data-test-id="limit-editor-time" + isValid={genericFieldInfo.time.isValid} + errorText={genericFieldInfo.time.errorText} + groupClassName="bootstrap-input-options" + className="input-options-select" + type="select"> + {selectValues.TIME.map(mtype => ( + <option + key={mtype.enum} + value={mtype.enum}>{`${ + mtype.title + }`}</option> + ))} + </Input> + </GridItem> + </GridSection> + <GridSection className="limit-editor-buttons"> + <Button + btnType="outline" + disabled={!isFormValid || isReadOnlyMode} + onClick={() => this.submit()} + type="reset"> + {i18n('Save')} + </Button> + <Button + btnType="outline" + color="gray" + onClick={onCancel} + type="reset"> + {i18n('Cancel')} + </Button> + </GridSection> + </Form> + )} + </div> + ); + } - validateName(value) { - const {data: {id}, limitsNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: limitsNames}); + validateName(value) { + const { data: { id }, limitsNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: limitsNames + }); - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('Limit by the name \'' + value + '\' already exists. Limit name must be unique')}; - } + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "Limit by the name '" + + value + + "' already exists. Limit name must be unique" + ) + }; + } - - submit() { - if (!this.props.formReady) { - this.props.onValidateForm(LIMITS_FORM_NAME); - } else { - this.props.onSubmit(); - } - } + submit() { + if (!this.props.formReady) { + this.props.onValidateForm(LIMITS_FORM_NAME); + } else { + this.props.onSubmit(); + } + } } export default LimitEditor; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js index 8ac845a1a7..a275808d01 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorActionHelper.js @@ -14,41 +14,47 @@ * permissions and limitations under the License. */ -import {actionTypes, selectValues} from './LimitEditorConstants.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; - +import { actionTypes, selectValues } from './LimitEditorConstants.js'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; const LimitEditorActionHelper = { - openLimitsEditor(dispatch, {limit}) { - let modifiedLimit = {...limit}; - if (limit && limit.metric) { - modifiedLimit.metric = LimitEditorActionHelper.createChoiceObject(modifiedLimit.metric, selectValues.METRIC); - } - if (limit && limit.unit) { - modifiedLimit.unit = LimitEditorActionHelper.createChoiceObject(modifiedLimit.unit, selectValues.UNIT); - } - dispatch({type: actionTypes.OPEN, limitItem: modifiedLimit}); - }, + openLimitsEditor(dispatch, { limit }) { + let modifiedLimit = { ...limit }; + if (limit && limit.metric) { + modifiedLimit.metric = LimitEditorActionHelper.createChoiceObject( + modifiedLimit.metric, + selectValues.METRIC + ); + } + if (limit && limit.unit) { + modifiedLimit.unit = LimitEditorActionHelper.createChoiceObject( + modifiedLimit.unit, + selectValues.UNIT + ); + } + dispatch({ type: actionTypes.OPEN, limitItem: modifiedLimit }); + }, - closeLimitsEditor(dispatch) { - dispatch({type: actionTypes.CLOSE}); - }, + closeLimitsEditor(dispatch) { + dispatch({ type: actionTypes.CLOSE }); + }, - createChoiceObject(value, optionsList) { - let option = optionsList.find(function(item) { return item.enum === value; }); - if (!option) { - return { - choice: optionInputOther.OTHER, - other: value - }; - } - else { - return { - choice: value, - other: '' - }; - } - } + createChoiceObject(value, optionsList) { + let option = optionsList.find(function(item) { + return item.enum === value; + }); + if (!option) { + return { + choice: optionInputOther.OTHER, + other: value + }; + } else { + return { + choice: value, + other: '' + }; + } + } }; export default LimitEditorActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js index 9829e696c3..a916b9594c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorConstants.js @@ -3,62 +3,61 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; // import InputOptions, {other as optionInputOther} from 'nfvo-components/input/inputOptions/InputOptions.jsx'; export const actionTypes = keyMirror({ - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, + OPEN: null, + CLOSE: null, + DATA_CHANGED: null }); export const LIMITS_FORM_NAME = 'LIMITSFORM'; export const selectValues = { - METRIC: [ - {enum: '', title: i18n('please select…')}, - {enum: 'BWTH', title: 'BWTH'}, - {enum: 'Country', title: 'Country'}, - {enum: 'Session', title: 'Session'}, - {enum: 'LoB', title: 'LoB'}, - {enum: 'Site', title: 'Site'}, - {enum: 'Usage', title: 'Usage'} - ], - UNIT: [ - {enum: '', title: i18n('please select…')}, - {enum: 'trunk', title: 'Trunks'}, - {enum: 'user', title: 'Users'}, - {enum: 'subscriber', title: 'Subscribers'}, - {enum: 'session', title: 'Sessions'}, - {enum: 'tenant', title: 'Tenants'}, - {enum: 'token', title: 'Tokens'}, - {enum: 'seats', title: 'Seats'}, - {enum: 'TB', title: 'TB'}, - {enum: 'GB', title: 'GB'}, - {enum: 'MB', title: 'MB'} - ], - AGGREGATION_FUNCTION: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Peak', title: 'Peak'}, - {enum: 'Average', title: 'Average'} - ], - TIME: [ - {enum: '', title: i18n('please select…')}, - {enum: 'Day', title: 'Day'}, - {enum: 'Month', title: 'Month'}, - {enum: 'Hour', title: 'Hour'}, - {enum: 'Minute', title: 'Minute'}, - {enum: 'Second', title: 'Second'}, - {enum: 'Milli-Second', title: 'Milli-Second'} - ] - + METRIC: [ + { enum: '', title: i18n('please select…') }, + { enum: 'BWTH', title: 'BWTH' }, + { enum: 'Country', title: 'Country' }, + { enum: 'Session', title: 'Session' }, + { enum: 'LoB', title: 'LoB' }, + { enum: 'Site', title: 'Site' }, + { enum: 'Usage', title: 'Usage' } + ], + UNIT: [ + { enum: '', title: i18n('please select…') }, + { enum: 'trunk', title: 'Trunks' }, + { enum: 'user', title: 'Users' }, + { enum: 'subscriber', title: 'Subscribers' }, + { enum: 'session', title: 'Sessions' }, + { enum: 'tenant', title: 'Tenants' }, + { enum: 'token', title: 'Tokens' }, + { enum: 'seats', title: 'Seats' }, + { enum: 'TB', title: 'TB' }, + { enum: 'GB', title: 'GB' }, + { enum: 'MB', title: 'MB' } + ], + AGGREGATION_FUNCTION: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Peak', title: 'Peak' }, + { enum: 'Average', title: 'Average' } + ], + TIME: [ + { enum: '', title: i18n('please select…') }, + { enum: 'Day', title: 'Day' }, + { enum: 'Month', title: 'Month' }, + { enum: 'Hour', title: 'Hour' }, + { enum: 'Minute', title: 'Minute' }, + { enum: 'Second', title: 'Second' }, + { enum: 'Milli-Second', title: 'Milli-Second' } + ] }; export const limitType = { - SERVICE_PROVIDER: 'ServiceProvider', - VENDOR: 'Vendor' + SERVICE_PROVIDER: 'ServiceProvider', + VENDOR: 'Vendor' }; export const defaultState = { - LIMITS_EDITOR_DATA: { - metric: {choice: '', other: ''}, - } + LIMITS_EDITOR_DATA: { + metric: { choice: '', other: '' } + } }; export const NEW_LIMIT_TEMP_ID = 'NEW_LIMIT_TEMP_ID'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js index 99d94a09cc..a0c3b0b1b1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitEditorReducer.js @@ -14,58 +14,73 @@ * permissions and limitations under the License. */ -import {actionTypes, LIMITS_FORM_NAME, defaultState} from './LimitEditorConstants.js'; -import {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { + actionTypes, + LIMITS_FORM_NAME, + defaultState +} from './LimitEditorConstants.js'; +import { other as optionInputOther } from 'nfvo-components/input/validation/InputOptions.jsx'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.OPEN: - return { - ...state, - data: action.limitItem ? {...action.limitItem} : defaultState.LIMITS_EDITOR_DATA, - formReady: null, - formName: LIMITS_FORM_NAME, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}] - }, - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - 'metric' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'requiredChoiceWithOther', data: optionInputOther.OTHER}] - }, - 'value' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - 'unit' : { - isValid: true, - errorText: '', - validations: [] - }, - 'aggregationFunction' : { - isValid: true, - errorText: '', - validations: [] - }, - 'time' : { - isValid: true, - errorText: '', - validations: [] - } - } - }; - case actionTypes.CLOSE: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.OPEN: + return { + ...state, + data: action.limitItem + ? { ...action.limitItem } + : defaultState.LIMITS_EDITOR_DATA, + formReady: null, + formName: LIMITS_FORM_NAME, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }] + }, + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + metric: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { + type: 'requiredChoiceWithOther', + data: optionInputOther.OTHER + } + ] + }, + value: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + unit: { + isValid: true, + errorText: '', + validations: [] + }, + aggregationFunction: { + isValid: true, + errorText: '', + validations: [] + }, + time: { + isValid: true, + errorText: '', + validations: [] + } + } + }; + case actionTypes.CLOSE: + return {}; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx index 4841d0335c..2667560935 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/Limits.jsx @@ -18,99 +18,157 @@ 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 LimitEditor from './LimitEditor.js'; -import {NEW_LIMIT_TEMP_ID, selectValues} from './LimitEditorConstants.js'; +import { NEW_LIMIT_TEMP_ID, selectValues } from './LimitEditorConstants.js'; -const LimitItem = ({isReadOnlyMode, limit, onDelete, onSelect}) => { - const {name, description, value, metric, aggregationFunction = '', time = ''} = limit; - const timeLabel = time ? `per ${time}` : ''; - let metricOption = selectValues.METRIC.find(item => item.enum === metric); - metricOption = metricOption ? metricOption.title : metric; +const LimitItem = ({ isReadOnlyMode, limit, onDelete, onSelect }) => { + const { + name, + description, + value, + metric, + aggregationFunction = '', + time = '' + } = limit; + const timeLabel = time ? `per ${time}` : ''; + let metricOption = selectValues.METRIC.find(item => item.enum === metric); + metricOption = metricOption ? metricOption.title : metric; - return ( - <ListEditorItemView - onDelete={onDelete} - onSelect={onSelect} - isReadOnlyMode={isReadOnlyMode}> - <div className='list-editor-item-view-field limit-name'> - <div className='text name'>{name}</div> - </div> + return ( + <ListEditorItemView + onDelete={onDelete} + onSelect={onSelect} + isReadOnlyMode={isReadOnlyMode}> + <div className="list-editor-item-view-field limit-name"> + <div className="text name">{name}</div> + </div> - <div className='list-editor-item-view-field limit-description'> - <div className='text description'>{description}</div> - </div> + <div className="list-editor-item-view-field limit-description"> + <div className="text description">{description}</div> + </div> - <div className='list-editor-item-view-field limit-metric-details'> - <div className='text description'>{`${metricOption} ${value} ${aggregationFunction} ${timeLabel}`}</div> - </div> - </ListEditorItemView> - ); + <div className="list-editor-item-view-field limit-metric-details"> + <div className="text description">{`${metricOption} ${value} ${aggregationFunction} ${timeLabel}`}</div> + </div> + </ListEditorItemView> + ); }; class Limits extends React.Component { + state = { + localFilter: '' + }; + render() { + const { + isReadOnlyMode = false, + limitEditor, + limitsList = [], + onCloseLimitEditor, + selectedLimit + } = this.props; + let limitsNames = {}; + for (let i = 0; i < limitsList.length; i++) { + limitsNames[limitsList[i].name.toLowerCase()] = limitsList[i].id; + } + return ( + <div className="license-model-limits-view"> + <ListEditorView isReadOnlyMode={isReadOnlyMode}> + {this.props.selectedLimit === NEW_LIMIT_TEMP_ID && + limitEditor.data && ( + <LimitEditor + limitsNames={limitsNames} + onCancel={onCloseLimitEditor} + onSubmit={() => this.submit()} + isReadOnlyMode={isReadOnlyMode} + /> + )} + {limitsList.length === 0 && + !limitEditor.data && ( + <div className="no-limits-text"> + {i18n('There are no limits')} + </div> + )} + {limitsList.map(limit => ( + <div key={limit.id} className="limit-item-wrapper"> + <LimitItem + onDelete={() => this.deleteLimit(limit)} + onSelect={ + selectedLimit + ? undefined + : () => this.props.onSelectLimit(limit) + } + clickable={!selectedLimit} + isReadOnlyMode={isReadOnlyMode} + limit={limit} + /> + {limit.id === selectedLimit && + limitEditor.data && ( + <LimitEditor + limitsNames={limitsNames} + onCancel={onCloseLimitEditor} + onSubmit={() => this.submit()} + isReadOnlyMode={isReadOnlyMode} + /> + )} + </div> + ))} + </ListEditorView> + </div> + ); + } - state = { - localFilter: '' - }; + submit() { + let { + onSubmit, + onCloseLimitEditor, + parent, + limitEditor, + licenseModelId, + version, + limitType + } = this.props; + onSubmit( + { type: limitType, ...limitEditor.data }, + parent, + licenseModelId, + version + ).then(() => onCloseLimitEditor()); + } - render() { - const {isReadOnlyMode = false, limitEditor, limitsList = [], onCloseLimitEditor, selectedLimit} = this.props; - let limitsNames = {}; - for (let i = 0; i < limitsList.length; i++) { - limitsNames[limitsList[i].name.toLowerCase()] = limitsList[i].id; - } - return ( - <div className='license-model-limits-view'> - <ListEditorView isReadOnlyMode={isReadOnlyMode}> - {this.props.selectedLimit === NEW_LIMIT_TEMP_ID && limitEditor.data && - <LimitEditor limitsNames={limitsNames} onCancel={onCloseLimitEditor} onSubmit={ () => this.submit()} isReadOnlyMode={isReadOnlyMode}/> - } - {limitsList.length === 0 && !limitEditor.data && <div className='no-limits-text'>{i18n('There are no limits')}</div>} - {limitsList.map(limit => - <div key={limit.id} className='limit-item-wrapper'> - <LimitItem - onDelete={() => this.deleteLimit(limit)} - onSelect={selectedLimit ? undefined : () => this.props.onSelectLimit(limit)} - clickable={!selectedLimit} - isReadOnlyMode={isReadOnlyMode} - limit={limit}/> - {limit.id === selectedLimit && limitEditor.data && - <LimitEditor - limitsNames={limitsNames} - onCancel={onCloseLimitEditor} - onSubmit={ () => this.submit()} - isReadOnlyMode={isReadOnlyMode} /> - } - </div> )} - </ListEditorView> + deleteLimit(limit) { + let { + onDelete, + parent, + licenseModelId, + version, + onCloseLimitEditor, + selectedLimit + } = this.props; + onDelete({ + limit, + parent, + licenseModelId, + version, + onCloseLimitEditor, + selectedLimit + }); + } - </div> - ); - } - - submit() { - let {onSubmit, onCloseLimitEditor, parent, limitEditor, licenseModelId, version, limitType} = this.props; - onSubmit({type: limitType, ...limitEditor.data}, parent, licenseModelId, version).then(() => onCloseLimitEditor()); - } - - deleteLimit(limit) { - let {onDelete, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit} = this.props; - onDelete({limit, parent, licenseModelId, version, onCloseLimitEditor, selectedLimit}); - } - - filterList() { - let {limitsList = []} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return limitsList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return limitsList; - } - } + filterList() { + let { limitsList = [] } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return limitsList.filter(({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + }); + } else { + return limitsList; + } + } } export default Limits; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js index 1b8ecb9d94..679f9975e5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/limits/LimitsServer.js @@ -16,31 +16,29 @@ // items/{itemId}/users -let list = [ - -]; +let list = []; export default { - fetch() { - return Promise.resolve({ - listCount: list.length, - results: list - }); - }, + fetch() { + return Promise.resolve({ + listCount: list.length, + results: list + }); + }, - put(url, payload) { - // let {removedUsers, addedUsers} = payload; - // users = users.filter(user => !removedUsers.map(user => user.userId).includes(user.userId)).concat(addedUsers); - payload.id = Math.random() * (1000 - 1) + 1; - list.push(payload); - return Promise.resolve(); - }, + put(url, payload) { + // let {removedUsers, addedUsers} = payload; + // users = users.filter(user => !removedUsers.map(user => user.userId).includes(user.userId)).concat(addedUsers); + payload.id = Math.random() * (1000 - 1) + 1; + list.push(payload); + return Promise.resolve(); + }, - destroy(url) { - const parts = url.split('/'); - const id = parts[parts.length - 1]; - let newList = list.filter(item => item.id !== id); - list = newList; - return Promise.resolve(); - } -};
\ No newline at end of file + destroy(url) { + const parts = url.split('/'); + const id = parts[parts.length - 1]; + let newList = list.filter(item => item.id !== id); + list = newList; + return Promise.resolve(); + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverview.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverview.js index 54941aaaf0..2b10e426d1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverview.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverview.js @@ -13,161 +13,214 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseModelActionHelper.js'; import LicenseModelOverviewView from './LicenseModelOverviewView.jsx'; -import {overviewEditorHeaders, selectedButton} from './LicenseModelOverviewConstants.js'; +import { + overviewEditorHeaders, + selectedButton +} from './LicenseModelOverviewConstants.js'; import licenseModelOverviewActionHelper from './licenseModelOverviewActionHelper.js'; export const mapStateToProps = ({ - licenseModel: { - licenseModelEditor, - entitlementPool, - licenseAgreement, - featureGroup, - licenseKeyGroup, - licenseModelOverview - } + licenseModel: { + licenseModelEditor, + entitlementPool, + licenseAgreement, + featureGroup, + licenseKeyGroup, + licenseModelOverview + } }) => { - - let modalHeader, licensingDataList; - let isDisplayModal = false; - - const reduceLicenseKeyGroups = (accum, licenseKeyGroupId) => { - let curLicenseKeyGroup = licenseKeyGroup.licenseKeyGroupsList.find(item => {return item.id === licenseKeyGroupId;}); - if (curLicenseKeyGroup) { - accum.push({ - ...curLicenseKeyGroup, - itemType: overviewEditorHeaders.LICENSE_KEY_GROUP - }); - } - return accum; - }; - - const reduceEntitlementPools = (accum, entitlementPoolId) => { - let curEntitlementPool = entitlementPool.entitlementPoolsList.find(item => {return item.id === entitlementPoolId;}); - if (curEntitlementPool) { - accum.push ({ - ...curEntitlementPool, - itemType: overviewEditorHeaders.ENTITLEMENT_POOL - }); - } - return accum; - }; - - const reduceFeatureGroups = (accum, featureGroupId) => { - let curFeatureGroup = featureGroup.featureGroupsList.find(item => {return item.id === featureGroupId;}); - if (curFeatureGroup) { - let {entitlementPoolsIds = [], licenseKeyGroupsIds = []} = curFeatureGroup; - accum.push({ - ...curFeatureGroup, - itemType: overviewEditorHeaders.FEATURE_GROUP, - children: [ - ...entitlementPoolsIds.length ? entitlementPoolsIds.reduce(reduceEntitlementPools, []) : [], - ...licenseKeyGroupsIds.length ? licenseKeyGroupsIds.reduce(reduceLicenseKeyGroups, []) : [] - ] - }); - } - return accum; - }; - - - const checkEP = (accum, elem) => { - if (!elem.referencingFeatureGroups || !elem.referencingFeatureGroups.length) { - accum.push({ - ...elem, - itemType: overviewEditorHeaders.ENTITLEMENT_POOL - }); - } - return accum; - }; - - const checkLG = (accum, elem) => { - if (!elem.referencingFeatureGroups || !elem.referencingFeatureGroups.length) { - accum.push({ - ...elem, - itemType: overviewEditorHeaders.LICENSE_KEY_GROUP - }); - } - return accum; - }; - - const checkFG = (accum, elem) => { - if (!elem.referencingLicenseAgreements || !elem.referencingLicenseAgreements.length) { - let {entitlementPoolsIds = [], licenseKeyGroupsIds = []} = elem; - accum.push({ - ...elem, - itemType: overviewEditorHeaders.FEATURE_GROUP, - - children: [ - ...entitlementPoolsIds.length ? entitlementPoolsIds.reduce(reduceEntitlementPools, []) : [], - ...licenseKeyGroupsIds.length ? licenseKeyGroupsIds.reduce(reduceLicenseKeyGroups, []) : [] - ] - - }); - } - return accum; - }; - - - - const mapLicenseAgreementData = licenseAgreement => { - let {featureGroupsIds = []} = licenseAgreement; - return { - ...licenseAgreement, - itemType: overviewEditorHeaders.LICENSE_AGREEMENT, - children: featureGroupsIds.length ? featureGroupsIds.reduce(reduceFeatureGroups, []) : [] - }; - }; - - if (entitlementPool.entitlementPoolEditor && entitlementPool.entitlementPoolEditor.data) { - modalHeader = overviewEditorHeaders.ENTITLEMENT_POOL; - isDisplayModal = true; - }else - if (licenseAgreement.licenseAgreementEditor && licenseAgreement.licenseAgreementEditor.data) { - modalHeader = overviewEditorHeaders.LICENSE_AGREEMENT; - isDisplayModal = true; - }else - if (featureGroup.featureGroupEditor && featureGroup.featureGroupEditor.data) { - modalHeader = overviewEditorHeaders.FEATURE_GROUP; - isDisplayModal = true; - }else - if (licenseKeyGroup.licenseKeyGroupsEditor && licenseKeyGroup.licenseKeyGroupsEditor.data) { - modalHeader = overviewEditorHeaders.LICENSE_KEY_GROUP; - isDisplayModal = true; - } - - let orphanDataList = [ - ...featureGroup.featureGroupsList.reduce(checkFG, []), - ...entitlementPool.entitlementPoolsList.reduce(checkEP, []), - ...licenseKeyGroup.licenseKeyGroupsList.reduce(checkLG, []) - ]; - - licensingDataList = licenseAgreement.licenseAgreementList && licenseAgreement.licenseAgreementList.length ? licenseAgreement.licenseAgreementList.map(mapLicenseAgreementData) : []; - let selectedTab = licenseModelOverview.selectedTab; - // on first entry, we will decide what tab to open depending on data. if there are no connections, we will open the orphans - if (selectedTab === null) { - selectedTab = (licensingDataList.length) ? selectedButton.VLM_LIST_VIEW : selectedButton.NOT_IN_USE; - } - - return { - isDisplayModal, - modalHeader, - licenseModelId: licenseModelEditor.data.id, - version: licenseModelEditor.data.version, - licensingDataList, - orphanDataList, - selectedTab - }; + let modalHeader, licensingDataList; + let isDisplayModal = false; + + const reduceLicenseKeyGroups = (accum, licenseKeyGroupId) => { + let curLicenseKeyGroup = licenseKeyGroup.licenseKeyGroupsList.find( + item => { + return item.id === licenseKeyGroupId; + } + ); + if (curLicenseKeyGroup) { + accum.push({ + ...curLicenseKeyGroup, + itemType: overviewEditorHeaders.LICENSE_KEY_GROUP + }); + } + return accum; + }; + + const reduceEntitlementPools = (accum, entitlementPoolId) => { + let curEntitlementPool = entitlementPool.entitlementPoolsList.find( + item => { + return item.id === entitlementPoolId; + } + ); + if (curEntitlementPool) { + accum.push({ + ...curEntitlementPool, + itemType: overviewEditorHeaders.ENTITLEMENT_POOL + }); + } + return accum; + }; + + const reduceFeatureGroups = (accum, featureGroupId) => { + let curFeatureGroup = featureGroup.featureGroupsList.find(item => { + return item.id === featureGroupId; + }); + if (curFeatureGroup) { + let { + entitlementPoolsIds = [], + licenseKeyGroupsIds = [] + } = curFeatureGroup; + accum.push({ + ...curFeatureGroup, + itemType: overviewEditorHeaders.FEATURE_GROUP, + children: [ + ...(entitlementPoolsIds.length + ? entitlementPoolsIds.reduce(reduceEntitlementPools, []) + : []), + ...(licenseKeyGroupsIds.length + ? licenseKeyGroupsIds.reduce(reduceLicenseKeyGroups, []) + : []) + ] + }); + } + return accum; + }; + + const checkEP = (accum, elem) => { + if ( + !elem.referencingFeatureGroups || + !elem.referencingFeatureGroups.length + ) { + accum.push({ + ...elem, + itemType: overviewEditorHeaders.ENTITLEMENT_POOL + }); + } + return accum; + }; + + const checkLG = (accum, elem) => { + if ( + !elem.referencingFeatureGroups || + !elem.referencingFeatureGroups.length + ) { + accum.push({ + ...elem, + itemType: overviewEditorHeaders.LICENSE_KEY_GROUP + }); + } + return accum; + }; + + const checkFG = (accum, elem) => { + if ( + !elem.referencingLicenseAgreements || + !elem.referencingLicenseAgreements.length + ) { + let { entitlementPoolsIds = [], licenseKeyGroupsIds = [] } = elem; + accum.push({ + ...elem, + itemType: overviewEditorHeaders.FEATURE_GROUP, + + children: [ + ...(entitlementPoolsIds.length + ? entitlementPoolsIds.reduce(reduceEntitlementPools, []) + : []), + ...(licenseKeyGroupsIds.length + ? licenseKeyGroupsIds.reduce(reduceLicenseKeyGroups, []) + : []) + ] + }); + } + return accum; + }; + + const mapLicenseAgreementData = licenseAgreement => { + let { featureGroupsIds = [] } = licenseAgreement; + return { + ...licenseAgreement, + itemType: overviewEditorHeaders.LICENSE_AGREEMENT, + children: featureGroupsIds.length + ? featureGroupsIds.reduce(reduceFeatureGroups, []) + : [] + }; + }; + + if ( + entitlementPool.entitlementPoolEditor && + entitlementPool.entitlementPoolEditor.data + ) { + modalHeader = overviewEditorHeaders.ENTITLEMENT_POOL; + isDisplayModal = true; + } else if ( + licenseAgreement.licenseAgreementEditor && + licenseAgreement.licenseAgreementEditor.data + ) { + modalHeader = overviewEditorHeaders.LICENSE_AGREEMENT; + isDisplayModal = true; + } else if ( + featureGroup.featureGroupEditor && + featureGroup.featureGroupEditor.data + ) { + modalHeader = overviewEditorHeaders.FEATURE_GROUP; + isDisplayModal = true; + } else if ( + licenseKeyGroup.licenseKeyGroupsEditor && + licenseKeyGroup.licenseKeyGroupsEditor.data + ) { + modalHeader = overviewEditorHeaders.LICENSE_KEY_GROUP; + isDisplayModal = true; + } + + let orphanDataList = [ + ...featureGroup.featureGroupsList.reduce(checkFG, []), + ...entitlementPool.entitlementPoolsList.reduce(checkEP, []), + ...licenseKeyGroup.licenseKeyGroupsList.reduce(checkLG, []) + ]; + + licensingDataList = + licenseAgreement.licenseAgreementList && + licenseAgreement.licenseAgreementList.length + ? licenseAgreement.licenseAgreementList.map(mapLicenseAgreementData) + : []; + let selectedTab = licenseModelOverview.selectedTab; + // on first entry, we will decide what tab to open depending on data. if there are no connections, we will open the orphans + if (selectedTab === null) { + selectedTab = licensingDataList.length + ? selectedButton.VLM_LIST_VIEW + : selectedButton.NOT_IN_USE; + } + + return { + isDisplayModal, + modalHeader, + licenseModelId: licenseModelEditor.data.id, + version: licenseModelEditor.data.version, + licensingDataList, + orphanDataList, + selectedTab + }; }; -const mapActionsToProps = (dispatch, {licenseModelId}) => { - return { - onCallVCAction: action => { - LicenseModelActionHelper.performVCAction(dispatch, {licenseModelId, action}); - }, - onTabSelect: (buttonTab) => licenseModelOverviewActionHelper.selectVLMListView(dispatch,{buttonTab}) - }; +const mapActionsToProps = (dispatch, { licenseModelId }) => { + return { + onCallVCAction: action => { + LicenseModelActionHelper.performVCAction(dispatch, { + licenseModelId, + action + }); + }, + onTabSelect: buttonTab => + licenseModelOverviewActionHelper.selectVLMListView(dispatch, { + buttonTab + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(LicenseModelOverviewView); +export default connect(mapStateToProps, mapActionsToProps)( + LicenseModelOverviewView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js index 56b23384a7..b05da582f4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewConstants.js @@ -16,27 +16,27 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const overviewItems = keyMirror({ - LICENSE_AGREEMENTS: 'License Agreements', - FEATURE_GROUPS: 'Feature Groups', - ENTITLEMENT_POOLS: 'Entitlement Pools', - LICENSE_KEY_GROUPS: 'License Key Groups' + LICENSE_AGREEMENTS: 'License Agreements', + FEATURE_GROUPS: 'Feature Groups', + ENTITLEMENT_POOLS: 'Entitlement Pools', + LICENSE_KEY_GROUPS: 'License Key Groups' }); export const overviewEditorHeaders = keyMirror({ - LICENSE_AGREEMENT: 'License Agreement', - FEATURE_GROUP: 'Feature Group', - ENTITLEMENT_POOL: 'Entitlement Pool', - LICENSE_KEY_GROUP: 'License Key Group' + LICENSE_AGREEMENT: 'License Agreement', + FEATURE_GROUP: 'Feature Group', + ENTITLEMENT_POOL: 'Entitlement Pool', + LICENSE_KEY_GROUP: 'License Key Group' }); export const actionTypes = keyMirror({ - LICENSE_MODEL_OVERVIEW_TAB_SELECTED: null, - LM_DATA_CHANGED: null + LICENSE_MODEL_OVERVIEW_TAB_SELECTED: null, + LM_DATA_CHANGED: null }); export const selectedButton = { - VLM_LIST_VIEW: 'VLM_LIST_VIEW', - NOT_IN_USE: 'NOT_IN_USE' + VLM_LIST_VIEW: 'VLM_LIST_VIEW', + NOT_IN_USE: 'NOT_IN_USE' }; export const VLM_DESCRIPTION_FORM = 'VLMDEWSCRIPTIONFORM'; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewView.jsx index 39109af9a3..6899360597 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/LicenseModelOverviewView.jsx @@ -23,87 +23,137 @@ import EntitlementPoolsEditor from '../entitlementPools/EntitlementPoolsEditor.j import FeatureGroupEditor from '../featureGroups/FeatureGroupEditor.js'; import LicenseAgreementEditor from '../licenseAgreement/LicenseAgreementEditor.js'; import LicenseKeyGroupsEditor from '../licenseKeyGroups/LicenseKeyGroupsEditor.js'; -import {overviewEditorHeaders, selectedButton} from './LicenseModelOverviewConstants.js'; +import { + overviewEditorHeaders, + selectedButton +} from './LicenseModelOverviewConstants.js'; import SummaryView from './SummaryView.jsx'; import VLMListView from './VLMListView.jsx'; import ListButtons from './summary/ListButtons.jsx'; - -const setModalClassName = (modalHeader) => { - switch (modalHeader) { - case overviewEditorHeaders.ENTITLEMENT_POOL: - return 'entitlement-pools-modal'; - case overviewEditorHeaders.LICENSE_AGREEMENT: - return 'license-agreement-modal'; - case overviewEditorHeaders.FEATURE_GROUP: - return 'feature-group-modal'; - case overviewEditorHeaders.LICENSE_KEY_GROUP: - return 'license-key-groups-modal'; - default: - return ''; - } +const setModalClassName = modalHeader => { + switch (modalHeader) { + case overviewEditorHeaders.ENTITLEMENT_POOL: + return 'entitlement-pools-modal'; + case overviewEditorHeaders.LICENSE_AGREEMENT: + return 'license-agreement-modal'; + case overviewEditorHeaders.FEATURE_GROUP: + return 'feature-group-modal'; + case overviewEditorHeaders.LICENSE_KEY_GROUP: + return 'license-key-groups-modal'; + default: + return ''; + } }; class LicenseModelOverviewView extends React.Component { + static propTypes = { + isDisplayModal: PropTypes.bool, + isReadOnlyMode: PropTypes.bool, + licenseModelId: PropTypes.string, + licensingDataList: PropTypes.array, + orphanDataList: PropTypes.array, + modalHeader: PropTypes.string, + selectedTab: PropTypes.string, + onTabSelect: PropTypes.func, + onCallVCAction: PropTypes.func, + onClose: PropTypes.func + }; - static propTypes = { - isDisplayModal: PropTypes.bool, - isReadOnlyMode: PropTypes.bool, - licenseModelId: PropTypes.string, - licensingDataList: PropTypes.array, - orphanDataList: PropTypes.array, - modalHeader: PropTypes.string, - selectedTab: PropTypes.string, - onTabSelect: PropTypes.func, - onCallVCAction: PropTypes.func, - onClose: PropTypes.func - }; - - render() { - let {isDisplayModal, modalHeader, licensingDataList, selectedTab, onTabSelect, orphanDataList, isReadOnlyMode} = this.props; - let selectedInUse = selectedTab !== selectedButton.NOT_IN_USE; - let dataList = selectedInUse ? licensingDataList : orphanDataList; - return( - <div className='license-model-overview'> - <SummaryView isReadOnlyMode={isReadOnlyMode}/> - <div className={classNames('overview-list-section ', !selectedInUse ? 'overview-list-orphans' : '' )}> - <div className='vlm-list-tab-panel'> - <ListButtons onTabSelect={onTabSelect} - selectedTab={selectedTab} - hasOrphans={orphanDataList.length > 0} - hasLicensing={licensingDataList.length > 0}/> - </div> - <VLMListView licensingDataList={dataList} showInUse={selectedInUse}/> - </div> - { - isDisplayModal && - <Modal show={isDisplayModal} bsSize='large' animation={true} className={classNames('onborading-modal license-model-modal', setModalClassName(modalHeader))}> - <Modal.Header> - <Modal.Title>{`${i18n('Create New ')}${i18n(modalHeader)}`}</Modal.Title> - </Modal.Header> - <Modal.Body> - {this.renderModalBody(modalHeader)} - </Modal.Body> - </Modal> - } - </div> - ); - } + render() { + let { + isDisplayModal, + modalHeader, + licensingDataList, + selectedTab, + onTabSelect, + orphanDataList, + isReadOnlyMode + } = this.props; + let selectedInUse = selectedTab !== selectedButton.NOT_IN_USE; + let dataList = selectedInUse ? licensingDataList : orphanDataList; + return ( + <div className="license-model-overview"> + <SummaryView isReadOnlyMode={isReadOnlyMode} /> + <div + className={classNames( + 'overview-list-section ', + !selectedInUse ? 'overview-list-orphans' : '' + )}> + <div className="vlm-list-tab-panel"> + <ListButtons + onTabSelect={onTabSelect} + selectedTab={selectedTab} + hasOrphans={orphanDataList.length > 0} + hasLicensing={licensingDataList.length > 0} + /> + </div> + <VLMListView + licensingDataList={dataList} + showInUse={selectedInUse} + /> + </div> + {isDisplayModal && ( + <Modal + show={isDisplayModal} + bsSize="large" + animation={true} + className={classNames( + 'onborading-modal license-model-modal', + setModalClassName(modalHeader) + )}> + <Modal.Header> + <Modal.Title>{`${i18n('Create New ')}${i18n( + modalHeader + )}`}</Modal.Title> + </Modal.Header> + <Modal.Body> + {this.renderModalBody(modalHeader)} + </Modal.Body> + </Modal> + )} + </div> + ); + } - renderModalBody(modalHeader) { - let {licenseModelId, version, isReadOnlyMode} = this.props; - switch (modalHeader) { - case overviewEditorHeaders.ENTITLEMENT_POOL: - return <EntitlementPoolsEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/>; - case overviewEditorHeaders.LICENSE_AGREEMENT: - return <LicenseAgreementEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/>; - case overviewEditorHeaders.FEATURE_GROUP: - return <FeatureGroupEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/>; - case overviewEditorHeaders.LICENSE_KEY_GROUP: - return <LicenseKeyGroupsEditor version={version} licenseModelId={licenseModelId} isReadOnlyMode={isReadOnlyMode}/>; - } - } + renderModalBody(modalHeader) { + let { licenseModelId, version, isReadOnlyMode } = this.props; + switch (modalHeader) { + case overviewEditorHeaders.ENTITLEMENT_POOL: + return ( + <EntitlementPoolsEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + ); + case overviewEditorHeaders.LICENSE_AGREEMENT: + return ( + <LicenseAgreementEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + ); + case overviewEditorHeaders.FEATURE_GROUP: + return ( + <FeatureGroupEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + ); + case overviewEditorHeaders.LICENSE_KEY_GROUP: + return ( + <LicenseKeyGroupsEditor + version={version} + licenseModelId={licenseModelId} + isReadOnlyMode={isReadOnlyMode} + /> + ); + } + } } -export default LicenseModelOverviewView; +export default LicenseModelOverviewView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/SummaryView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/SummaryView.jsx index 4053f14ced..f416b0a07f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/SummaryView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/SummaryView.jsx @@ -13,24 +13,24 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {default as VendorDataView} from './summary/VendorDataView.js'; -import {default as SummaryCountList} from './summary/SummaryCountList.js'; +import { default as VendorDataView } from './summary/VendorDataView.js'; +import { default as SummaryCountList } from './summary/SummaryCountList.js'; class SummaryView extends Component { - render() { - const {isReadOnlyMode} = this.props; - return( - <div className='overview-top-section'> - <div className='page-title'>{i18n('overview')}</div> - <div className='license-model-overview-top'> - <VendorDataView isReadOnlyMode={isReadOnlyMode}/> - <SummaryCountList isReadOnlyMode={isReadOnlyMode}/> - </div> - </div> - ); - } + render() { + const { isReadOnlyMode } = this.props; + return ( + <div className="overview-top-section"> + <div className="page-title">{i18n('overview')}</div> + <div className="license-model-overview-top"> + <VendorDataView isReadOnlyMode={isReadOnlyMode} /> + <SummaryCountList isReadOnlyMode={isReadOnlyMode} /> + </div> + </div> + ); + } } export default SummaryView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/VLMListView.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/VLMListView.jsx index 012bd6e158..d91960e6a3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/VLMListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/VLMListView.jsx @@ -13,114 +13,130 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; -import {Collapse} from 'react-bootstrap'; +import { Collapse } from 'react-bootstrap'; import LicenseAgreement from './listItems/LicenseAgreement.jsx'; import EntitlementPool from './listItems/EntitlementPool.jsx'; import FeatureGroup from './listItems/FeatureGroup.jsx'; import LicenseKeyGroup from './listItems/LicenseKeyGroup.jsx'; -import {overviewEditorHeaders} from './LicenseModelOverviewConstants.js'; +import { overviewEditorHeaders } from './LicenseModelOverviewConstants.js'; class VLMListView extends Component { + static propTypes = { + licensingDataList: PropTypes.array, + showInUse: PropTypes.bool + }; - static propTypes = { - licensingDataList: PropTypes.array, - showInUse: PropTypes.bool - }; + state = {}; - state = { + render() { + let { licensingDataList = [] } = this.props; + return ( + <div className="vlm-list-view"> + <div> + <ul className="vlm-list" data-test-id="vlm-list"> + {licensingDataList.map(item => + this.renderLicensingItem(item) + )} + </ul> + </div> + </div> + ); + } - }; + renderLicensingItem(item) { + switch (item.itemType) { + case overviewEditorHeaders.LICENSE_AGREEMENT: + return this.renderLicenseAgreementItem(item); + case overviewEditorHeaders.FEATURE_GROUP: + return this.renderFeatureGroupItem(item); + case overviewEditorHeaders.LICENSE_KEY_GROUP: + return this.renderLicenseKeyGroupItem(item); + case overviewEditorHeaders.ENTITLEMENT_POOL: + return this.renderEntitlementPoolItem(item); + default: + return; + } + } - render() { - let {licensingDataList = []} = this.props; - return ( - <div className='vlm-list-view'> - <div> - <ul className='vlm-list' data-test-id='vlm-list'> - {licensingDataList.map(item => this.renderLicensingItem(item))} - </ul> - </div> - </div> - ); - } + renderLicenseAgreementItem(licenseAgreement) { + return ( + <li key={licenseAgreement.id}> + <LicenseAgreement + laData={licenseAgreement} + isCollapsed={this.state[licenseAgreement.id]} + onClick={event => + this.updateCollapsable(event, licenseAgreement.id) + } + isOrphan={!this.props.showInUse} + /> + <Collapse in={this.state[licenseAgreement.id]}> + <ul> + {licenseAgreement.children && + licenseAgreement.children.map(item => + this.renderLicensingItem(item) + )} + </ul> + </Collapse> + </li> + ); + } - renderLicensingItem(item) { - switch (item.itemType) { - case overviewEditorHeaders.LICENSE_AGREEMENT : - return this.renderLicenseAgreementItem(item); - case overviewEditorHeaders.FEATURE_GROUP : - return this.renderFeatureGroupItem(item); - case overviewEditorHeaders.LICENSE_KEY_GROUP : - return this.renderLicenseKeyGroupItem(item); - case overviewEditorHeaders.ENTITLEMENT_POOL: - return this.renderEntitlementPoolItem(item); - default: - return; - } - } + renderFeatureGroupItem(featureGroup) { + const { showInUse } = this.props; + return ( + <li key={featureGroup.id}> + <FeatureGroup + fgData={featureGroup} + isCollapsed={this.state[featureGroup.id]} + onClick={event => + this.updateCollapsable(event, featureGroup.id) + } + isOrphan={!this.props.showInUse} + /> + {showInUse && ( + <Collapse in={this.state[featureGroup.id]}> + <ul> + {featureGroup.children && + featureGroup.children.map(item => + this.renderLicensingItem(item) + )} + </ul> + </Collapse> + )} + </li> + ); + } - renderLicenseAgreementItem(licenseAgreement) { - return ( - <li key={licenseAgreement.id}> - <LicenseAgreement - laData={licenseAgreement} - isCollapsed={this.state[licenseAgreement.id]} - onClick={event => this.updateCollapsable(event, licenseAgreement.id) } - isOrphan={!this.props.showInUse}/> - <Collapse in={this.state[licenseAgreement.id]}> - <ul> - {licenseAgreement.children && licenseAgreement.children.map(item => this.renderLicensingItem(item))} - </ul> - </Collapse> - </li> - ); - } + renderEntitlementPoolItem(entitlementPool) { + return ( + <li key={entitlementPool.id}> + <EntitlementPool + epData={entitlementPool} + isOrphan={!this.props.showInUse} + /> + </li> + ); + } - renderFeatureGroupItem(featureGroup) { - const {showInUse} = this.props; - return ( - <li key={featureGroup.id}> - <FeatureGroup - fgData={featureGroup} - isCollapsed={this.state[featureGroup.id]} - onClick={event=> this.updateCollapsable(event, featureGroup.id) } - isOrphan={!this.props.showInUse}/> - { - showInUse && <Collapse in={this.state[featureGroup.id]}> - <ul> - {featureGroup.children && featureGroup.children.map(item => this.renderLicensingItem(item))} + renderLicenseKeyGroupItem(licenseKeyGroup) { + return ( + <li key={licenseKeyGroup.id}> + <LicenseKeyGroup + lkgData={licenseKeyGroup} + isOrphan={!this.props.showInUse} + /> + </li> + ); + } - </ul> - </Collapse> - } - </li> - ); - } - - renderEntitlementPoolItem(entitlementPool) { - return ( - <li key={entitlementPool.id}> - <EntitlementPool epData={entitlementPool} isOrphan={!this.props.showInUse}/> - </li> - ); - } - - renderLicenseKeyGroupItem(licenseKeyGroup) { - return ( - <li key={licenseKeyGroup.id}> - <LicenseKeyGroup lkgData={licenseKeyGroup} isOrphan={!this.props.showInUse}/> - </li> - ); - } - - updateCollapsable(event, id) { - event.stopPropagation(); - let obj = {}; - obj[id] = !this.state[id]; - this.setState(obj); - } + updateCollapsable(event, id) { + event.stopPropagation(); + let obj = {}; + obj[id] = !this.state[id]; + this.setState(obj); + } } export default VLMListView; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js index af9bc22b07..0e9fca7b4a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/licenseModelOverviewActionHelper.js @@ -13,27 +13,27 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './LicenseModelOverviewConstants.js'; +import { actionTypes } from './LicenseModelOverviewConstants.js'; export default { - selectVLMListView(dispatch, {buttonTab}) { - dispatch({ - type: actionTypes.LICENSE_MODEL_OVERVIEW_TAB_SELECTED, - buttonTab - }); - }, + selectVLMListView(dispatch, { buttonTab }) { + dispatch({ + type: actionTypes.LICENSE_MODEL_OVERVIEW_TAB_SELECTED, + buttonTab + }); + }, - editDescriptionOpen(dispatch, {description}) { - dispatch({ - type: actionTypes.LM_DATA_CHANGED, - description - }); - }, + editDescriptionOpen(dispatch, { description }) { + dispatch({ + type: actionTypes.LM_DATA_CHANGED, + description + }); + }, - editDescriptionClose(dispatch) { - dispatch({ - type: actionTypes.LM_DATA_CHANGED, - description: undefined - }); - } + editDescriptionClose(dispatch) { + dispatch({ + type: actionTypes.LM_DATA_CHANGED, + description: undefined + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/EntitlementPool.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/EntitlementPool.jsx index 34d2ee6db5..60eba401c7 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/EntitlementPool.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/EntitlementPool.jsx @@ -13,33 +13,46 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {extractUnits} from '../../entitlementPools/EntitlementPoolsConstants.js'; +import { extractUnits } from '../../entitlementPools/EntitlementPoolsConstants.js'; import ArrowCol from './listItemsComponents/ArrowCol.jsx'; import ItemInfo from './listItemsComponents/ItemInfo.jsx'; import IconCol from './listItemsComponents/IconCol.jsx'; -import {AdditionalDataCol, AdditionalDataElement} from './listItemsComponents/AdditionalDataCol.jsx'; +import { + AdditionalDataCol, + AdditionalDataElement +} from './listItemsComponents/AdditionalDataCol.jsx'; class EntitlementPool extends Component { - render() { - let {epData: {name, description, thresholdValue, thresholdUnits}, isOrphan} = this.props; - return ( - <div className={`vlm-list-item vlm-list-item-ep ${isOrphan ? 'orphan-list-item' : ''}`} data-test-id='vlm-list-item-ep'> - {!isOrphan && <ArrowCol/>} - <IconCol className='ep-icon' text='EP'/> - <ItemInfo name={name} description={description}/> - <AdditionalDataCol> - {thresholdValue && <AdditionalDataElement - className='vlm-list-item-entitlement-metric' - name={i18n('Entitlement')} - value={`${thresholdValue} ${extractUnits(thresholdUnits)}`}/> - } - </AdditionalDataCol> - </div> - ); - } - + render() { + let { + epData: { name, description, thresholdValue, thresholdUnits }, + isOrphan + } = this.props; + return ( + <div + className={`vlm-list-item vlm-list-item-ep ${ + isOrphan ? 'orphan-list-item' : '' + }`} + data-test-id="vlm-list-item-ep"> + {!isOrphan && <ArrowCol />} + <IconCol className="ep-icon" text="EP" /> + <ItemInfo name={name} description={description} /> + <AdditionalDataCol> + {thresholdValue && ( + <AdditionalDataElement + className="vlm-list-item-entitlement-metric" + name={i18n('Entitlement')} + value={`${thresholdValue} ${extractUnits( + thresholdUnits + )}`} + /> + )} + </AdditionalDataCol> + </div> + ); + } } export default EntitlementPool; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/FeatureGroup.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/FeatureGroup.jsx index 6d97dea358..df1d813408 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/FeatureGroup.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/FeatureGroup.jsx @@ -13,49 +13,83 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; -import {overviewEditorHeaders} from '../LicenseModelOverviewConstants.js'; +import React, { Component } from 'react'; +import { overviewEditorHeaders } from '../LicenseModelOverviewConstants.js'; import ArrowCol from './listItemsComponents/ArrowCol.jsx'; import ItemInfo from './listItemsComponents/ItemInfo.jsx'; import IconCol from './listItemsComponents/IconCol.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {AdditionalDataCol, AdditionalDataElement} from './listItemsComponents/AdditionalDataCol.jsx'; +import { + AdditionalDataCol, + AdditionalDataElement +} from './listItemsComponents/AdditionalDataCol.jsx'; class FeatureGroup extends Component { - render() { - let {fgData: {name, manufacturerReferenceNumber, description, children = []}, isCollapsed, onClick, isOrphan} = this.props; - return ( - <div - onClick={e => onClick(e)} - className={`vlm-list-item vlm-list-item-fg ${isOrphan ? 'orphan-list-item' : ''} ${children.length && !isOrphan ? 'clickable' : ''}`} data-test-id='vlm-list-item-fg'> - {!isOrphan && <ArrowCol isCollapsed={isCollapsed} length={children.length} />} - <IconCol className='fg-icon' text='FG'/> - <ItemInfo name={name} description={description}> - <div className='children-count'> - <span className='count-value'> - {i18n('Entitlement Pools: ')} - <span data-test-id='vlm-list-ep-count-value'> - {`${children.filter(child => child.itemType === overviewEditorHeaders.ENTITLEMENT_POOL).length}`} - </span> - </span> - <span className='fg-pipeline-separator'>|</span> - <span className='count-value'> - {i18n('License Key Groups: ')} - <span data-test-id='vlm-list-lkg-count-value'> - {`${children.filter(child => child.itemType === overviewEditorHeaders.LICENSE_KEY_GROUP).length}`} - </span> - </span> - </div> - </ItemInfo> - <AdditionalDataCol> - <AdditionalDataElement - name={i18n('Manufacturer Reference Number')} - value={manufacturerReferenceNumber} - className='vlm-list-item-sku'/> - </AdditionalDataCol> - </div> - ); - } + render() { + let { + fgData: { + name, + manufacturerReferenceNumber, + description, + children = [] + }, + isCollapsed, + onClick, + isOrphan + } = this.props; + return ( + <div + onClick={e => onClick(e)} + className={`vlm-list-item vlm-list-item-fg ${ + isOrphan ? 'orphan-list-item' : '' + } ${children.length && !isOrphan ? 'clickable' : ''}`} + data-test-id="vlm-list-item-fg"> + {!isOrphan && ( + <ArrowCol + isCollapsed={isCollapsed} + length={children.length} + /> + )} + <IconCol className="fg-icon" text="FG" /> + <ItemInfo name={name} description={description}> + <div className="children-count"> + <span className="count-value"> + {i18n('Entitlement Pools: ')} + <span data-test-id="vlm-list-ep-count-value"> + {`${ + children.filter( + child => + child.itemType === + overviewEditorHeaders.ENTITLEMENT_POOL + ).length + }`} + </span> + </span> + <span className="fg-pipeline-separator">|</span> + <span className="count-value"> + {i18n('License Key Groups: ')} + <span data-test-id="vlm-list-lkg-count-value"> + {`${ + children.filter( + child => + child.itemType === + overviewEditorHeaders.LICENSE_KEY_GROUP + ).length + }`} + </span> + </span> + </div> + </ItemInfo> + <AdditionalDataCol> + <AdditionalDataElement + name={i18n('Manufacturer Reference Number')} + value={manufacturerReferenceNumber} + className="vlm-list-item-sku" + /> + </AdditionalDataCol> + </div> + ); + } } export default FeatureGroup; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseAgreement.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseAgreement.jsx index dfbbe20d69..b409776c27 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseAgreement.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseAgreement.jsx @@ -13,44 +13,73 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import InputOptions, {other as optionInputOther} from 'nfvo-components/input/validation/InputOptions.jsx'; -import {optionsInputValues} from '../../licenseAgreement/LicenseAgreementConstants.js'; +import InputOptions, { + other as optionInputOther +} from 'nfvo-components/input/validation/InputOptions.jsx'; +import { optionsInputValues } from '../../licenseAgreement/LicenseAgreementConstants.js'; import ArrowCol from './listItemsComponents/ArrowCol.jsx'; import ItemInfo from './listItemsComponents/ItemInfo.jsx'; import IconCol from './listItemsComponents/IconCol.jsx'; -import {AdditionalDataCol, AdditionalDataElement} from './listItemsComponents/AdditionalDataCol.jsx'; +import { + AdditionalDataCol, + AdditionalDataElement +} from './listItemsComponents/AdditionalDataCol.jsx'; class LicenseAgreement extends Component { - render() { - let {laData: {name, description, licenseTerm, children = []}, isCollapsed, onClick, isOrphan} = this.props; - return ( - <div - onClick={e => onClick(e)} - className={`vlm-list-item vlm-list-item-la ${isOrphan ? 'orphan-list-item' : ''} ${children.length && !isOrphan ? 'clickable' : ''} `} - data-test-id='vlm-list-la-item'> - {!isOrphan && <ArrowCol isCollapsed={isCollapsed} length={children.length} />} - <IconCol className='la-icon' text='LA'/> - <ItemInfo name={name} description={description}> - <div className='children-count'> - <span className='count-value'>{i18n('Feature Groups: ')}<span data-test-id='vlm-list-fg-count-value'>{`${children.length}`}</span></span> - </div> - </ItemInfo> - <AdditionalDataCol> - <AdditionalDataElement - name={i18n('License Model Type')} - value={this.extractValue(licenseTerm)}/> - </AdditionalDataCol> - </div> - ); - } + render() { + let { + laData: { name, description, licenseTerm, children = [] }, + isCollapsed, + onClick, + isOrphan + } = this.props; + return ( + <div + onClick={e => onClick(e)} + className={`vlm-list-item vlm-list-item-la ${ + isOrphan ? 'orphan-list-item' : '' + } ${children.length && !isOrphan ? 'clickable' : ''} `} + data-test-id="vlm-list-la-item"> + {!isOrphan && ( + <ArrowCol + isCollapsed={isCollapsed} + length={children.length} + /> + )} + <IconCol className="la-icon" text="LA" /> + <ItemInfo name={name} description={description}> + <div className="children-count"> + <span className="count-value"> + {i18n('Feature Groups: ')} + <span data-test-id="vlm-list-fg-count-value">{`${ + children.length + }`}</span> + </span> + </div> + </ItemInfo> + <AdditionalDataCol> + <AdditionalDataElement + name={i18n('License Model Type')} + value={this.extractValue(licenseTerm)} + /> + </AdditionalDataCol> + </div> + ); + } - extractValue(item) { - if (item === undefined) {return '';} //TODO fix it later + extractValue(item) { + if (item === undefined) { + return ''; + } //TODO fix it later - return item ? item.choice === optionInputOther.OTHER ? item.other : InputOptions.getTitleByName(optionsInputValues, item.choice) : ''; - } + return item + ? item.choice === optionInputOther.OTHER + ? item.other + : InputOptions.getTitleByName(optionsInputValues, item.choice) + : ''; + } } export default LicenseAgreement; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseKeyGroup.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseKeyGroup.jsx index b1036aae23..555acf8dbe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseKeyGroup.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/LicenseKeyGroup.jsx @@ -13,36 +13,53 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {extractValue, getOperationalScopes} from '../../licenseKeyGroups/LicenseKeyGroupsConstants.js'; +import { + extractValue, + getOperationalScopes +} from '../../licenseKeyGroups/LicenseKeyGroupsConstants.js'; import ArrowCol from './listItemsComponents/ArrowCol.jsx'; import ItemInfo from './listItemsComponents/ItemInfo.jsx'; import IconCol from './listItemsComponents/IconCol.jsx'; -import {AdditionalDataCol, AdditionalDataElement} from './listItemsComponents/AdditionalDataCol.jsx'; +import { + AdditionalDataCol, + AdditionalDataElement +} from './listItemsComponents/AdditionalDataCol.jsx'; class LicenseKeyGroup extends Component { - render() { - let {lkgData: {name, description, operationalScope, type}, isOrphan} = this.props; - return ( - <div className={`vlm-list-item vlm-list-item-lkg ${isOrphan ? 'orphan-list-item' : ''}`} data-test-id='vlm-list-item-lkg'> - {!isOrphan && <ArrowCol/>} - <IconCol className='lkg-icon' text='LKG'/> - <ItemInfo name={name} description={description}/> - <AdditionalDataCol> - {operationalScope && operationalScope.choices && <AdditionalDataElement - className='vlm-list-item-operational-scope' - name={i18n('Operational Scope')} - value={getOperationalScopes(operationalScope)}/>} - <AdditionalDataElement - className='vlm-list-item-group-type' - name={i18n('Type')} - value={extractValue(type)}/> - </AdditionalDataCol> - </div> - ); - } - + render() { + let { + lkgData: { name, description, operationalScope, type }, + isOrphan + } = this.props; + return ( + <div + className={`vlm-list-item vlm-list-item-lkg ${ + isOrphan ? 'orphan-list-item' : '' + }`} + data-test-id="vlm-list-item-lkg"> + {!isOrphan && <ArrowCol />} + <IconCol className="lkg-icon" text="LKG" /> + <ItemInfo name={name} description={description} /> + <AdditionalDataCol> + {operationalScope && + operationalScope.choices && ( + <AdditionalDataElement + className="vlm-list-item-operational-scope" + name={i18n('Operational Scope')} + value={getOperationalScopes(operationalScope)} + /> + )} + <AdditionalDataElement + className="vlm-list-item-group-type" + name={i18n('Type')} + value={extractValue(type)} + /> + </AdditionalDataCol> + </div> + ); + } } export default LicenseKeyGroup; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/AdditionalDataCol.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/AdditionalDataCol.jsx index ffc0991354..0f9c783eac 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/AdditionalDataCol.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/AdditionalDataCol.jsx @@ -16,37 +16,35 @@ import React from 'react'; import PropTypes from 'prop-types'; -function AdditionalDataCol({children}) { - return ( - <div className='list-item-section list-item-additional-data-col'> - <div className='additional-data-col-border'></div> - <div className='additional-data'> - {children} - </div> - </div> - ); +function AdditionalDataCol({ children }) { + return ( + <div className="list-item-section list-item-additional-data-col"> + <div className="additional-data-col-border" /> + <div className="additional-data">{children}</div> + </div> + ); } AdditionalDataCol.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]) + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) }; -function AdditionalDataElement({className, name, value}) { - return ( - <div className={className}> - <span className='additional-data-name'>{name}: </span> - <span className='additional-data-value'>{value}</span> - </div> - ); +function AdditionalDataElement({ className, name, value }) { + return ( + <div className={className}> + <span className="additional-data-name">{name}: </span> + <span className="additional-data-value">{value}</span> + </div> + ); } AdditionalDataElement.propTypes = { - name: PropTypes.string, - value: PropTypes.string, - className: PropTypes.string + name: PropTypes.string, + value: PropTypes.string, + className: PropTypes.string }; -export {AdditionalDataCol, AdditionalDataElement}; +export { AdditionalDataCol, AdditionalDataElement }; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ArrowCol.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ArrowCol.jsx index 29aec64bdd..de12eae7d5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ArrowCol.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ArrowCol.jsx @@ -17,20 +17,24 @@ import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -function ArrowCol ({isCollapsed, length}) { - return ( - <div className='list-item-section list-item-arrow-col'> - <div className={classNames('arrow-icon', {'chevron': length > 0}, - {'down': (length > 0 && isCollapsed)}, - {'right': (length > 0 && (!isCollapsed))})} > - </div> - </div> - ); +function ArrowCol({ isCollapsed, length }) { + return ( + <div className="list-item-section list-item-arrow-col"> + <div + className={classNames( + 'arrow-icon', + { chevron: length > 0 }, + { down: length > 0 && isCollapsed }, + { right: length > 0 && !isCollapsed } + )} + /> + </div> + ); } ArrowCol.propTypes = { - isCollapsed: PropTypes.bool, - length: PropTypes.number + isCollapsed: PropTypes.bool, + length: PropTypes.number }; export default ArrowCol; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/IconCol.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/IconCol.jsx index 826248e510..61eeb03496 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/IconCol.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/IconCol.jsx @@ -15,12 +15,14 @@ */ import React from 'react'; -function IconCol({className, text}) { - return ( - <div className='list-item-section list-item-icon-col'> - <div className={`overview-list-icon ${className ? className : ''}`}>{text}</div> - </div> - ); +function IconCol({ className, text }) { + return ( + <div className="list-item-section list-item-icon-col"> + <div className={`overview-list-icon ${className ? className : ''}`}> + {text} + </div> + </div> + ); } export default IconCol; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ItemInfo.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ItemInfo.jsx index 95ae123974..2d2cc8f754 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ItemInfo.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/listItems/listItemsComponents/ItemInfo.jsx @@ -16,25 +16,27 @@ import React from 'react'; import PropTypes from 'prop-types'; -function ItemInfo({name, description, children}) { - return ( - <div className='list-item-section vlm-item-info'> - <div className='vlm-list-item-title'> - <div className='item-name' data-test-id='vlm-list-item-name'>{name}</div> - {children} - </div> - <div className='vlm-list-item-description'>{description}</div> - </div> - ); +function ItemInfo({ name, description, children }) { + return ( + <div className="list-item-section vlm-item-info"> + <div className="vlm-list-item-title"> + <div className="item-name" data-test-id="vlm-list-item-name"> + {name} + </div> + {children} + </div> + <div className="vlm-list-item-description">{description}</div> + </div> + ); } ItemInfo.propTypes = { - name: PropTypes.string, - description: PropTypes.string, - children: PropTypes.oneOfType([ - PropTypes.arrayOf(PropTypes.node), - PropTypes.node - ]) + name: PropTypes.string, + description: PropTypes.string, + children: PropTypes.oneOfType([ + PropTypes.arrayOf(PropTypes.node), + PropTypes.node + ]) }; export default ItemInfo; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/LicenseModelDescriptionEdit.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/LicenseModelDescriptionEdit.jsx index af759f1206..04a00177d3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/LicenseModelDescriptionEdit.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/LicenseModelDescriptionEdit.jsx @@ -18,42 +18,54 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; class LicenseModelDescriptionEdit extends React.Component { - render() { - //TODO check if buttons - let {onDataChanged, description, genericFieldInfo} = this.props; - let {isValid, errorText} = genericFieldInfo.description; - let saveButtonClassName = isValid ? 'description-save' : 'description-save disabled'; - return( - <div className='vendor-description-edit'> + render() { + //TODO check if buttons + let { onDataChanged, description, genericFieldInfo } = this.props; + let { isValid, errorText } = genericFieldInfo.description; + let saveButtonClassName = isValid + ? 'description-save' + : 'description-save disabled'; + return ( + <div className="vendor-description-edit"> + <Input + onChange={description => onDataChanged({ description })} + value={description} + isValid={isValid} + errorText={errorText} + className="description-edit-textarea" + type="textarea" + /> + <div className="buttons-row"> + <div className="buttons-wrapper"> + <div + onClick={() => this.submit()} + className={saveButtonClassName} + data-test-id="vlm-summary-vendor-desc-save-btn"> + {i18n('Save')} + </div> + <div + onClick={() => this.onClose()} + className="description-button" + data-test-id="vlm-summary-vendor-desc-cancel-btn"> + {i18n('Cancel')} + </div> + </div> + </div> + </div> + ); + } - <Input - onChange={description => onDataChanged({description})} - value={description} - isValid={isValid} - errorText={errorText} - className='description-edit-textarea' - type='textarea'/> - <div className='buttons-row'> - <div className='buttons-wrapper'> - <div onClick={() => this.submit()} className={saveButtonClassName} data-test-id='vlm-summary-vendor-desc-save-btn'>{i18n('Save')}</div> - <div onClick={() => this.onClose()} className='description-button' data-test-id='vlm-summary-vendor-desc-cancel-btn'>{i18n('Cancel')}</div> - </div> - </div> - </div> - ); - } + onClose() { + this.props.onClose(); + } - onClose() { - this.props.onClose(); - } - - submit() { - let {onSubmit, data, description} = this.props; - onSubmit({ - ...data, - description: description.trim() - }); - } + submit() { + let { onSubmit, data, description } = this.props; + onSubmit({ + ...data, + description: description.trim() + }); + } } export default LicenseModelDescriptionEdit; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/ListButtons.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/ListButtons.jsx index 3fcac3c1d8..d422d5d4b2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/ListButtons.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/ListButtons.jsx @@ -15,37 +15,39 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {selectedButton} from '../LicenseModelOverviewConstants.js'; +import { selectedButton } from '../LicenseModelOverviewConstants.js'; import Tabs from 'sdc-ui/lib/react/Tabs.js'; import Tab from 'sdc-ui/lib/react/Tab.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -function ListButtons ({onTabSelect, selectedTab, hasOrphans, hasLicensing}) { - // no data, no tabs - if (!hasLicensing && !hasOrphans) { - return null; - } - return ( - <Tabs - onTabClick={(tabId) => onTabSelect(tabId)} - activeTab={selectedTab} - className='overview-buttons-section' - type='header' > - <Tab - tabId={selectedButton.VLM_LIST_VIEW} - title={i18n('Connections List')} - data-test-id='vlm-overview-vlmlist-tab' /> - <Tab - tabId={selectedButton.NOT_IN_USE} - title={i18n('Orphans List')} - data-test-id='vlm-overview-orphans-tab' /> - </Tabs> - ); +function ListButtons({ onTabSelect, selectedTab, hasOrphans, hasLicensing }) { + // no data, no tabs + if (!hasLicensing && !hasOrphans) { + return null; + } + return ( + <Tabs + onTabClick={tabId => onTabSelect(tabId)} + activeTab={selectedTab} + className="overview-buttons-section" + type="header"> + <Tab + tabId={selectedButton.VLM_LIST_VIEW} + title={i18n('Connections List')} + data-test-id="vlm-overview-vlmlist-tab" + /> + <Tab + tabId={selectedButton.NOT_IN_USE} + title={i18n('Orphans List')} + data-test-id="vlm-overview-orphans-tab" + /> + </Tabs> + ); } ListButtons.propTypes = { - onTabSelect: PropTypes.func, - selectedInUse: PropTypes.bool + onTabSelect: PropTypes.func, + selectedInUse: PropTypes.bool }; export default ListButtons; diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountItem.jsx b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountItem.jsx index 50c547e042..144d9bcc1b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountItem.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountItem.jsx @@ -16,19 +16,43 @@ import React from 'react'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -function SummaryCountItem ({name, counter, onAdd, onNavigate, isReadOnlyMode}) { - //TODO check for buttons - return( - <div className='summary-count-item'> - <div className='summary-name-and-count' onClick={onNavigate}> - <span className='item-name' onClick={onNavigate}>{name}</span> - <span className='item-count' onClick={onNavigate} data-test-id={'vlm-summary-vendor-counter-' + name.toLowerCase().replace(/\s/g,'-')}>({counter})</span> - </div> - <SVGIcon name='plusCircle' disabled={isReadOnlyMode} className={isReadOnlyMode ? 'disabled' : ''} - color='secondary' onClick={onAdd} data-test-id={'vlm-summary-vendor-add-btn-' + name.toLowerCase().replace(/\s/g,'-')}/> - </div> - ); +function SummaryCountItem({ + name, + counter, + onAdd, + onNavigate, + isReadOnlyMode +}) { + //TODO check for buttons + return ( + <div className="summary-count-item"> + <div className="summary-name-and-count" onClick={onNavigate}> + <span className="item-name" onClick={onNavigate}> + {name} + </span> + <span + className="item-count" + onClick={onNavigate} + data-test-id={ + 'vlm-summary-vendor-counter-' + + name.toLowerCase().replace(/\s/g, '-') + }> + ({counter}) + </span> + </div> + <SVGIcon + name="plusCircle" + disabled={isReadOnlyMode} + className={isReadOnlyMode ? 'disabled' : ''} + color="secondary" + onClick={onAdd} + data-test-id={ + 'vlm-summary-vendor-add-btn-' + + name.toLowerCase().replace(/\s/g, '-') + } + /> + </div> + ); } export default SummaryCountItem; - diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountList.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountList.js index 15b6649543..711bb7a374 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountList.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/SummaryCountList.js @@ -14,123 +14,158 @@ * permissions and limitations under the License. */ import React from 'react'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import EntitlementPoolsActionHelper from '../../entitlementPools/EntitlementPoolsActionHelper.js'; import LicenseAgreementActionHelper from '../../licenseAgreement/LicenseAgreementActionHelper.js'; import LicenseKeyGroupsActionHelper from '../../licenseKeyGroups/LicenseKeyGroupsActionHelper.js'; import FeatureGroupsActionHelper from '../../featureGroups/FeatureGroupsActionHelper.js'; -import {overviewItems} from '../LicenseModelOverviewConstants.js'; +import { overviewItems } from '../LicenseModelOverviewConstants.js'; import SummaryCountItem from './SummaryCountItem.jsx'; export const mapStateToProps = ({ - licenseModel: { - licenseModelEditor, - licenseAgreement: {licenseAgreementList}, - featureGroup: {featureGroupsList}, - entitlementPool: {entitlementPoolsList}, - licenseKeyGroup: {licenseKeyGroupsList} - } + licenseModel: { + licenseModelEditor, + licenseAgreement: { licenseAgreementList }, + featureGroup: { featureGroupsList }, + entitlementPool: { entitlementPoolsList }, + licenseKeyGroup: { licenseKeyGroupsList } + } }) => { + let { vendorName, description, id, version } = licenseModelEditor.data; + let counts = [ + { + name: overviewItems.LICENSE_AGREEMENTS, + count: licenseAgreementList.length + }, + { name: overviewItems.FEATURE_GROUPS, count: featureGroupsList.length }, + { + name: overviewItems.ENTITLEMENT_POOLS, + count: entitlementPoolsList.length + }, + { + name: overviewItems.LICENSE_KEY_GROUPS, + count: licenseKeyGroupsList.length + } + ]; - let {vendorName, description, id, version} = licenseModelEditor.data; - let counts = [ - {name: overviewItems.LICENSE_AGREEMENTS, count: licenseAgreementList.length}, - {name: overviewItems.FEATURE_GROUPS, count: featureGroupsList.length}, - {name: overviewItems.ENTITLEMENT_POOLS, count: entitlementPoolsList.length}, - {name: overviewItems.LICENSE_KEY_GROUPS, count: licenseKeyGroupsList.length}, - ]; - - return { - vendorName, - licenseModelId: id, - description, - counts, - version - }; - + return { + vendorName, + licenseModelId: id, + description, + counts, + version + }; }; -const mapActionsToProps = (dispatch) => { - return { - onEditorOpenClick: (name, licenseModelId, version) => { - switch (name) { - case overviewItems.ENTITLEMENT_POOLS: - EntitlementPoolsActionHelper.openEntitlementPoolsEditor(dispatch); - break; - case overviewItems.FEATURE_GROUPS: - FeatureGroupsActionHelper.openFeatureGroupsEditor(dispatch, {licenseModelId, version}); - break; - case overviewItems.LICENSE_AGREEMENTS: - LicenseAgreementActionHelper.openLicenseAgreementEditor(dispatch, {licenseModelId, version}); - break; - case overviewItems.LICENSE_KEY_GROUPS: - LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor(dispatch); - break; - default: - break; - } - }, - onNavigateClick: ({name, licenseModelId, version}) => { - let screenToNavigate; - switch (name) { - case overviewItems.ENTITLEMENT_POOLS: - screenToNavigate = enums.SCREEN.ENTITLEMENT_POOLS; - break; - case overviewItems.FEATURE_GROUPS: - screenToNavigate = enums.SCREEN.FEATURE_GROUPS; - break; - case overviewItems.LICENSE_AGREEMENTS: - screenToNavigate = enums.SCREEN.LICENSE_AGREEMENTS; - break; - case overviewItems.LICENSE_KEY_GROUPS: - screenToNavigate = enums.SCREEN.LICENSE_KEY_GROUPS; - break; - default: - break; - } - ScreensHelper.loadScreen(dispatch, { - screen: screenToNavigate, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId, version} - }); - } - }; +const mapActionsToProps = dispatch => { + return { + onEditorOpenClick: (name, licenseModelId, version) => { + switch (name) { + case overviewItems.ENTITLEMENT_POOLS: + EntitlementPoolsActionHelper.openEntitlementPoolsEditor( + dispatch + ); + break; + case overviewItems.FEATURE_GROUPS: + FeatureGroupsActionHelper.openFeatureGroupsEditor( + dispatch, + { + licenseModelId, + version + } + ); + break; + case overviewItems.LICENSE_AGREEMENTS: + LicenseAgreementActionHelper.openLicenseAgreementEditor( + dispatch, + { + licenseModelId, + version + } + ); + break; + case overviewItems.LICENSE_KEY_GROUPS: + LicenseKeyGroupsActionHelper.openLicenseKeyGroupsEditor( + dispatch + ); + break; + default: + break; + } + }, + onNavigateClick: ({ name, licenseModelId, version }) => { + let screenToNavigate; + switch (name) { + case overviewItems.ENTITLEMENT_POOLS: + screenToNavigate = enums.SCREEN.ENTITLEMENT_POOLS; + break; + case overviewItems.FEATURE_GROUPS: + screenToNavigate = enums.SCREEN.FEATURE_GROUPS; + break; + case overviewItems.LICENSE_AGREEMENTS: + screenToNavigate = enums.SCREEN.LICENSE_AGREEMENTS; + break; + case overviewItems.LICENSE_KEY_GROUPS: + screenToNavigate = enums.SCREEN.LICENSE_KEY_GROUPS; + break; + default: + break; + } + ScreensHelper.loadScreen(dispatch, { + screen: screenToNavigate, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId, version } + }); + } + }; }; export class SummaryCountList extends React.Component { + render() { + let { counts } = this.props; + return ( + <div className="summary-count-list"> + {counts.map(item => this.renderItem(item))} + </div> + ); + } - render() { - let {counts} = this.props; - return( - <div className='summary-count-list'> - {counts.map(item => this.renderItem(item))} - </div> - ); - } - - renderItem(item){ - const {name, count} = item; - const {isReadOnlyMode} = this.props; - return( - <SummaryCountItem isReadOnlyMode={isReadOnlyMode} name={name} counter={count} onNavigate={() => this.onNavigate(name)} onAdd={() => this.onAdd(name)} key={name} /> - ); - } + renderItem(item) { + const { name, count } = item; + const { isReadOnlyMode } = this.props; + return ( + <SummaryCountItem + isReadOnlyMode={isReadOnlyMode} + name={name} + counter={count} + onNavigate={() => this.onNavigate(name)} + onAdd={() => this.onAdd(name)} + key={name} + /> + ); + } - onAdd(name) { - let {onEditorOpenClick, licenseModelId, isReadOnlyMode, version} = this.props; - if (!isReadOnlyMode) { - onEditorOpenClick(name, licenseModelId, version); - } - } + onAdd(name) { + let { + onEditorOpenClick, + licenseModelId, + isReadOnlyMode, + version + } = this.props; + if (!isReadOnlyMode) { + onEditorOpenClick(name, licenseModelId, version); + } + } - onNavigate(name) { - let {onNavigateClick, licenseModelId, version} = this.props; - onNavigateClick({licenseModelId, name, version}); - } + onNavigate(name) { + let { onNavigateClick, licenseModelId, version } = this.props; + onNavigateClick({ licenseModelId, name, version }); + } } export default connect(mapStateToProps, mapActionsToProps)(SummaryCountList); diff --git a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/VendorDataView.js b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/VendorDataView.js index 616355de41..62fc2c3cb3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/VendorDataView.js +++ b/openecomp-ui/src/sdc-app/onboarding/licenseModel/overview/summary/VendorDataView.js @@ -13,8 +13,8 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; -import {connect} from 'react-redux'; +import React, { Component } from 'react'; +import { connect } from 'react-redux'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; @@ -23,89 +23,139 @@ import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import licenseModelOverviewActionHelper from '../licenseModelOverviewActionHelper.js'; import LicenseModelActionHelper from '../../LicenseModelActionHelper.js'; import LicenseModelDescriptionEdit from './LicenseModelDescriptionEdit.jsx'; -import {VLM_DESCRIPTION_FORM} from '../LicenseModelOverviewConstants.js'; +import { VLM_DESCRIPTION_FORM } from '../LicenseModelOverviewConstants.js'; export const mapStateToProps = ({ - licenseModel: { - licenseModelEditor: {data}, - licenseModelOverview: {descriptionEditor: {data: descriptionData = {}, genericFieldInfo}} - } + licenseModel: { + licenseModelEditor: { data }, + licenseModelOverview: { + descriptionEditor: { data: descriptionData = {}, genericFieldInfo } + } + } }) => { - let {description} = descriptionData; - return { - data, - description, - genericFieldInfo - }; + let { description } = descriptionData; + return { + data, + description, + genericFieldInfo + }; }; -const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: VLM_DESCRIPTION_FORM}), - onCancel: () => licenseModelOverviewActionHelper.editDescriptionClose(dispatch), - onSubmit: (licenseModel) => { - licenseModelOverviewActionHelper.editDescriptionClose(dispatch); - LicenseModelActionHelper.saveLicenseModel(dispatch, {licenseModel}); - }, - onVendorDescriptionEdit: description => licenseModelOverviewActionHelper.editDescriptionOpen(dispatch,{description}) - }; +const mapActionsToProps = dispatch => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: VLM_DESCRIPTION_FORM + }), + onCancel: () => + licenseModelOverviewActionHelper.editDescriptionClose(dispatch), + onSubmit: licenseModel => { + licenseModelOverviewActionHelper.editDescriptionClose(dispatch); + LicenseModelActionHelper.saveLicenseModel(dispatch, { + licenseModel + }); + }, + onVendorDescriptionEdit: description => + licenseModelOverviewActionHelper.editDescriptionOpen(dispatch, { + description + }) + }; }; export class VendorDataView extends Component { - render() { - let {data: {vendorName}, description, isReadOnlyMode} = this.props; - return ( - <div className='vendor-data-view'> - <div className='vendor-title'>vendor</div> - <div className='vendor-name' data-test-id='vlm-summary-vendor-name'>{vendorName}</div> - { - description !== undefined && !isReadOnlyMode ? this.renderDescriptionEdit() : this.renderDescription() - } - </div> - ); - } + render() { + let { data: { vendorName }, description, isReadOnlyMode } = this.props; + return ( + <div className="vendor-data-view"> + <div className="vendor-title">vendor</div> + <div + className="vendor-name" + data-test-id="vlm-summary-vendor-name"> + {vendorName} + </div> + {description !== undefined && !isReadOnlyMode + ? this.renderDescriptionEdit() + : this.renderDescription()} + </div> + ); + } - componentWillUnmount() { - this.props.onCancel(); - } + componentWillUnmount() { + this.props.onCancel(); + } + renderDescription() { + let { + data: { description }, + onVendorDescriptionEdit, + isReadOnlyMode + } = this.props; + return ( + <div + onClick={() => { + if (!isReadOnlyMode) { + onVendorDescriptionEdit(description); + } + }} + className={ + !isReadOnlyMode + ? 'vendor-description' + : 'vendor-description-readonly' + }> + {this.renderOverlay( + <div + className="description-data" + data-test-id="vlm-summary-vendor-description"> + {description} + {!isReadOnlyMode && <SVGIcon name="pencil" />} + </div> + )} + </div> + ); + } - renderDescription() { - let {data: {description}, onVendorDescriptionEdit, isReadOnlyMode} = this.props; - return ( - <div onClick={() => {if (!isReadOnlyMode) {onVendorDescriptionEdit(description);}}} className={!isReadOnlyMode ? 'vendor-description' : 'vendor-description-readonly'}> - {this.renderOverlay( - <div className='description-data' data-test-id='vlm-summary-vendor-description'> - {description} - {!isReadOnlyMode && <SVGIcon name='pencil'/>} - </div> - )} - </div> - ); - } - - renderDescriptionEdit() { - let {onCancel, onDataChanged, onSubmit, description, genericFieldInfo, data} = this.props; - return( - <LicenseModelDescriptionEdit onClose={onCancel} onDataChanged={onDataChanged} onSubmit={onSubmit} data={data} genericFieldInfo={genericFieldInfo} description={description}/> - ); - } - - renderOverlay(children) { - let {data: {description}, isReadOnlyMode} = this.props; - if (isReadOnlyMode) { - return ( - <OverlayTrigger - placement='bottom' - overlay={<Tooltip className='vendor-description-tooltip' id='tooltip-bottom'>{description}</Tooltip>} - delayShow={400}> - {children} - </OverlayTrigger> - ); - } - return children; - } + renderDescriptionEdit() { + let { + onCancel, + onDataChanged, + onSubmit, + description, + genericFieldInfo, + data + } = this.props; + return ( + <LicenseModelDescriptionEdit + onClose={onCancel} + onDataChanged={onDataChanged} + onSubmit={onSubmit} + data={data} + genericFieldInfo={genericFieldInfo} + description={description} + /> + ); + } + renderOverlay(children) { + let { data: { description }, isReadOnlyMode } = this.props; + if (isReadOnlyMode) { + return ( + <OverlayTrigger + placement="bottom" + overlay={ + <Tooltip + className="vendor-description-tooltip" + id="tooltip-bottom"> + {description} + </Tooltip> + } + delayShow={400}> + {children} + </OverlayTrigger> + ); + } + return children; + } } export default connect(mapStateToProps, mapActionsToProps)(VendorDataView); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx index 345c91e01b..7f361d2742 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.jsx @@ -16,71 +16,96 @@ import React from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {catalogItemTypes, migrationStatusMapper} from './onboardingCatalog/OnboardingCatalogConstants.js'; -import {Tile, TileInfo, TileInfoLine, TileFooter, TileFooterCell} from 'sdc-ui/lib/react'; -import {TooltipWrapper} from './onboardingCatalog/Tooltip.jsx'; +import { + catalogItemTypes, + migrationStatusMapper +} from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { + Tile, + TileInfo, + TileInfoLine, + TileFooter, + TileFooterCell +} from 'sdc-ui/lib/react'; +import { TooltipWrapper } from './onboardingCatalog/Tooltip.jsx'; const ITEM_TYPE_MAP = { - [catalogItemTypes.LICENSE_MODEL]: { - headerText: i18n('VLM'), - contentIconName: 'vlm', - color: 'purple' - }, - [catalogItemTypes.SOFTWARE_PRODUCT]: { - headerText: i18n('VSP'), - contentIconName: 'vsp', - color: 'blue' - } + [catalogItemTypes.LICENSE_MODEL]: { + headerText: i18n('VLM'), + contentIconName: 'vlm', + color: 'purple' + }, + [catalogItemTypes.SOFTWARE_PRODUCT]: { + headerText: i18n('VSP'), + contentIconName: 'vsp', + color: 'blue' + } }; -const CatalogItemDetails = ({catalogItemData, catalogItemTypeClass, onSelect, onMigrate}) => { +const CatalogItemDetails = ({ + catalogItemData, + catalogItemTypeClass, + onSelect, + onMigrate +}) => { + let { vendorName, name, owner } = catalogItemData; + let { headerText, color, contentIconName } = ITEM_TYPE_MAP[ + catalogItemTypeClass + ]; - let {vendorName, name, owner} = catalogItemData; - let {headerText, color, contentIconName} = ITEM_TYPE_MAP[catalogItemTypeClass]; - - let onClick = (e) => { - e.stopPropagation(); - e.preventDefault(); - if (catalogItemData.isOldVersion && catalogItemData.isOldVersion === migrationStatusMapper.OLD_VERSION) { - onMigrate({softwareProduct: catalogItemData}); - } else { - onSelect(); - } - }; - - return ( - <Tile - headerText={headerText} - headerColor={color} - iconName={contentIconName} - iconColor={color} - onClick={onClick} - dataTestId={catalogItemTypeClass}> - <TileInfo data-test-id='catalog-item-content'> - {vendorName && - <TileInfoLine type='supertitle'> - <TooltipWrapper className='with-overlay' tooltipClassName='tile-super-info' dataTestId='catalog-item-vendor-name'>{vendorName}</TooltipWrapper> - </TileInfoLine> - } - <TileInfoLine type='title'> - <TooltipWrapper className='with-overlay' tooltipClassName='tile-title-info' dataTestId='catalog-item-name'>{name}</TooltipWrapper> - </TileInfoLine> - </TileInfo> - <TileFooter> - {owner && - <TileFooterCell>Owner - {owner}</TileFooterCell> - } - </TileFooter> - </Tile> - ); + let onClick = e => { + e.stopPropagation(); + e.preventDefault(); + if ( + catalogItemData.isOldVersion && + catalogItemData.isOldVersion === migrationStatusMapper.OLD_VERSION + ) { + onMigrate({ softwareProduct: catalogItemData }); + } else { + onSelect(); + } + }; + return ( + <Tile + headerText={headerText} + headerColor={color} + iconName={contentIconName} + iconColor={color} + onClick={onClick} + dataTestId={catalogItemTypeClass}> + <TileInfo data-test-id="catalog-item-content"> + {vendorName && ( + <TileInfoLine type="supertitle"> + <TooltipWrapper + className="with-overlay" + tooltipClassName="tile-super-info" + dataTestId="catalog-item-vendor-name"> + {vendorName} + </TooltipWrapper> + </TileInfoLine> + )} + <TileInfoLine type="title"> + <TooltipWrapper + className="with-overlay" + tooltipClassName="tile-title-info" + dataTestId="catalog-item-name"> + {name} + </TooltipWrapper> + </TileInfoLine> + </TileInfo> + <TileFooter> + {owner && <TileFooterCell>Owner - {owner}</TileFooterCell>} + </TileFooter> + </Tile> + ); }; CatalogItemDetails.PropTypes = { - catalogItemData: PropTypes.obj, - catalogItemTypeClass: PropTypes.string, - onSelect: PropTypes.func, - onMigrate: PropTypes.func + catalogItemData: PropTypes.obj, + catalogItemTypeClass: PropTypes.string, + onSelect: PropTypes.func, + onMigrate: PropTypes.func }; export default CatalogItemDetails; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js index 156adfc5e7..d01b9d0d04 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogItemDetails.stories.js @@ -1,33 +1,48 @@ import React from 'react'; -import {storiesOf, action} from '@kadira/storybook'; -import {select, withKnobs} from '@kadira/storybook-addon-knobs'; +import { storiesOf, action } from '@kadira/storybook'; +import { select, withKnobs } from '@kadira/storybook-addon-knobs'; import CatalogItemDetails from './CatalogItemDetails.jsx'; -import {catalogItemTypes, catalogItemStatuses} from './onboardingCatalog/OnboardingCatalogConstants.js'; -import {FinalizedLicenseModelFactory} from 'test-utils/factories/licenseModel/LicenseModelFactories.js'; +import { + catalogItemTypes, + catalogItemStatuses +} from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { FinalizedLicenseModelFactory } from 'test-utils/factories/licenseModel/LicenseModelFactories.js'; const stories = storiesOf('CatalogTiles', module); stories.addDecorator(withKnobs); const types = [ - catalogItemTypes.LICENSE_MODEL, - catalogItemTypes.SOFTWARE_PRODUCT + catalogItemTypes.LICENSE_MODEL, + catalogItemTypes.SOFTWARE_PRODUCT ]; function selectType() { - return select('Item type' , types, types[0]); + return select('Item type', types, types[0]); } -let vlm = {...FinalizedLicenseModelFactory.build({name: 'Test-VLM'}), itemStatus: catalogItemStatuses.DRAFT}; -let certifiedVlm = {...vlm, itemStatus: catalogItemStatuses.CERTIFIED}; +let vlm = { + ...FinalizedLicenseModelFactory.build({ name: 'Test-VLM' }), + itemStatus: catalogItemStatuses.DRAFT +}; +let certifiedVlm = { ...vlm, itemStatus: catalogItemStatuses.CERTIFIED }; -stories - .add('preview', () => ( - <div className='catalog-view'> - <div className='catalog-list'> - <div className='catalog-items'> - <CatalogItemDetails catalogItemData={vlm} catalogItemTypeClass={selectType()} onSelect={action('onSelect')} onMigrate={action('onMigrate')}/> - <CatalogItemDetails catalogItemData={certifiedVlm} catalogItemTypeClass={selectType()} onSelect={action('onSelect')} onMigrate={action('onMigrate')}/> - </div> - </div> - </div> - )); +stories.add('preview', () => ( + <div className="catalog-view"> + <div className="catalog-list"> + <div className="catalog-items"> + <CatalogItemDetails + catalogItemData={vlm} + catalogItemTypeClass={selectType()} + onSelect={action('onSelect')} + onMigrate={action('onMigrate')} + /> + <CatalogItemDetails + catalogItemData={certifiedVlm} + catalogItemTypeClass={selectType()} + onSelect={action('onSelect')} + onMigrate={action('onMigrate')} + /> + </div> + </div> + </div> +)); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx index 10d855c862..b00ceeb48f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogList.jsx @@ -17,37 +17,61 @@ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -const SoftwareProductListHeader = ({selectedVendor, onBack}) => ( - <div className='vendor-page-header'> - <SVGIcon name='back' onClick={onBack}/> - <div className='tab-separator' /> - <div className='vendor-name'>{selectedVendor.name}</div> - </div> +const SoftwareProductListHeader = ({ selectedVendor, onBack }) => ( + <div className="vendor-page-header"> + <SVGIcon name="back" onClick={onBack} /> + <div className="tab-separator" /> + <div className="vendor-name">{selectedVendor.name}</div> + </div> ); -const CatalogList = ({children, onAddVLM, onAddVSP, vendorPageOptions}) => ( - <div className='catalog-list'> - {vendorPageOptions && <SoftwareProductListHeader onBack={vendorPageOptions.onBack} selectedVendor={vendorPageOptions.selectedVendor}/>} - <div className='catalog-items'> - { (onAddVLM || onAddVSP) && - <div className='create-catalog-item-wrapper'> - {onAddVLM && <CreateItemTile onClick={onAddVLM} dataTestId={'catalog-add-new-vlm'} className='vlm-type' title={i18n('CREATE NEW VLM')}/>} - {onAddVSP && <CreateItemTile onClick={() => onAddVSP()} dataTestId={'catalog-add-new-vsp'} className='vsp-type' title={i18n('CREATE NEW VSP')}/>} - </div> - } - {children} - </div> - </div> +const CatalogList = ({ children, onAddVLM, onAddVSP, vendorPageOptions }) => ( + <div className="catalog-list"> + {vendorPageOptions && ( + <SoftwareProductListHeader + onBack={vendorPageOptions.onBack} + selectedVendor={vendorPageOptions.selectedVendor} + /> + )} + <div className="catalog-items"> + {(onAddVLM || onAddVSP) && ( + <div className="create-catalog-item-wrapper"> + {onAddVLM && ( + <CreateItemTile + onClick={onAddVLM} + dataTestId={'catalog-add-new-vlm'} + className="vlm-type" + title={i18n('CREATE NEW VLM')} + /> + )} + {onAddVSP && ( + <CreateItemTile + onClick={() => onAddVSP()} + dataTestId={'catalog-add-new-vsp'} + className="vsp-type" + title={i18n('CREATE NEW VSP')} + /> + )} + </div> + )} + {children} + </div> + </div> ); -const CreateItemTile = ({onClick, dataTestId, title, className = ''}) => { - //TODO check for buttons - return ( - <div className={`create-catalog-item tile ${className}`} onClick={onClick} data-test-id={dataTestId}> - <div className='create-item-plus-icon'><SVGIcon name='plus' /></div> - <div className='create-item-text'>{title}</div> - </div> - ); +const CreateItemTile = ({ onClick, dataTestId, title, className = '' }) => { + //TODO check for buttons + return ( + <div + className={`create-catalog-item tile ${className}`} + onClick={onClick} + data-test-id={dataTestId}> + <div className="create-item-plus-icon"> + <SVGIcon name="plus" /> + </div> + <div className="create-item-text">{title}</div> + </div> + ); }; export default CatalogList; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogModal.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogModal.jsx index 1ef9c82822..90496c9be4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogModal.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/CatalogModal.jsx @@ -14,49 +14,52 @@ * permissions and limitations under the License. */ import React from 'react'; -import {modalMapper, catalogItemTypes, catalogItemTypeClasses } from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { + modalMapper, + catalogItemTypes, + catalogItemTypeClasses +} from './onboardingCatalog/OnboardingCatalogConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Modal from 'nfvo-components/modal/Modal.jsx'; import LicenseModelCreation from '../licenseModel/creation/LicenseModelCreation.js'; import SoftwareProductCreation from '../softwareProduct/creation/SoftwareProductCreation.js'; -class CatalogModal extends React.Component{ +class CatalogModal extends React.Component { + getModalDetails() { + const { modalToShow } = this.props; + switch (modalToShow) { + case catalogItemTypes.LICENSE_MODEL: + return { + title: i18n('New License Model'), + element: <LicenseModelCreation /> + }; + case catalogItemTypes.SOFTWARE_PRODUCT: + return { + title: i18n('New Software Product'), + element: <SoftwareProductCreation /> + }; + } + } - getModalDetails(){ - const {modalToShow} = this.props; - switch (modalToShow) { - case catalogItemTypes.LICENSE_MODEL: - return { - title: i18n('New License Model'), - element: <LicenseModelCreation/> - }; - case catalogItemTypes.SOFTWARE_PRODUCT: - return { - title: i18n('New Software Product'), - element: <SoftwareProductCreation/> - }; - } - } + render() { + const { modalToShow } = this.props; + const modalDetails = this.getModalDetails(modalToShow); - render(){ - const {modalToShow} = this.props; - const modalDetails = this.getModalDetails(modalToShow); - - return ( - <Modal - show={Boolean(modalDetails)} - className={`${catalogItemTypeClasses[modalMapper[modalToShow]]}-modal`}> - <Modal.Header> - <Modal.Title>{modalDetails && modalDetails.title}</Modal.Title> - </Modal.Header> - <Modal.Body> - { - modalDetails && modalDetails.element - } - </Modal.Body> - </Modal> - ); - } + return ( + <Modal + show={Boolean(modalDetails)} + className={`${ + catalogItemTypeClasses[modalMapper[modalToShow]] + }-modal`}> + <Modal.Header> + <Modal.Title> + {modalDetails && modalDetails.title} + </Modal.Title> + </Modal.Header> + <Modal.Body>{modalDetails && modalDetails.element}</Modal.Body> + </Modal> + ); + } } export default CatalogModal; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx index ea6cf5e9bc..771c0eb6c1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/DetailsCatalogView.jsx @@ -15,42 +15,66 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {catalogItemTypes} from './onboardingCatalog/OnboardingCatalogConstants.js'; -import {filterCatalogItemsByType} from './onboardingCatalog/OnboardingCatalogUtils.js'; +import { catalogItemTypes } from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { filterCatalogItemsByType } from './onboardingCatalog/OnboardingCatalogUtils.js'; import CatalogList from './CatalogList.jsx'; import CatalogItemDetails from './CatalogItemDetails.jsx'; -class DetailsCatalogView extends React.Component{ +class DetailsCatalogView extends React.Component { + static propTypes = { + VLMList: PropTypes.array, + VSPList: PropTypes.array, + onSelectVLM: PropTypes.func.isRequired, + onSelectVSP: PropTypes.func.isRequired, + onAddVLM: PropTypes.func, + onAddVSP: PropTypes.func, + filter: PropTypes.string.isRequired + }; - static propTypes = { - VLMList: PropTypes.array, - VSPList: PropTypes.array, - onSelectVLM: PropTypes.func.isRequired, - onSelectVSP: PropTypes.func.isRequired, - onAddVLM: PropTypes.func, - onAddVSP: PropTypes.func, - filter: PropTypes.string.isRequired - }; + renderCatalogItems({ items, type, filter, onSelect, onMigrate, users }) { + return filterCatalogItemsByType({ items, filter }).map(item => ( + <CatalogItemDetails + key={item.id} + catalogItemData={item} + catalogItemTypeClass={type} + onMigrate={onMigrate} + onSelect={() => onSelect(item, users)} + /> + )); + } - renderCatalogItems({items, type, filter, onSelect, onMigrate, users}){ - return filterCatalogItemsByType({items, filter}).map(item => - <CatalogItemDetails - key={item.id} - catalogItemData={item} - catalogItemTypeClass={type} - onMigrate={onMigrate} - onSelect={() => onSelect(item, users)} /> - ); - } - - render() { - let {VLMList, VSPList, users, onAddVSP, onAddVLM, onSelectVLM, onSelectVSP, filter = '', onMigrate} = this.props; - return ( - <CatalogList onAddVLM={onAddVLM} onAddVSP={onAddVSP}> - {this.renderCatalogItems({items: VLMList, type: catalogItemTypes.LICENSE_MODEL, filter, onSelect: onSelectVLM, onMigrate, users})} - {this.renderCatalogItems({items: VSPList, type: catalogItemTypes.SOFTWARE_PRODUCT, filter, onSelect: onSelectVSP, onMigrate, users})} - </CatalogList> - ); - } + render() { + let { + VLMList, + VSPList, + users, + onAddVSP, + onAddVLM, + onSelectVLM, + onSelectVSP, + filter = '', + onMigrate + } = this.props; + return ( + <CatalogList onAddVLM={onAddVLM} onAddVSP={onAddVSP}> + {this.renderCatalogItems({ + items: VLMList, + type: catalogItemTypes.LICENSE_MODEL, + filter, + onSelect: onSelectVLM, + onMigrate, + users + })} + {this.renderCatalogItems({ + items: VSPList, + type: catalogItemTypes.SOFTWARE_PRODUCT, + filter, + onSelect: onSelectVSP, + onMigrate, + users + })} + </CatalogList> + ); + } } export default DetailsCatalogView; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js b/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js index 9535147a46..a1e0018114 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/Onboard.js @@ -14,109 +14,121 @@ * limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import OnboardView from './OnboardView.jsx'; import OnboardingCatalogActionHelper from './onboardingCatalog/OnboardingCatalogActionHelper.js'; import OnboardActionHelper from './OnboardActionHelper.js'; import LicenseModelCreationActionHelper from '../licenseModel/creation/LicenseModelCreationActionHelper.js'; import SoftwareProductCreationActionHelper from '../softwareProduct/creation/SoftwareProductCreationActionHelper.js'; import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js'; -import {tabsMapping} from './onboardingCatalog/OnboardingCatalogConstants.js'; -import {itemsType} from './filter/FilterConstants.js'; +import { tabsMapping } from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { itemsType } from './filter/FilterConstants.js'; export const mapStateToProps = ({ - onboard: { - onboardingCatalog, - activeTab, - searchValue, - filter - }, - licenseModelList, - users, - archivedLicenseModelList, - archivedSoftwareProductList, - finalizedLicenseModelList, - softwareProductList, - finalizedSoftwareProductList + onboard: { onboardingCatalog, activeTab, searchValue, filter }, + licenseModelList, + users, + archivedLicenseModelList, + archivedSoftwareProductList, + finalizedLicenseModelList, + softwareProductList, + finalizedSoftwareProductList }) => { + const fullSoftwareProducts = softwareProductList + .filter( + vsp => + !finalizedSoftwareProductList.find(fvsp => fvsp.id === vsp.id) + ) + .concat(finalizedSoftwareProductList); - const fullSoftwareProducts = softwareProductList.filter(vsp => - !finalizedSoftwareProductList - .find(fvsp => fvsp.id === vsp.id) - ).concat(finalizedSoftwareProductList); + const reduceLicenseModelList = (accum, vlm) => { + let currentSoftwareProductList = sortByStringProperty( + fullSoftwareProducts.filter(vsp => vsp.vendorId === vlm.id), + 'name' + ); + accum.push({ ...vlm, softwareProductList: currentSoftwareProductList }); + return accum; + }; - const reduceLicenseModelList = (accum, vlm) => { - let currentSoftwareProductList = sortByStringProperty( - fullSoftwareProducts - .filter(vsp => vsp.vendorId === vlm.id), - 'name' - ); - accum.push({...vlm, softwareProductList: currentSoftwareProductList}); - return accum; - }; + licenseModelList = sortByStringProperty( + licenseModelList.reduce(reduceLicenseModelList, []), + 'name' + ); - licenseModelList = sortByStringProperty( - licenseModelList - .reduce(reduceLicenseModelList, []), - 'name' - ); + finalizedLicenseModelList = sortByStringProperty( + finalizedLicenseModelList.reduce(reduceLicenseModelList, []), + 'name' + ); - finalizedLicenseModelList = sortByStringProperty( - finalizedLicenseModelList - .reduce(reduceLicenseModelList, []), - 'name' - ); + const fullLicenseModelList = licenseModelList + .filter( + vlm => !finalizedLicenseModelList.find(fvlm => fvlm.id === vlm.id) + ) + .concat(finalizedLicenseModelList); - const fullLicenseModelList = licenseModelList.filter(vlm => - !finalizedLicenseModelList - .find(fvlm => fvlm.id === vlm.id) - ).concat(finalizedLicenseModelList); - - let {activeTab: catalogActiveTab, vendorCatalog: {vspOverlay, selectedVendor}} = onboardingCatalog; - if (filter.byVendorView) { - catalogActiveTab = tabsMapping.BY_VENDOR; - } - else if (filter.itemsType && filter.itemsType === itemsType.ARCHIVED) { - catalogActiveTab = tabsMapping.ARCHIVE; - } - - return { - finalizedLicenseModelList, - finalizedSoftwareProductList, - licenseModelList, - softwareProductList, - archivedLicenseModelList, - archivedSoftwareProductList, - fullLicenseModelList, - activeTab, - catalogActiveTab, - searchValue, - vspOverlay, - selectedVendor, - users: users.usersList - }; + let { + activeTab: catalogActiveTab, + vendorCatalog: { vspOverlay, selectedVendor } + } = onboardingCatalog; + if (filter.byVendorView) { + catalogActiveTab = tabsMapping.BY_VENDOR; + } else if (filter.itemsType && filter.itemsType === itemsType.ARCHIVED) { + catalogActiveTab = tabsMapping.ARCHIVE; + } + return { + finalizedLicenseModelList, + finalizedSoftwareProductList, + licenseModelList, + softwareProductList, + archivedLicenseModelList, + archivedSoftwareProductList, + fullLicenseModelList, + activeTab, + catalogActiveTab, + searchValue, + vspOverlay, + selectedVendor, + users: users.usersList + }; }; -const mapActionsToProps = (dispatch) => { - - return { - onSelectLicenseModel({id: licenseModelId, name}, users, tab) { - OnboardActionHelper.loadVLMScreen(dispatch, {id: licenseModelId, name}, users, tab); - }, - onSelectSoftwareProduct(softwareProduct, users, tab) { - OnboardActionHelper.loadVSPScreen(dispatch, softwareProduct, users, tab); - }, - onAddSoftwareProductClick: (vendorId) => SoftwareProductCreationActionHelper.open(dispatch, vendorId), - onAddLicenseModelClick: () => LicenseModelCreationActionHelper.open(dispatch), - onVspOverlayChange: (vendor) => OnboardingCatalogActionHelper.changeVspOverlay(dispatch, vendor), - closeVspOverlay: () => OnboardingCatalogActionHelper.closeVspOverlay(dispatch), - onCatalogTabClick: (tab) => OnboardingCatalogActionHelper.changeActiveTab(dispatch, tab), - onTabClick: (tab) => OnboardActionHelper.changeActiveTab(dispatch, tab), - onSearch: (searchValue) => OnboardActionHelper.changeSearchValue(dispatch, searchValue), - onVendorSelect: (vendor) => OnboardingCatalogActionHelper.onVendorSelect(dispatch, {vendor}), - onMigrate: ({softwareProduct}) => OnboardingCatalogActionHelper.onMigrate(dispatch, softwareProduct) - }; +const mapActionsToProps = dispatch => { + return { + onSelectLicenseModel({ id: licenseModelId, name }, users, tab) { + OnboardActionHelper.loadVLMScreen( + dispatch, + { id: licenseModelId, name }, + users, + tab + ); + }, + onSelectSoftwareProduct(softwareProduct, users, tab) { + OnboardActionHelper.loadVSPScreen( + dispatch, + softwareProduct, + users, + tab + ); + }, + onAddSoftwareProductClick: vendorId => + SoftwareProductCreationActionHelper.open(dispatch, vendorId), + onAddLicenseModelClick: () => + LicenseModelCreationActionHelper.open(dispatch), + onVspOverlayChange: vendor => + OnboardingCatalogActionHelper.changeVspOverlay(dispatch, vendor), + closeVspOverlay: () => + OnboardingCatalogActionHelper.closeVspOverlay(dispatch), + onCatalogTabClick: tab => + OnboardingCatalogActionHelper.changeActiveTab(dispatch, tab), + onTabClick: tab => OnboardActionHelper.changeActiveTab(dispatch, tab), + onSearch: searchValue => + OnboardActionHelper.changeSearchValue(dispatch, searchValue), + onVendorSelect: vendor => + OnboardingCatalogActionHelper.onVendorSelect(dispatch, { vendor }), + onMigrate: ({ softwareProduct }) => + OnboardingCatalogActionHelper.onMigrate(dispatch, softwareProduct) + }; }; export default connect(mapStateToProps, mapActionsToProps)(OnboardView); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js index 892056855f..87ec2d148e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardActionHelper.js @@ -13,97 +13,146 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {tabsMapping, actionTypes} from './OnboardConstants.js'; +import { tabsMapping, actionTypes } from './OnboardConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import {catalogItemStatuses} from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; -import {itemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; const OnboardActionHelper = { - resetOnboardStore(dispatch) { - dispatch({ - type: actionTypes.RESET_ONBOARD_STORE - }); - }, - changeActiveTab(dispatch, activeTab) { - this.clearSearchValue(dispatch); - dispatch({ - type: actionTypes.CHANGE_ACTIVE_ONBOARD_TAB, - activeTab - }); - }, - changeSearchValue(dispatch, searchValue) { - dispatch({ - type: actionTypes.CHANGE_SEARCH_VALUE, - searchValue - }); - }, - clearSearchValue(dispatch) { - dispatch({ - type: actionTypes.CHANGE_SEARCH_VALUE, - searchValue: '' - }); - }, + resetOnboardStore(dispatch) { + dispatch({ + type: actionTypes.RESET_ONBOARD_STORE + }); + }, + changeActiveTab(dispatch, activeTab) { + this.clearSearchValue(dispatch); + dispatch({ + type: actionTypes.CHANGE_ACTIVE_ONBOARD_TAB, + activeTab + }); + }, + changeSearchValue(dispatch, searchValue) { + dispatch({ + type: actionTypes.CHANGE_SEARCH_VALUE, + searchValue + }); + }, + clearSearchValue(dispatch) { + dispatch({ + type: actionTypes.CHANGE_SEARCH_VALUE, + searchValue: '' + }); + }, - loadVLMScreen(dispatch, {id: licenseModelId, name}, users, tab) { - if (tab === tabsMapping.WORKSPACE) { - VersionsPageActionHelper.fetchVersions(dispatch, {itemId: licenseModelId, itemType: itemTypes.LICENSE_MODEL}).then(({results})=> { - results = results.filter((version) => version.status === catalogItemStatuses.DRAFT); - if (results.length !== 1) { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.VERSIONS_PAGE, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId, licenseModel: {name}, usersList: users} - }); - } - else { - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId: licenseModelId, allUsers: users}).then(() => - ScreensHelper.loadLandingScreen(dispatch, {screenType: screenTypes.LICENSE_MODEL, props: {licenseModelId, version: results[0]}}) - ); - } - }); - } - if (tab === tabsMapping.CATALOG) { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.VERSIONS_PAGE, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId, licenseModel: {name}, usersList: users} - }); - } - }, - loadVSPScreen(dispatch, softwareProduct, users, tab) { - let {id: softwareProductId, vendorId: licenseModelId, licensingVersion, name} = softwareProduct; - if (tab === tabsMapping.WORKSPACE) { - VersionsPageActionHelper.fetchVersions(dispatch,{itemId: softwareProductId, itemType: itemTypes.SOFTWARE_PRODUCT}).then(({results})=> { - results = results.filter((version) => version.status === catalogItemStatuses.DRAFT); - if (results.length !== 1) { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: { - softwareProductId, - softwareProduct: {name, vendorId: licenseModelId, licensingVersion}, - usersList: users - } - }); - } - else { - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId: softwareProductId, allUsers: users}).then(() => - ScreensHelper.loadLandingScreen(dispatch, {screenType: screenTypes.SOFTWARE_PRODUCT, props: {softwareProductId, licenseModelId, version: results[0]}}) - ); - } - }); - } - if (tab === tabsMapping.CATALOG) { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: { - softwareProductId, - softwareProduct: {name, vendorId: licenseModelId, licensingVersion}, - usersList: users - } - }); - } - } + loadVLMScreen(dispatch, { id: licenseModelId, name }, users, tab) { + if (tab === tabsMapping.WORKSPACE) { + VersionsPageActionHelper.fetchVersions(dispatch, { + itemId: licenseModelId, + itemType: itemTypes.LICENSE_MODEL + }).then(({ results }) => { + results = results.filter( + version => version.status === catalogItemStatuses.DRAFT + ); + if (results.length !== 1) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.VERSIONS_PAGE, + screenType: screenTypes.LICENSE_MODEL, + props: { + licenseModelId, + licenseModel: { name }, + usersList: users + } + }); + } else { + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId: licenseModelId, + allUsers: users + }).then(() => + ScreensHelper.loadLandingScreen(dispatch, { + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId, version: results[0] } + }) + ); + } + }); + } + if (tab === tabsMapping.CATALOG) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.VERSIONS_PAGE, + screenType: screenTypes.LICENSE_MODEL, + props: { + licenseModelId, + licenseModel: { name }, + usersList: users + } + }); + } + }, + loadVSPScreen(dispatch, softwareProduct, users, tab) { + let { + id: softwareProductId, + vendorId: licenseModelId, + licensingVersion, + name + } = softwareProduct; + if (tab === tabsMapping.WORKSPACE) { + VersionsPageActionHelper.fetchVersions(dispatch, { + itemId: softwareProductId, + itemType: itemTypes.SOFTWARE_PRODUCT + }).then(({ results }) => { + results = results.filter( + version => version.status === catalogItemStatuses.DRAFT + ); + if (results.length !== 1) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct: { + name, + vendorId: licenseModelId, + licensingVersion + }, + usersList: users + } + }); + } else { + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId: softwareProductId, + allUsers: users + }).then(() => + ScreensHelper.loadLandingScreen(dispatch, { + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + licenseModelId, + version: results[0] + } + }) + ); + } + }); + } + if (tab === tabsMapping.CATALOG) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct: { + name, + vendorId: licenseModelId, + licensingVersion + }, + usersList: users + } + }); + } + } }; export default OnboardActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardConstants.js b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardConstants.js index 41128bfb11..6fbf265afb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardConstants.js @@ -16,13 +16,13 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const tabsMapping = { - 'WORKSPACE': 1, - 'CATALOG': 2 + WORKSPACE: 1, + CATALOG: 2 }; export const actionTypes = keyMirror({ - CHANGE_ACTIVE_ONBOARD_TAB: null, - CHANGE_SEARCH_VALUE: null, - RESET_ONBOARD_STORE: null, - VSP_MIGRATION: null + CHANGE_ACTIVE_ONBOARD_TAB: null, + CHANGE_SEARCH_VALUE: null, + RESET_ONBOARD_STORE: null, + VSP_MIGRATION: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardReducer.js index b2e7b0479b..39ceb31b34 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardReducer.js @@ -13,21 +13,27 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, tabsMapping} from './OnboardConstants.js'; -import {combineReducers} from 'redux'; +import { actionTypes, tabsMapping } from './OnboardConstants.js'; +import { combineReducers } from 'redux'; import onboardingCatalogReducer from './onboardingCatalog/OnboardingCatalogReducer.js'; import filterReducer from './filter/FilterReducer.js'; const onboardReducer = combineReducers({ - onboardingCatalog: onboardingCatalogReducer, - filter: filterReducer, - activeTab: (state = tabsMapping.WORKSPACE, action) => action.type === actionTypes.CHANGE_ACTIVE_ONBOARD_TAB ? action.activeTab : state, - searchValue: (state = '', action) => action.type === actionTypes.CHANGE_SEARCH_VALUE ? action.searchValue : state + onboardingCatalog: onboardingCatalogReducer, + filter: filterReducer, + activeTab: (state = tabsMapping.WORKSPACE, action) => + action.type === actionTypes.CHANGE_ACTIVE_ONBOARD_TAB + ? action.activeTab + : state, + searchValue: (state = '', action) => + action.type === actionTypes.CHANGE_SEARCH_VALUE + ? action.searchValue + : state }); export default (state, action) => { - if (action.type === actionTypes.RESET_ONBOARD_STORE) { - state = undefined; - } - return onboardReducer(state, action); + if (action.type === actionTypes.RESET_ONBOARD_STORE) { + state = undefined; + } + return onboardReducer(state, action); }; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx index c045a3739a..dcaeaa787d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/OnboardView.jsx @@ -17,89 +17,99 @@ import React from 'react'; import PropTypes from 'prop-types'; import OnboardingCatalogView from './onboardingCatalog/OnboardingCatalogView.jsx'; import WorkspaceView from './workspace/WorkspaceView.jsx'; -import {tabsMapping} from './OnboardConstants.js'; +import { tabsMapping } from './OnboardConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import classnames from 'classnames'; import ExpandableInput from 'nfvo-components/input/ExpandableInput.jsx'; import objectValues from 'lodash/values.js'; -import {catalogItemTypes} from './onboardingCatalog/OnboardingCatalogConstants.js'; +import { catalogItemTypes } from './onboardingCatalog/OnboardingCatalogConstants.js'; import NotificationsView from 'sdc-app/onboarding/userNotifications/NotificationsView.jsx'; import Filter from 'sdc-app/onboarding/onboard/filter/Filter.jsx'; -const OnboardHeaderTabs = ({onTabClick, activeTab}) => ( - <div className='onboard-header-tabs'> - <div - className={classnames('onboard-header-tab', {'active': activeTab === tabsMapping.WORKSPACE })} - onClick={() => onTabClick(tabsMapping.WORKSPACE)} - data-test-id='onboard-workspace-tab'> - {i18n('WORKSPACE')} - </div> - <div - className={classnames('onboard-header-tab', {'active': activeTab === tabsMapping.CATALOG })} - onClick={() => onTabClick(tabsMapping.CATALOG)} - data-test-id='onboard-onboard-tab'> - {i18n('ONBOARD CATALOG')} - </div> - </div> +const OnboardHeaderTabs = ({ onTabClick, activeTab }) => ( + <div className="onboard-header-tabs"> + <div + className={classnames('onboard-header-tab', { + active: activeTab === tabsMapping.WORKSPACE + })} + onClick={() => onTabClick(tabsMapping.WORKSPACE)} + data-test-id="onboard-workspace-tab"> + {i18n('WORKSPACE')} + </div> + <div + className={classnames('onboard-header-tab', { + active: activeTab === tabsMapping.CATALOG + })} + onClick={() => onTabClick(tabsMapping.CATALOG)} + data-test-id="onboard-onboard-tab"> + {i18n('ONBOARD CATALOG')} + </div> + </div> ); -const OnboardHeader = ({onSearch, activeTab, onTabClick, searchValue}) => ( - <div className='onboard-header'> - <OnboardHeaderTabs activeTab={activeTab} onTabClick={onTabClick} /> - <ExpandableInput - onChange={onSearch} - iconType='search' - value={searchValue}/> - <NotificationsView /> - </div> +const OnboardHeader = ({ onSearch, activeTab, onTabClick, searchValue }) => ( + <div className="onboard-header"> + <OnboardHeaderTabs activeTab={activeTab} onTabClick={onTabClick} /> + <ExpandableInput + onChange={onSearch} + iconType="search" + value={searchValue} + /> + <NotificationsView /> + </div> ); class OnboardView extends React.Component { - static propTypes = { - licenseModelList: PropTypes.array, - softwareProductList: PropTypes.array, - finalizedLicenseModelList: PropTypes.array, - finalizedSoftwareProductList: PropTypes.array, - archivedSoftwareProductList: PropTypes.array, - archivedLicenseModelList: PropTypes.array, - modalToShow: PropTypes.oneOf(objectValues(catalogItemTypes)), - onSelectLicenseModel: PropTypes.func.isRequired, - onSelectSoftwareProduct: PropTypes.func.isRequired, - onAddLicenseModelClick: PropTypes.func.isRequired, - onAddSoftwareProductClick: PropTypes.func.isRequired, - closeVspOverlay: PropTypes.func.isRequired, - onVspOverlayChange: PropTypes.func.isRequired, - onTabClick: PropTypes.func.isRequired, - onCatalogTabClick: PropTypes.func.isRequired, - onSearch: PropTypes.func.isRequired, - activeTab: PropTypes.number.isRequired, - catalogActiveTab: PropTypes.number.isRequired, - searchValue: PropTypes.string.isRequired, - onMigrate: PropTypes.func.isRequired, - }; - renderViewByTab(activeTab){ - switch (activeTab){ - case tabsMapping.WORKSPACE: - return <WorkspaceView {...this.props} />; - case tabsMapping.CATALOG: - return <OnboardingCatalogView {...this.props} />; - default: - return <WorkspaceView {...this.props} />; - } - } + static propTypes = { + licenseModelList: PropTypes.array, + softwareProductList: PropTypes.array, + finalizedLicenseModelList: PropTypes.array, + finalizedSoftwareProductList: PropTypes.array, + archivedSoftwareProductList: PropTypes.array, + archivedLicenseModelList: PropTypes.array, + modalToShow: PropTypes.oneOf(objectValues(catalogItemTypes)), + onSelectLicenseModel: PropTypes.func.isRequired, + onSelectSoftwareProduct: PropTypes.func.isRequired, + onAddLicenseModelClick: PropTypes.func.isRequired, + onAddSoftwareProductClick: PropTypes.func.isRequired, + closeVspOverlay: PropTypes.func.isRequired, + onVspOverlayChange: PropTypes.func.isRequired, + onTabClick: PropTypes.func.isRequired, + onCatalogTabClick: PropTypes.func.isRequired, + onSearch: PropTypes.func.isRequired, + activeTab: PropTypes.number.isRequired, + catalogActiveTab: PropTypes.number.isRequired, + searchValue: PropTypes.string.isRequired, + onMigrate: PropTypes.func.isRequired + }; + renderViewByTab(activeTab) { + switch (activeTab) { + case tabsMapping.WORKSPACE: + return <WorkspaceView {...this.props} />; + case tabsMapping.CATALOG: + return <OnboardingCatalogView {...this.props} />; + default: + return <WorkspaceView {...this.props} />; + } + } - render() { - let {activeTab, onTabClick, onSearch, searchValue} = this.props; - return ( - <div className='catalog-view'> - <Filter/> - <div className='catalog-parts'> - <OnboardHeader activeTab={activeTab} onTabClick={onTabClick} searchValue={searchValue} onSearch={value => onSearch(value)}/> - {this.renderViewByTab(activeTab)} - </div> - </div> - ); - } + render() { + let { activeTab, onTabClick, onSearch, searchValue } = this.props; + return ( + <div className="catalog-view"> + <Filter /> + <div className="catalog-parts"> + <OnboardHeader + activeTab={activeTab} + onTabClick={onTabClick} + searchValue={searchValue} + onSearch={value => onSearch(value)} + /> + {this.renderViewByTab(activeTab)} + </div> + </div> + ); + } } export default OnboardView; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx index d8d04f242b..c80232de0a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/Filter.jsx @@ -14,83 +14,166 @@ * limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import React from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Input from 'nfvo-components/input/validation/Input.jsx'; import Accordion from 'nfvo-components/accordion/Accordion.jsx'; -import {actionTypes} from './FilterConstants.js'; +import { actionTypes } from './FilterConstants.js'; import featureToggle from 'sdc-app/features/featureToggle.js'; -import {featureToggleNames} from 'sdc-app/features/FeaturesConstants.js'; -import {tabsMapping as onboardTabsMapping} from '../OnboardConstants.js'; -import {itemsType as itemsTypeConstants} from './FilterConstants.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; +import { tabsMapping as onboardTabsMapping } from '../OnboardConstants.js'; +import { itemsType as itemsTypeConstants } from './FilterConstants.js'; -const mapStateToProps = ({onboard: {filter, activeTab}}) => { - return { - data: filter, - activeTab - }; +const mapStateToProps = ({ onboard: { filter, activeTab } }) => { + return { + data: filter, + activeTab + }; }; -const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData) => - dispatch({ - type: actionTypes.FILTER_DATA_CHANGED, - deltaData - }) - }; +const mapActionsToProps = dispatch => { + return { + onDataChanged: deltaData => + dispatch({ + type: actionTypes.FILTER_DATA_CHANGED, + deltaData + }) + }; }; -const Filter = ({onDataChanged, data: {entityTypeVsp, entityTypeVlm, roleOwner, roleContributor, roleViewer, - procedureNetwork, procedureManual, recentlyUpdated, byVendorView, itemsType}, activeTab}) => ( - <div className='catalog-filter'> - {activeTab === onboardTabsMapping.CATALOG && <Input - type='select' - className='catalog-filter-items-type' - data-test-id='catalog-filter-items-type' - disabled={byVendorView} - value={itemsType} - onChange={e => onDataChanged({itemsType: e.target.value})}> - <option key={itemsTypeConstants.ACTIVE} value={itemsTypeConstants.ACTIVE}>Active Items</option> - <option key={itemsTypeConstants.ARCHIVED} value={itemsTypeConstants.ARCHIVED}>Archived Items</option> - </Input>} - {activeTab === onboardTabsMapping.CATALOG && <Input - label={i18n('By Vendor View')} - type='checkbox' - disabled={itemsType === itemsTypeConstants.ARCHIVED} - checked={byVendorView} - onChange={byVendorView => onDataChanged({byVendorView})} - data-test-id='filter-by-vendor-view' value='' /> - } - <Input label={i18n('Recently Updated')} type='checkbox' checked={recentlyUpdated} - onChange={recentlyUpdated => onDataChanged({recentlyUpdated})} data-test-id='filter-recently-updated' value='' /> +const Filter = ({ + onDataChanged, + data: { + entityTypeVsp, + entityTypeVlm, + roleOwner, + roleContributor, + roleViewer, + procedureNetwork, + procedureManual, + recentlyUpdated, + byVendorView, + itemsType + }, + activeTab +}) => ( + <div className="catalog-filter"> + {activeTab === onboardTabsMapping.CATALOG && ( + <Input + type="select" + className="catalog-filter-items-type" + data-test-id="catalog-filter-items-type" + disabled={byVendorView} + value={itemsType} + onChange={e => onDataChanged({ itemsType: e.target.value })}> + <option + key={itemsTypeConstants.ACTIVE} + value={itemsTypeConstants.ACTIVE}> + Active Items + </option> + <option + key={itemsTypeConstants.ARCHIVED} + value={itemsTypeConstants.ARCHIVED}> + Archived Items + </option> + </Input> + )} + {activeTab === onboardTabsMapping.CATALOG && ( + <Input + label={i18n('By Vendor View')} + type="checkbox" + disabled={itemsType === itemsTypeConstants.ARCHIVED} + checked={byVendorView} + onChange={byVendorView => onDataChanged({ byVendorView })} + data-test-id="filter-by-vendor-view" + value="" + /> + )} + <Input + label={i18n('Recently Updated')} + type="checkbox" + checked={recentlyUpdated} + onChange={recentlyUpdated => onDataChanged({ recentlyUpdated })} + data-test-id="filter-recently-updated" + value="" + /> - <Accordion title={i18n('ENTITY TYPE')}> - <Input label={i18n('VSP')} type='checkbox' checked={entityTypeVsp} onChange={entityTypeVsp => onDataChanged({entityTypeVsp})} data-test-id='filter-type-vsp' value='' /> - <Input label={i18n('VLM')} type='checkbox' checked={entityTypeVlm} onChange={entityTypeVlm => onDataChanged({entityTypeVlm})} data-test-id='filter-type-vlm' value='' /> - </Accordion> + <Accordion title={i18n('ENTITY TYPE')}> + <Input + label={i18n('VSP')} + type="checkbox" + checked={entityTypeVsp} + onChange={entityTypeVsp => onDataChanged({ entityTypeVsp })} + data-test-id="filter-type-vsp" + value="" + /> + <Input + label={i18n('VLM')} + type="checkbox" + checked={entityTypeVlm} + onChange={entityTypeVlm => onDataChanged({ entityTypeVlm })} + data-test-id="filter-type-vlm" + value="" + /> + </Accordion> - <Accordion title={i18n('ROLE')}> - <Input label={i18n('Owner')} type='checkbox' checked={roleOwner} onChange={roleOwner => onDataChanged({roleOwner})} data-test-id='filter-role-owner' value='' /> - <Input label={i18n('Contributer')} type='checkbox' checked={roleContributor} - onChange={roleContributor => onDataChanged({roleContributor})} data-test-id='filter-role-contributor' value='' /> - <Input label={i18n('Viewer')} type='checkbox' checked={roleViewer} onChange={roleViewer => onDataChanged({roleViewer})} data-test-id='filter-role-viewr' value='' /> - </Accordion> - - <Accordion title={i18n('ONBOARDING PROCEDURE')}> - <Input label={i18n('Network Package')} type='checkbox' checked={procedureNetwork} - onChange={procedureNetwork => onDataChanged({procedureNetwork})} data-test-id='filter-procedure-network' value='' /> - <Input label={i18n('Manual')} type='checkbox' checked={procedureManual} - onChange={procedureManual => onDataChanged({procedureManual})} data-test-id='filter-procedure-manual' value='' /> - </Accordion> + <Accordion title={i18n('ROLE')}> + <Input + label={i18n('Owner')} + type="checkbox" + checked={roleOwner} + onChange={roleOwner => onDataChanged({ roleOwner })} + data-test-id="filter-role-owner" + value="" + /> + <Input + label={i18n('Contributer')} + type="checkbox" + checked={roleContributor} + onChange={roleContributor => onDataChanged({ roleContributor })} + data-test-id="filter-role-contributor" + value="" + /> + <Input + label={i18n('Viewer')} + type="checkbox" + checked={roleViewer} + onChange={roleViewer => onDataChanged({ roleViewer })} + data-test-id="filter-role-viewr" + value="" + /> + </Accordion> + + <Accordion title={i18n('ONBOARDING PROCEDURE')}> + <Input + label={i18n('Network Package')} + type="checkbox" + checked={procedureNetwork} + onChange={procedureNetwork => + onDataChanged({ procedureNetwork }) + } + data-test-id="filter-procedure-network" + value="" + /> + <Input + label={i18n('Manual')} + type="checkbox" + checked={procedureManual} + onChange={procedureManual => onDataChanged({ procedureManual })} + data-test-id="filter-procedure-manual" + value="" + /> + </Accordion> </div> ); Filter.PropTypes = { - onDataChanged: PropTypes.func, - data: PropTypes.object + onDataChanged: PropTypes.func, + data: PropTypes.object }; -export default featureToggle(featureToggleNames.FILTER)(connect(mapStateToProps, mapActionsToProps)(Filter)); +export default featureToggle(featureToggleNames.FILTER)( + connect(mapStateToProps, mapActionsToProps)(Filter) +); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js index d944cb02fb..edfe592877 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterConstants.js @@ -17,10 +17,10 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FILTER_DATA_CHANGED: null + FILTER_DATA_CHANGED: null }); export const itemsType = { - ACTIVE: '1', - ARCHIVED: '2' -};
\ No newline at end of file + ACTIVE: '1', + ARCHIVED: '2' +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js index 963226cd38..f1e857498a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/filter/FilterReducer.js @@ -13,16 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {actionTypes} from './FilterConstants.js'; +import { actionTypes } from './FilterConstants.js'; -export default (state = {}, action) => { - switch (action.type) { - case actionTypes.FILTER_DATA_CHANGED: - return { - ...state, - ...action.deltaData - }; - default: - return state; - } +export default (state = {}, action) => { + switch (action.type) { + case actionTypes.FILTER_DATA_CHANGED: + return { + ...state, + ...action.deltaData + }; + default: + return state; + } }; 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 a85c79edd9..aebb829a88 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogActionHelper.js @@ -15,69 +15,88 @@ */ import React from 'react'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes} from './OnboardingCatalogConstants.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './OnboardingCatalogConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import OnboardActionHelper from '../OnboardActionHelper.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; - function getMessageForMigration(name) { - return ( - <div> - <div>{i18n('{name} needs to be updated. Click ‘Checkout & Update’, to proceed.', {name: name})}</div> - <div>{i18n('Please don’t forget to submit afterwards')}</div> - </div> - ); + return ( + <div> + <div> + {i18n( + '{name} needs to be updated. Click ‘Checkout & Update’, to proceed.', + { name: name } + )} + </div> + <div>{i18n('Please don’t forget to submit afterwards')}</div> + </div> + ); } const OnboardingCatalogActionHelper = { - changeVspOverlay(dispatch, vendor) { - dispatch({ - type: actionTypes.CHANGE_VSP_OVERLAY, - vendorId: vendor ? vendor.id : null - }); - }, - closeVspOverlay(dispatch) { - dispatch({ - type: actionTypes.CLOSE_VSP_OVERLAY - }); - }, - changeActiveTab(dispatch, activeTab) { - OnboardActionHelper.clearSearchValue(dispatch); - dispatch({ - type: actionTypes.CHANGE_ACTIVE_CATALOG_TAB, - activeTab - }); - }, - onVendorSelect(dispatch, {vendor}) { - OnboardActionHelper.clearSearchValue(dispatch); - dispatch({ - type: actionTypes.ONBOARDING_CATALOG_OPEN_VENDOR_PAGE, - selectedVendor: vendor - }); - }, - onMigrate(dispatch, softwareProduct) { - const {name, lockingUser} = softwareProduct; - if (NaN === NaN) { // TODO - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: 'WARNING', - msg: i18n('{name} is locked by user {lockingUser} for self-healing', {name: name, lockingUser: lockingUser}) - } - }); - } else { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - title: 'WARNING', - msg: getMessageForMigration(softwareProduct.name.toUpperCase()), - confirmationButtonText: i18n('Checkout & Update'), - onConfirmed: ()=>SoftwareProductActionHelper.migrateSoftwareProduct(dispatch, {softwareProduct}) - } - }); - } - } + changeVspOverlay(dispatch, vendor) { + dispatch({ + type: actionTypes.CHANGE_VSP_OVERLAY, + vendorId: vendor ? vendor.id : null + }); + }, + closeVspOverlay(dispatch) { + dispatch({ + type: actionTypes.CLOSE_VSP_OVERLAY + }); + }, + changeActiveTab(dispatch, activeTab) { + OnboardActionHelper.clearSearchValue(dispatch); + dispatch({ + type: actionTypes.CHANGE_ACTIVE_CATALOG_TAB, + activeTab + }); + }, + onVendorSelect(dispatch, { vendor }) { + OnboardActionHelper.clearSearchValue(dispatch); + dispatch({ + type: actionTypes.ONBOARDING_CATALOG_OPEN_VENDOR_PAGE, + selectedVendor: vendor + }); + }, + onMigrate(dispatch, softwareProduct) { + const { name, lockingUser } = softwareProduct; + if (NaN === NaN) { + // TODO + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: 'WARNING', + msg: i18n( + '{name} is locked by user {lockingUser} for self-healing', + { + name: name, + lockingUser: lockingUser + } + ) + } + }); + } else { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: 'WARNING', + msg: getMessageForMigration( + softwareProduct.name.toUpperCase() + ), + confirmationButtonText: i18n('Checkout & Update'), + onConfirmed: () => + SoftwareProductActionHelper.migrateSoftwareProduct( + dispatch, + { + softwareProduct + } + ) + } + }); + } + } }; export default OnboardingCatalogActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js index 239ae4545f..f0cefdcde3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js @@ -16,41 +16,41 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const catalogItemTypes = Object.freeze({ - LICENSE_MODEL: 'license-model', - SOFTWARE_PRODUCT: 'software-product' + LICENSE_MODEL: 'license-model', + SOFTWARE_PRODUCT: 'software-product' }); export const catalogItemTypeClasses = { - LICENSE_MODEL: 'license-model-type', - SOFTWARE_PRODUCT: 'software-product-type', - VENDOR: 'vendor-type' + LICENSE_MODEL: 'license-model-type', + SOFTWARE_PRODUCT: 'software-product-type', + VENDOR: 'vendor-type' }; export const catalogItemStatuses = { - DRAFT: 'Draft', - CERTIFIED: 'Certified', - ARCHIVED: 'ARCHIVED' + DRAFT: 'Draft', + CERTIFIED: 'Certified', + ARCHIVED: 'ARCHIVED' }; export const modalMapper = { - 'license-model': 'LICENSE_MODEL', - 'software-product': 'SOFTWARE_PRODUCT' + 'license-model': 'LICENSE_MODEL', + 'software-product': 'SOFTWARE_PRODUCT' }; export const tabsMapping = { - 'BY_VENDOR': 1, - 'ACTIVE': 2, - 'ARCHIVE': 3 + BY_VENDOR: 1, + ACTIVE: 2, + ARCHIVE: 3 }; export const migrationStatusMapper = { - OLD_VERSION: 'True', + OLD_VERSION: 'True' }; export const actionTypes = keyMirror({ - ONBOARDING_CATALOG_OPEN_VENDOR_PAGE: null, - CHANGE_ACTIVE_CATALOG_TAB: null, - CHANGE_SEARCH_VALUE: null, - CHANGE_VSP_OVERLAY: null, - CLOSE_VSP_OVERLAY: null + ONBOARDING_CATALOG_OPEN_VENDOR_PAGE: null, + CHANGE_ACTIVE_CATALOG_TAB: null, + CHANGE_SEARCH_VALUE: null, + CHANGE_VSP_OVERLAY: null, + CLOSE_VSP_OVERLAY: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogReducer.js index 3f8a833074..9796cf8918 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogReducer.js @@ -13,18 +13,21 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import {actionTypes, tabsMapping} from './OnboardingCatalogConstants.js'; -import {combineReducers} from 'redux'; +import { actionTypes, tabsMapping } from './OnboardingCatalogConstants.js'; +import { combineReducers } from 'redux'; import vendorCatalogReducer from './VendorCatalogReducer.js'; const onboardingCatalogReducer = combineReducers({ - vendorCatalog: vendorCatalogReducer, - activeTab: (state = tabsMapping.ACTIVE, action) => action.type === actionTypes.CHANGE_ACTIVE_CATALOG_TAB ? action.activeTab : state + vendorCatalog: vendorCatalogReducer, + activeTab: (state = tabsMapping.ACTIVE, action) => + action.type === actionTypes.CHANGE_ACTIVE_CATALOG_TAB + ? action.activeTab + : state }); export default (state, action) => { - if (action.type === actionTypes.RESET_ONBOARDING_CATALOG_STORE) { - state = undefined; - } - return onboardingCatalogReducer(state, action); + if (action.type === actionTypes.RESET_ONBOARDING_CATALOG_STORE) { + state = undefined; + } + return onboardingCatalogReducer(state, action); }; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogUtils.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogUtils.js index 78258255ec..d1e401f57d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogUtils.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogUtils.js @@ -14,6 +14,8 @@ * permissions and limitations under the License. */ -export const filterCatalogItemsByType = ({items, filter}) => { - return items.filter(item => item.name.toLowerCase().indexOf(filter.toLowerCase()) > -1); +export const filterCatalogItemsByType = ({ items, filter }) => { + return items.filter( + item => item.name.toLowerCase().indexOf(filter.toLowerCase()) > -1 + ); }; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx index 8ae8549688..2cc32c2936 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogView.jsx @@ -18,120 +18,202 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import classnames from 'classnames'; import DetailsCatalogView from 'sdc-app/onboarding/onboard/DetailsCatalogView.jsx'; import VendorCatalogView from './VendorCatalogView.jsx'; -import { tabsMapping} from './OnboardingCatalogConstants.js'; -import {tabsMapping as WCTabsMapping} from 'sdc-app/onboarding/onboard/OnboardConstants.js'; +import { tabsMapping } from './OnboardingCatalogConstants.js'; +import { tabsMapping as WCTabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; import featureToggle from 'sdc-app/features/featureToggle.js'; -import {featureToggleNames} from 'sdc-app/features/FeaturesConstants.js'; +import { featureToggleNames } from 'sdc-app/features/FeaturesConstants.js'; -const Separator = () => ( - <div className='tab-separator'/> -); +const Separator = () => <div className="tab-separator" />; -const Tab = ({onTabPress, title, dataTestId, activeTab, tabMapping}) => ( - <div - className={classnames('catalog-header-tab', {'active': activeTab === tabMapping })} - onClick={() => onTabPress(tabMapping)} - data-test-id={dataTestId}> - {title} - </div> +const Tab = ({ onTabPress, title, dataTestId, activeTab, tabMapping }) => ( + <div + className={classnames('catalog-header-tab', { + active: activeTab === tabMapping + })} + onClick={() => onTabPress(tabMapping)} + data-test-id={dataTestId}> + {title} + </div> ); const ArchiveTab = featureToggle(featureToggleNames.ARCHIVE_ITEM)(Tab); -const ArchiveTabSeparator = featureToggle(featureToggleNames.ARCHIVE_ITEM)(Separator); +const ArchiveTabSeparator = featureToggle(featureToggleNames.ARCHIVE_ITEM)( + Separator +); -const CatalogHeaderTabs = (props) => ( - <div className='catalog-header-tabs'> - <Tab {...props} title={i18n('ACTIVE')} dataTestId='catalog-all-tab' tabMapping={tabsMapping.ACTIVE}/> - <Separator/> - <Tab {...props} title={i18n('BY VENDOR')} dataTestId='catalog-header-tab' tabMapping={tabsMapping.BY_VENDOR}/> - <ArchiveTabSeparator/> - <ArchiveTab {...props} title={i18n('ARCHIVE')} dataTestId='catalog-archive-tab' tabMapping={tabsMapping.ARCHIVE}/> - </div> +const CatalogHeaderTabs = props => ( + <div className="catalog-header-tabs"> + <Tab + {...props} + title={i18n('ACTIVE')} + dataTestId="catalog-all-tab" + tabMapping={tabsMapping.ACTIVE} + /> + <Separator /> + <Tab + {...props} + title={i18n('BY VENDOR')} + dataTestId="catalog-header-tab" + tabMapping={tabsMapping.BY_VENDOR} + /> + <ArchiveTabSeparator /> + <ArchiveTab + {...props} + title={i18n('ARCHIVE')} + dataTestId="catalog-archive-tab" + tabMapping={tabsMapping.ARCHIVE} + /> + </div> ); -const CatalogHeader = ({activeTab, onTabPress}) => ( - <div className='catalog-header'> - <CatalogHeaderTabs activeTab={activeTab} onTabPress={onTabPress} /> - </div> +const CatalogHeader = ({ activeTab, onTabPress }) => ( + <div className="catalog-header"> + <CatalogHeaderTabs activeTab={activeTab} onTabPress={onTabPress} /> + </div> ); const FilterCatalogHeader = () => ( - <div className='catalog-header'> - <div className='catalog-header-tabs'> - <div className='catalog-header-tab active'> - {i18n('ONBOARD CATALOG')} - </div> - </div> - </div> + <div className="catalog-header"> + <div className="catalog-header-tabs"> + <div className="catalog-header-tab active"> + {i18n('ONBOARD CATALOG')} + </div> + </div> + </div> ); - -const FeaturedCatalogHeader = featureToggle(featureToggleNames.FILTER)({AComp: FilterCatalogHeader, BComp: CatalogHeader}); +const FeaturedCatalogHeader = featureToggle(featureToggleNames.FILTER)({ + AComp: FilterCatalogHeader, + BComp: CatalogHeader +}); class OnboardingCatalogView extends React.Component { - renderViewByTab(activeTab){ - const {finalizedLicenseModelList: licenseModelList, fullLicenseModelList, users, vspOverlay, finalizedSoftwareProductList: softwareProductList, onSelectLicenseModel, onSelectSoftwareProduct, - onAddLicenseModelClick, onAddSoftwareProductClick, onVspOverlayChange, onVendorSelect, selectedVendor, searchValue, onMigrate, - archivedSoftwareProductList, archivedLicenseModelList} = this.props; + renderViewByTab(activeTab) { + const { + finalizedLicenseModelList: licenseModelList, + fullLicenseModelList, + users, + vspOverlay, + finalizedSoftwareProductList: softwareProductList, + onSelectLicenseModel, + onSelectSoftwareProduct, + onAddLicenseModelClick, + onAddSoftwareProductClick, + onVspOverlayChange, + onVendorSelect, + selectedVendor, + searchValue, + onMigrate, + archivedSoftwareProductList, + archivedLicenseModelList + } = this.props; - switch (activeTab){ - case tabsMapping.ARCHIVE: - return ( - <DetailsCatalogView - VLMList={archivedLicenseModelList} - VSPList={archivedSoftwareProductList} - users={users} - onSelectVLM={(item, users) => onSelectLicenseModel(item, users, WCTabsMapping.CATALOG)} - onSelectVSP={(item, users) => onSelectSoftwareProduct(item, users, WCTabsMapping.CATALOG)} - filter={searchValue} - onMigrate={onMigrate}/> - ); - case tabsMapping.ACTIVE: - return ( - <DetailsCatalogView - VLMList={licenseModelList} - VSPList={softwareProductList} - users={users} - onAddVLM={onAddLicenseModelClick} - onAddVSP={onAddSoftwareProductClick} - onSelectVLM={(item, users) => onSelectLicenseModel(item, users, WCTabsMapping.CATALOG)} - onSelectVSP={(item, users) => onSelectSoftwareProduct(item, users, WCTabsMapping.CATALOG)} - filter={searchValue} - onMigrate={onMigrate}/> - ); - case tabsMapping.BY_VENDOR: - default: - return ( - <VendorCatalogView - licenseModelList={fullLicenseModelList} - users={users} - onAddVSP={onAddSoftwareProductClick} - onAddVLM={onAddLicenseModelClick} - onSelectVSP={(item, users) => onSelectSoftwareProduct(item, users, WCTabsMapping.CATALOG)} - onSelectVLM={(item, users) => onSelectLicenseModel(item, users, WCTabsMapping.CATALOG)} - vspOverlay={vspOverlay} - onVendorSelect={onVendorSelect} - selectedVendor={selectedVendor} - onVspOverlayChange={onVspOverlayChange} - onMigrate={onMigrate} - filter={searchValue}/> - ); - } - } + switch (activeTab) { + case tabsMapping.ARCHIVE: + return ( + <DetailsCatalogView + VLMList={archivedLicenseModelList} + VSPList={archivedSoftwareProductList} + users={users} + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + filter={searchValue} + onMigrate={onMigrate} + /> + ); + case tabsMapping.ACTIVE: + return ( + <DetailsCatalogView + VLMList={licenseModelList} + VSPList={softwareProductList} + users={users} + onAddVLM={onAddLicenseModelClick} + onAddVSP={onAddSoftwareProductClick} + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + filter={searchValue} + onMigrate={onMigrate} + /> + ); + case tabsMapping.BY_VENDOR: + default: + return ( + <VendorCatalogView + licenseModelList={fullLicenseModelList} + users={users} + onAddVSP={onAddSoftwareProductClick} + onAddVLM={onAddLicenseModelClick} + onSelectVSP={(item, users) => + onSelectSoftwareProduct( + item, + users, + WCTabsMapping.CATALOG + ) + } + onSelectVLM={(item, users) => + onSelectLicenseModel( + item, + users, + WCTabsMapping.CATALOG + ) + } + vspOverlay={vspOverlay} + onVendorSelect={onVendorSelect} + selectedVendor={selectedVendor} + onVspOverlayChange={onVspOverlayChange} + onMigrate={onMigrate} + filter={searchValue} + /> + ); + } + } - render() { - const {selectedVendor, catalogActiveTab: activeTab, onCatalogTabClick, onSearch, searchValue} = this.props; - return ( - <div className='catalog-wrapper'> - {!selectedVendor && <FeaturedCatalogHeader - onSearch={event => onSearch(event.target.value)} - activeTab={activeTab} - onTabPress={tab => onCatalogTabClick(tab)} - searchValue={searchValue}/>} - {this.renderViewByTab(activeTab)} - </div> - ); - } + render() { + const { + selectedVendor, + catalogActiveTab: activeTab, + onCatalogTabClick, + onSearch, + searchValue + } = this.props; + return ( + <div className="catalog-wrapper"> + {!selectedVendor && ( + <FeaturedCatalogHeader + onSearch={event => onSearch(event.target.value)} + activeTab={activeTab} + onTabPress={tab => onCatalogTabClick(tab)} + searchValue={searchValue} + /> + )} + {this.renderViewByTab(activeTab)} + </div> + ); + } } export default OnboardingCatalogView; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/Tooltip.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/Tooltip.jsx index 80d9b07ac9..2f00bf95ed 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/Tooltip.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/Tooltip.jsx @@ -19,13 +19,27 @@ import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; const tooltip = (msg, className = '') => ( - <Tooltip className={className} id={className}>{msg}</Tooltip> + <Tooltip className={className} id={className}> + {msg} + </Tooltip> ); -export const TooltipWrapper = ({placement = 'top', className = '', tooltipClassName = '', dataTestId, delayShow = 0, children}) => ( - <OverlayTrigger placement={placement} overlay={tooltip(children, tooltipClassName)} delayShow={delayShow}> - <div className={className} data-test-id={dataTestId}>{children}</div> - </OverlayTrigger> +export const TooltipWrapper = ({ + placement = 'top', + className = '', + tooltipClassName = '', + dataTestId, + delayShow = 0, + children +}) => ( + <OverlayTrigger + placement={placement} + overlay={tooltip(children, tooltipClassName)} + delayShow={delayShow}> + <div className={className} data-test-id={dataTestId}> + {children} + </div> + </OverlayTrigger> ); export default tooltip; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VSPOverlay.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VSPOverlay.jsx index a2852e5afa..c2eb8250f8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VSPOverlay.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VSPOverlay.jsx @@ -16,36 +16,52 @@ import React from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {migrationStatusMapper} from './OnboardingCatalogConstants.js'; +import { migrationStatusMapper } from './OnboardingCatalogConstants.js'; -const VSPOverlay = ({VSPList, onSelectVSP, onSeeMore, onMigrate}) => ( - <div className='vsp-overlay-wrapper' onClick={(e) => { - e.stopPropagation(); - e.preventDefault(); - }}> - <div className='vsp-overlay-arrow'></div> - <div className='vsp-overlay'> - <div className='vsp-overlay-title'>{i18n('Recently Edited')}</div> - <div className='vsp-overlay-list'> - {VSPList.slice(0, 5).map(vsp => <div key={vsp.id} className='vsp-overlay-detail' onClick={() => { - if (vsp.isOldVersion && vsp.isOldVersion === migrationStatusMapper.OLD_VERSION) { - onMigrate({ - softwareProduct: vsp - }); - } else { - onSelectVSP(vsp); - } - } - }>{i18n(vsp.name)}</div>)} - </div> - {VSPList.length > 5 && <div className='vsp-overlay-see-more' onClick={onSeeMore}>{i18n('See More')}</div>} - </div> - </div> +const VSPOverlay = ({ VSPList, onSelectVSP, onSeeMore, onMigrate }) => ( + <div + className="vsp-overlay-wrapper" + onClick={e => { + e.stopPropagation(); + e.preventDefault(); + }}> + <div className="vsp-overlay-arrow" /> + <div className="vsp-overlay"> + <div className="vsp-overlay-title">{i18n('Recently Edited')}</div> + <div className="vsp-overlay-list"> + {VSPList.slice(0, 5).map(vsp => ( + <div + key={vsp.id} + className="vsp-overlay-detail" + onClick={() => { + if ( + vsp.isOldVersion && + vsp.isOldVersion === + migrationStatusMapper.OLD_VERSION + ) { + onMigrate({ + softwareProduct: vsp + }); + } else { + onSelectVSP(vsp); + } + }}> + {i18n(vsp.name)} + </div> + ))} + </div> + {VSPList.length > 5 && ( + <div className="vsp-overlay-see-more" onClick={onSeeMore}> + {i18n('See More')} + </div> + )} + </div> + </div> ); VSPOverlay.PropTypes = { - VSPList: PropTypes.array, - onSelectVSP: PropTypes.func + VSPList: PropTypes.array, + onSelectVSP: PropTypes.func }; export default VSPOverlay; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogReducer.js b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogReducer.js index dd8b41bd22..2d22a2db90 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogReducer.js @@ -13,26 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './OnboardingCatalogConstants.js'; +import { actionTypes } from './OnboardingCatalogConstants.js'; export default (state = {}, action) => { - switch(action.type) { - case actionTypes.ONBOARDING_CATALOG_OPEN_VENDOR_PAGE: - return { - ...state, - selectedVendor: action.selectedVendor - }; - case actionTypes.CHANGE_VSP_OVERLAY: - return { - ...state, - vspOverlay: action.vendorId - }; - case actionTypes.CLOSE_VSP_OVERLAY: - return { - ...state, - vspOverlay: null - }; - default: - return state; - } + switch (action.type) { + case actionTypes.ONBOARDING_CATALOG_OPEN_VENDOR_PAGE: + return { + ...state, + selectedVendor: action.selectedVendor + }; + case actionTypes.CHANGE_VSP_OVERLAY: + return { + ...state, + vspOverlay: action.vendorId + }; + case actionTypes.CLOSE_VSP_OVERLAY: + return { + ...state, + vspOverlay: null + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogView.jsx index 9914ea2154..02f8d50c5c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorCatalogView.jsx @@ -17,58 +17,100 @@ import React from 'react'; import VendorItem from './VendorItem.jsx'; import CatalogList from '../CatalogList.jsx'; import CatalogItemDetails from '../CatalogItemDetails.jsx'; -import {catalogItemTypes} from './OnboardingCatalogConstants.js'; -import {filterCatalogItemsByType} from './OnboardingCatalogUtils.js'; +import { catalogItemTypes } from './OnboardingCatalogConstants.js'; +import { filterCatalogItemsByType } from './OnboardingCatalogUtils.js'; -const VendorList = ({onAddVLM, onAddVSP, onSelectVSP, licenseModelList = [], vspOverlay: currentOverlay, onVspOverlayChange, onVendorSelect, filter, onMigrate, users}) => { - return( - <CatalogList onAddVLM={onAddVLM} onAddVSP={onAddVSP}> - { - filterCatalogItemsByType({items: licenseModelList, filter}).map(vlm => - <VendorItem - key={vlm.id} - onAddVSP={onAddVSP} - onSelectVSP={(vsp) => onSelectVSP(vsp, users)} - shouldShowOverlay={currentOverlay === vlm.id} - onVSPButtonClick={(hasVSP) => onVspOverlayChange(vlm.id === currentOverlay || !hasVSP ? null : vlm)} - onVendorSelect={onVendorSelect} - onMigrate={onMigrate} - vendor={vlm}/>) - } - </CatalogList> - ); +const VendorList = ({ + onAddVLM, + onAddVSP, + onSelectVSP, + licenseModelList = [], + vspOverlay: currentOverlay, + onVspOverlayChange, + onVendorSelect, + filter, + onMigrate, + users +}) => { + return ( + <CatalogList onAddVLM={onAddVLM} onAddVSP={onAddVSP}> + {filterCatalogItemsByType({ items: licenseModelList, filter }).map( + vlm => ( + <VendorItem + key={vlm.id} + onAddVSP={onAddVSP} + onSelectVSP={vsp => onSelectVSP(vsp, users)} + shouldShowOverlay={currentOverlay === vlm.id} + onVSPButtonClick={hasVSP => + onVspOverlayChange( + vlm.id === currentOverlay || !hasVSP + ? null + : vlm + ) + } + onVendorSelect={onVendorSelect} + onMigrate={onMigrate} + vendor={vlm} + /> + ) + )} + </CatalogList> + ); }; -const SoftwareProductListByVendor = ({onAddVSP, selectedVendor, onVendorSelect, onSelectVSP, onSelectVLM, filter, onMigrate, users}) => { - return( - <div> - <CatalogList onAddVSP={()=>{onAddVSP(selectedVendor.id);}} vendorPageOptions={{selectedVendor, onBack: () => onVendorSelect(false)}}> - <CatalogItemDetails - key={selectedVendor.id} - onSelect={() => onSelectVLM(selectedVendor, users)} - catalogItemTypeClass={catalogItemTypes.LICENSE_MODEL} - onMigrate={onMigrate} - catalogItemData={selectedVendor}/> - { - filterCatalogItemsByType({items: selectedVendor.softwareProductList, filter}).map(vsp => - <CatalogItemDetails - key={vsp.id} - catalogItemTypeClass={catalogItemTypes.SOFTWARE_PRODUCT} - onMigrate={onMigrate} - onSelect={() => onSelectVSP(vsp, users)} - catalogItemData={vsp}/> - ) - } - </CatalogList> - </div> - ); +const SoftwareProductListByVendor = ({ + onAddVSP, + selectedVendor, + onVendorSelect, + onSelectVSP, + onSelectVLM, + filter, + onMigrate, + users +}) => { + return ( + <div> + <CatalogList + onAddVSP={() => { + onAddVSP(selectedVendor.id); + }} + vendorPageOptions={{ + selectedVendor, + onBack: () => onVendorSelect(false) + }}> + <CatalogItemDetails + key={selectedVendor.id} + onSelect={() => onSelectVLM(selectedVendor, users)} + catalogItemTypeClass={catalogItemTypes.LICENSE_MODEL} + onMigrate={onMigrate} + catalogItemData={selectedVendor} + /> + {filterCatalogItemsByType({ + items: selectedVendor.softwareProductList, + filter + }).map(vsp => ( + <CatalogItemDetails + key={vsp.id} + catalogItemTypeClass={catalogItemTypes.SOFTWARE_PRODUCT} + onMigrate={onMigrate} + onSelect={() => onSelectVSP(vsp, users)} + catalogItemData={vsp} + /> + ))} + </CatalogList> + </div> + ); }; class VendorCatalogView extends React.Component { - render() { - let {selectedVendor} = this.props; - return( selectedVendor ? <SoftwareProductListByVendor {...this.props}/> : <VendorList {...this.props}/>); - } + render() { + let { selectedVendor } = this.props; + return selectedVendor ? ( + <SoftwareProductListByVendor {...this.props} /> + ) : ( + <VendorList {...this.props} /> + ); + } } export default VendorCatalogView; 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 158282cc48..bef47d5acf 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/onboardingCatalog/VendorItem.jsx @@ -16,82 +16,102 @@ import React from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {Tile, TileInfo, TileInfoLine, TileFooter, TileFooterCell, Button} from 'sdc-ui/lib/react'; +import { + Tile, + TileInfo, + TileInfoLine, + TileFooter, + TileFooterCell, + Button +} from 'sdc-ui/lib/react'; import VSPOverlay from './VSPOverlay.jsx'; -import {TooltipWrapper} from './Tooltip.jsx'; +import { TooltipWrapper } from './Tooltip.jsx'; class VendorItem extends React.Component { + static PropTypes = { + softwareProductList: PropTypes.array, + vendor: PropTypes.object, + shouldShowOverlay: PropTypes.bool, + onSelectVSP: PropTypes.func, + onVendorSelect: PropTypes.func, + onAddVSP: PropTypes.func, + onVSPButtonClick: PropTypes.func + }; - static PropTypes = { - softwareProductList: PropTypes.array, - vendor: PropTypes.object, - shouldShowOverlay: PropTypes.bool, - onSelectVSP: PropTypes.func, - onVendorSelect: PropTypes.func, - onAddVSP: PropTypes.func, - onVSPButtonClick: PropTypes.func - }; + render() { + let { + vendor, + onSelectVSP, + shouldShowOverlay, + onVendorSelect, + onMigrate + } = this.props; + let { softwareProductList = [], name } = vendor; + return ( + <Tile iconName="vendor" onClick={() => onVendorSelect(vendor)}> + <TileInfo align="center"> + <TileInfoLine type="title"> + <TooltipWrapper + className="with-overlay" + dataTestId="catalog-item-name"> + {name} + </TooltipWrapper> + </TileInfoLine> + <TileInfoLine> + <Button + btnType="outline-rounded" + color="dark-gray" + onClick={e => this.handleVspCountClick(e)} + data-test-id="catalog-vsp-count" + disabled={!softwareProductList.length}> + {i18n('{length} VSPs', { + length: softwareProductList.length + })} + </Button> + {shouldShowOverlay && + softwareProductList.length > 0 && ( + <VSPOverlay + onMigrate={onMigrate} + VSPList={softwareProductList} + onSelectVSP={onSelectVSP} + onSeeMore={() => onVendorSelect(vendor)} + /> + )} + </TileInfoLine> + </TileInfo> + <TileFooter align="center"> + <TileFooterCell dataTestId="catalog-create-new-vsp-from-vendor"> + <Button + btnType="link" + color="primary" + iconName="plusThin" + onClick={e => this.onCreateVspClick(e)}> + {i18n('Create new VSP')} + </Button> + </TileFooterCell> + </TileFooter> + </Tile> + ); + } - render() { - let {vendor, onSelectVSP, shouldShowOverlay, onVendorSelect, onMigrate} = this.props; - let {softwareProductList = [], name} = vendor; - return ( - <Tile - iconName='vendor' - onClick={() => onVendorSelect(vendor)}> - <TileInfo align='center'> - <TileInfoLine type='title'> - <TooltipWrapper className='with-overlay' dataTestId='catalog-item-name'>{name}</TooltipWrapper> - </TileInfoLine> - <TileInfoLine> - <Button - btnType='outline-rounded' - color='dark-gray' - onClick={e => this.handleVspCountClick(e)} - data-test-id='catalog-vsp-count' - disabled={!softwareProductList.length}> - {i18n('{length} VSPs', {length: softwareProductList.length})} - </Button> - {shouldShowOverlay && softwareProductList.length > 0 && - <VSPOverlay - onMigrate={onMigrate} - VSPList={softwareProductList} - onSelectVSP={onSelectVSP} - onSeeMore={() => onVendorSelect(vendor)} /> - } - </TileInfoLine> - </TileInfo> - <TileFooter align='center'> - <TileFooterCell dataTestId='catalog-create-new-vsp-from-vendor'> - <Button - btnType='link' - color='primary' - iconName='plusThin' - onClick={e => this.onCreateVspClick(e)}> - {i18n('Create new VSP')} - </Button> - </TileFooterCell> - </TileFooter> - </Tile> - ); - } - - onCreateVspClick(e) { - e.stopPropagation(); - e.preventDefault(); - const {onAddVSP, vendor: {id}} = this.props; - onAddVSP(id); - } - - handleVspCountClick(e){ - e.stopPropagation(); - e.preventDefault(); - const {onVSPButtonClick, vendor: {softwareProductList}} = this.props; - const hasVSP = Boolean(softwareProductList.length); - onVSPButtonClick(hasVSP); - } + onCreateVspClick(e) { + e.stopPropagation(); + e.preventDefault(); + const { onAddVSP, vendor: { id } } = this.props; + onAddVSP(id); + } + handleVspCountClick(e) { + e.stopPropagation(); + e.preventDefault(); + const { + onVSPButtonClick, + vendor: { softwareProductList } + } = this.props; + const hasVSP = Boolean(softwareProductList.length); + onVSPButtonClick(hasVSP); + } } export default VendorItem; diff --git a/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceView.jsx b/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceView.jsx index a937c11d85..2f17867af1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/onboard/workspace/WorkspaceView.jsx @@ -16,31 +16,43 @@ import React from 'react'; import DetailsCatalogView from '../DetailsCatalogView.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {tabsMapping} from 'sdc-app/onboarding/onboard/OnboardConstants.js'; +import { tabsMapping } from 'sdc-app/onboarding/onboard/OnboardConstants.js'; -const WorkspaceView = (props) => { - let { - licenseModelList, softwareProductList, onAddLicenseModelClick, users, - onAddSoftwareProductClick, onSelectLicenseModel, onSelectSoftwareProduct, searchValue, onMigrate - } = props; +const WorkspaceView = props => { + let { + licenseModelList, + softwareProductList, + onAddLicenseModelClick, + users, + onAddSoftwareProductClick, + onSelectLicenseModel, + onSelectSoftwareProduct, + searchValue, + onMigrate + } = props; - return ( - <div className='catalog-wrapper workspace-view'> - <div className='catalog-header workspace-header'> - {i18n('WORKSPACE')} - </div> - <DetailsCatalogView - VLMList={licenseModelList} - VSPList={softwareProductList} - users={users} - onAddVLM={onAddLicenseModelClick} - onAddVSP={onAddSoftwareProductClick} - onSelectVLM={(item, users) => onSelectLicenseModel(item, users, tabsMapping.WORKSPACE)} - onSelectVSP={(item, users) => onSelectSoftwareProduct(item, users, tabsMapping.WORKSPACE)} - onMigrate={onMigrate} - filter={searchValue} /> - </div> - ); + return ( + <div className="catalog-wrapper workspace-view"> + <div className="catalog-header workspace-header"> + {i18n('WORKSPACE')} + </div> + <DetailsCatalogView + VLMList={licenseModelList} + VSPList={softwareProductList} + users={users} + onAddVLM={onAddLicenseModelClick} + onAddVSP={onAddSoftwareProductClick} + onSelectVLM={(item, users) => + onSelectLicenseModel(item, users, tabsMapping.WORKSPACE) + } + onSelectVSP={(item, users) => + onSelectSoftwareProduct(item, users, tabsMapping.WORKSPACE) + } + onMigrate={onMigrate} + filter={searchValue} + /> + </div> + ); }; export default WorkspaceView; diff --git a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsActionHelper.js index c25d93f2fc..d42a2f83ad 100644 --- a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsActionHelper.js @@ -15,94 +15,110 @@ */ import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {actionTypes} from './PermissionsConstants.js'; -import {permissionTypes} from './PermissionsConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {askForRightsMsg} from './PermissionsManager.jsx'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './PermissionsConstants.js'; +import { permissionTypes } from './PermissionsConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { askForRightsMsg } from './PermissionsManager.jsx'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; const PermissionsActionHelper = { - openPermissonsManager(dispatch, {itemId, askForRights}) { - if (askForRights) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - title: i18n('Ask For Contributers Rights'), - msg: askForRightsMsg(), - confirmationButtonText: i18n('SEND'), - onConfirmed: () => this.askForContributorRights() - } - }); - } else { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.MANAGE_PERMISSIONS, - title: i18n('Manage Permissions'), - modalComponentProps: { - itemId - } - } - }); - } - }, + openPermissonsManager(dispatch, { itemId, askForRights }) { + if (askForRights) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + title: i18n('Ask For Contributers Rights'), + msg: askForRightsMsg(), + confirmationButtonText: i18n('SEND'), + onConfirmed: () => this.askForContributorRights() + } + }); + } else { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.MANAGE_PERMISSIONS, + title: i18n('Manage Permissions'), + modalComponentProps: { + itemId + } + } + }); + } + }, - closePermissionManager(dispatch) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - }, + closePermissionManager(dispatch) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + }, - saveItemUsers(dispatch, {itemId, removedUsersIds, addedUsersIds, allUsers}) { - return ItemsHelper.updateContributors({itemId, removedUsersIds, addedUsersIds}).then(() => - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId, allUsers}) - ); - }, + saveItemUsers( + dispatch, + { itemId, removedUsersIds, addedUsersIds, allUsers } + ) { + return ItemsHelper.updateContributors({ + itemId, + removedUsersIds, + addedUsersIds + }).then(() => + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId, + allUsers + }) + ); + }, - changeOwner(dispatch, {itemId, newOwnerId, allUsers}) { - return ItemsHelper.changeOwner({itemId, ownerId: newOwnerId}).then(() => - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId, allUsers}) - ); - }, + changeOwner(dispatch, { itemId, newOwnerId, allUsers }) { + return ItemsHelper.changeOwner({ itemId, ownerId: newOwnerId }).then( + () => + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId, + allUsers + }) + ); + }, - fetchItemUsers(dispatch, {itemId, allUsers}) { - return ItemsHelper.fetchUsers({itemId}).then(response => { + fetchItemUsers(dispatch, { itemId, allUsers }) { + return ItemsHelper.fetchUsers({ itemId }).then(response => { + let allContributors = response.results; - let allContributors = response.results; - - let owner = {}; - let contributors = []; - allContributors.map(user => { - let userObject = allUsers.find(userObject => userObject.userId === user.userId); - if (userObject) { - user = {...user, fullName: userObject.fullName, role: userObject.role}; - - switch(user.permission) { - case permissionTypes.OWNER: - owner = user; - break; - case permissionTypes.CONTRIBUTOR: - contributors.push(user); - break; - } - } - }); - - dispatch({ - type: actionTypes.ITEM_USERS_LOADED, - contributors, - owner - }); - }); - }, - - askForContributorRights() { - console.log('asked for contributor rights'); - } + let owner = {}; + let contributors = []; + allContributors.map(user => { + let userObject = allUsers.find( + userObject => userObject.userId === user.userId + ); + if (userObject) { + user = { + ...user, + fullName: userObject.fullName, + role: userObject.role + }; + switch (user.permission) { + case permissionTypes.OWNER: + owner = user; + break; + case permissionTypes.CONTRIBUTOR: + contributors.push(user); + break; + } + } + }); + dispatch({ + type: actionTypes.ITEM_USERS_LOADED, + contributors, + owner + }); + }); + }, + askForContributorRights() { + console.log('asked for contributor rights'); + } }; export default PermissionsActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsConstants.js b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsConstants.js index 48a3461799..686aaaf0dd 100644 --- a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsConstants.js @@ -16,12 +16,13 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - ITEM_USERS_LOADED: null + ITEM_USERS_LOADED: null }); export const permissionTypes = { - OWNER: 'Owner', - CONTRIBUTOR: 'Contributor' + OWNER: 'Owner', + CONTRIBUTOR: 'Contributor' }; -export const changeOwnerMessage = 'You will no longer be able to manage the permissions of this item.\nYour permission level will be set to contributor.'; +export const changeOwnerMessage = + 'You will no longer be able to manage the permissions of this item.\nYour permission level will be set to contributor.'; diff --git a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.js b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.js index ba6562b28f..3b6d62bc15 100644 --- a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.js +++ b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.js @@ -14,30 +14,55 @@ * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import PermissionsManager from './PermissionsManager.jsx'; import PermissionsActionHelper from './PermissionsActionHelper.js'; -export const mapStateToProps = ({versionsPage, users: {usersList, userInfo}}) => { - let {permissions} = versionsPage; +export const mapStateToProps = ({ + versionsPage, + users: { usersList, userInfo } +}) => { + let { permissions } = versionsPage; - return { - users: usersList, - userInfo, - owner: permissions.owner, - itemUsers: permissions.contributors - }; + return { + users: usersList, + userInfo, + owner: permissions.owner, + itemUsers: permissions.contributors + }; }; -const mapActionsToProps = (dispatch) => { - return { - onCancel: () => PermissionsActionHelper.closePermissionManager(dispatch), - onSubmit: ({itemId, addedUsersIds, removedUsersIds, allUsers, newOwnerId}) => { - return PermissionsActionHelper.saveItemUsers(dispatch,{itemId, addedUsersIds, removedUsersIds, allUsers}).then(() => { - return newOwnerId ? PermissionsActionHelper.changeOwner(dispatch, {itemId, newOwnerId, allUsers}) : Promise.resolve(); - }).then(() => PermissionsActionHelper.closePermissionManager(dispatch)); - } - }; +const mapActionsToProps = dispatch => { + return { + onCancel: () => + PermissionsActionHelper.closePermissionManager(dispatch), + onSubmit: ({ + itemId, + addedUsersIds, + removedUsersIds, + allUsers, + newOwnerId + }) => { + return PermissionsActionHelper.saveItemUsers(dispatch, { + itemId, + addedUsersIds, + removedUsersIds, + allUsers + }) + .then(() => { + return newOwnerId + ? PermissionsActionHelper.changeOwner(dispatch, { + itemId, + newOwnerId, + allUsers + }) + : Promise.resolve(); + }) + .then(() => + PermissionsActionHelper.closePermissionManager(dispatch) + ); + } + }; }; export default connect(mapStateToProps, mapActionsToProps)(PermissionsManager); diff --git a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.jsx b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.jsx index b7d5d57cca..ab6add8ac2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsManager.jsx @@ -21,97 +21,154 @@ import OverlayTrigger from 'react-bootstrap/lib/OverlayTrigger.js'; import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {permissionTypes, changeOwnerMessage} from './PermissionsConstants.js'; +import { permissionTypes, changeOwnerMessage } from './PermissionsConstants.js'; export const askForRightsMsg = () => { - return ( - <div> - <p>{i18n('Send a Contributor rights reguest to Owner')}</p> - </div> - ); + return ( + <div> + <p>{i18n('Send a Contributor rights reguest to Owner')}</p> + </div> + ); }; - class Permissions extends React.Component { - constructor(props) { - super(props); - this.state = { - itemUsers: props.itemUsers, - newOwnerId: '', - showChangeOwner: false - }; - } + constructor(props) { + super(props); + this.state = { + itemUsers: props.itemUsers, + newOwnerId: '', + showChangeOwner: false + }; + } - buildUserOptions() { - let {users, owner} = this.props; - return users.filter(user => user.userId !== owner.userId).map(item => {return {label: item.fullName, value: item.userId};}); - } + buildUserOptions() { + let { users, owner } = this.props; + return users.filter(user => user.userId !== owner.userId).map(item => { + return { label: item.fullName, value: item.userId }; + }); + } - render() { - let {onCancel, owner} = this.props; - let {newOwnerId} = this.state; - return ( - <div className='manage-permissions-page'> - <Form - hasButtons={true} - onSubmit={() => this.onsaveItemUsers()} - onReset={() => onCancel() } - labledButtons={true}> - <div className='manage-permissions-title'>{i18n('Owner')}</div> - <div className='owner-details'> - <span>{owner.fullName}</span> - <span className='change-owner' onClick={() => this.setState({showChangeOwner: !this.state.showChangeOwner})}>{i18n('Change Owner')}</span> - </div> - {this.state.showChangeOwner && <div className='change-owner-wrapper'> - <div className='change-owner-title'> - <span className='manage-permissions-title' data-test-id='change-owner'>{i18n('Change Owner')}</span> - <OverlayTrigger placement='right' trigger='click' overlay={ - <Tooltip id='manage-permissions-owner-tooltip' className='manage-permissions-owner-tooltip'>{i18n(changeOwnerMessage)}</Tooltip> }> - <SVGIcon name='questionMark' /> - </OverlayTrigger> - </div> - <Select - data-test-id='selected-owner' - value={newOwnerId} - onChange={(item) => this.setState({newOwnerId: item ? item.value : ''})} - options={this.buildUserOptions()} /> - </div>} - <div className='manage-permissions-title'>{i18n('Contributors')}</div> - <Select - data-test-id='selected-contributors' - value={this.state.itemUsers.map(item => item.userId)} - className='options-input contributors-select' - clearable={false} - onMultiSelectChanged={(value) => {this.onChangeItemUsers({itemUsers: value});}} - options={this.buildUserOptions()} - multi/> - </Form> - </div> - ); - } + render() { + let { onCancel, owner } = this.props; + let { newOwnerId } = this.state; + return ( + <div className="manage-permissions-page"> + <Form + hasButtons={true} + onSubmit={() => this.onsaveItemUsers()} + onReset={() => onCancel()} + labledButtons={true}> + <div className="manage-permissions-title"> + {i18n('Owner')} + </div> + <div className="owner-details"> + <span>{owner.fullName}</span> + <span + className="change-owner" + onClick={() => + this.setState({ + showChangeOwner: !this.state.showChangeOwner + }) + }> + {i18n('Change Owner')} + </span> + </div> + {this.state.showChangeOwner && ( + <div className="change-owner-wrapper"> + <div className="change-owner-title"> + <span + className="manage-permissions-title" + data-test-id="change-owner"> + {i18n('Change Owner')} + </span> + <OverlayTrigger + placement="right" + trigger="click" + overlay={ + <Tooltip + id="manage-permissions-owner-tooltip" + className="manage-permissions-owner-tooltip"> + {i18n(changeOwnerMessage)} + </Tooltip> + }> + <SVGIcon name="questionMark" /> + </OverlayTrigger> + </div> + <Select + data-test-id="selected-owner" + value={newOwnerId} + onChange={item => + this.setState({ + newOwnerId: item ? item.value : '' + }) + } + options={this.buildUserOptions()} + /> + </div> + )} + <div className="manage-permissions-title"> + {i18n('Contributors')} + </div> + <Select + data-test-id="selected-contributors" + value={this.state.itemUsers.map(item => item.userId)} + className="options-input contributors-select" + clearable={false} + onMultiSelectChanged={value => { + this.onChangeItemUsers({ itemUsers: value }); + }} + options={this.buildUserOptions()} + multi + /> + </Form> + </div> + ); + } - onChangeItemUsers({itemUsers}) { - this.setState({ - itemUsers: itemUsers.map(contributor => { - let contributorFromProps = this.props.itemUsers.find(user => user.userId === contributor.userId); - return { - userId: contributor.value, - fullName: contributor.label, - permission: contributorFromProps ? contributorFromProps.permission : permissionTypes.CONTRIBUTOR - }; - }) - }); - } + onChangeItemUsers({ itemUsers }) { + this.setState({ + itemUsers: itemUsers.map(contributor => { + let contributorFromProps = this.props.itemUsers.find( + user => user.userId === contributor.userId + ); + return { + userId: contributor.value, + fullName: contributor.label, + permission: contributorFromProps + ? contributorFromProps.permission + : permissionTypes.CONTRIBUTOR + }; + }) + }); + } - onsaveItemUsers() { - let {itemUsers: newUsers, newOwnerId} = this.state; - let {itemUsers: oldUsers, onSubmit, itemId, users} = this.props; - let addedUsersIds = newUsers.filter(newUser => !oldUsers.map(oldUser => oldUser.userId).includes(newUser.userId)) - .map(user => user.userId); - let removedUsersIds = oldUsers.filter(oldUser => !newUsers.map(newUser => newUser.userId).includes(oldUser.userId)) - .map(user => user.userId); - onSubmit({itemId, addedUsersIds, removedUsersIds, allUsers: users, newOwnerId}); - } + onsaveItemUsers() { + let { itemUsers: newUsers, newOwnerId } = this.state; + let { itemUsers: oldUsers, onSubmit, itemId, users } = this.props; + let addedUsersIds = newUsers + .filter( + newUser => + !oldUsers + .map(oldUser => oldUser.userId) + .includes(newUser.userId) + ) + .map(user => user.userId); + let removedUsersIds = oldUsers + .filter( + oldUser => + !newUsers + .map(newUser => newUser.userId) + .includes(oldUser.userId) + ) + .map(user => user.userId); + onSubmit({ + itemId, + addedUsersIds, + removedUsersIds, + allUsers: users, + newOwnerId + }); + } } export default Permissions; diff --git a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsReducer.js b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsReducer.js index b4ab78964d..6e817ae3db 100644 --- a/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/permissions/PermissionsReducer.js @@ -13,16 +13,16 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './PermissionsConstants.js'; +import { actionTypes } from './PermissionsConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.ITEM_USERS_LOADED: - return { - owner: action.owner, - contributors: action.contributors - }; - default: - return state; - } -};
\ No newline at end of file + switch (action.type) { + case actionTypes.ITEM_USERS_LOADED: + return { + owner: action.owner, + contributors: action.contributors + }; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/revisions/Revisions.js b/openecomp-ui/src/sdc-app/onboarding/revisions/Revisions.js index 73ee5dea21..738e7459fe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/revisions/Revisions.js +++ b/openecomp-ui/src/sdc-app/onboarding/revisions/Revisions.js @@ -14,24 +14,31 @@ * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import RevisionsView from './RevisionsView.jsx'; import RevisionsActionHelper from './RevisionsActionHelper.js'; -export const mapStateToProps = ({revisions, users}) => { - return { - revisions: revisions, - users: users.usersList - }; +export const mapStateToProps = ({ revisions, users }) => { + return { + revisions: revisions, + users: users.usersList + }; }; -export const mapActionsToProps = (dispatch, {itemId, version, itemType}) => { - return { - onCancel: () => RevisionsActionHelper.closeRevisionsView(dispatch), - onRevert: (revisionId) => { - RevisionsActionHelper.revertToRevision(dispatch, {itemId, version, revisionId, itemType}); - } - }; +export const mapActionsToProps = (dispatch, { itemId, version, itemType }) => { + return { + onCancel: () => RevisionsActionHelper.closeRevisionsView(dispatch), + onRevert: revisionId => { + RevisionsActionHelper.revertToRevision(dispatch, { + itemId, + version, + revisionId, + itemType + }); + } + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(RevisionsView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(RevisionsView); diff --git a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsActionHelper.js index 4fd9082b5b..61ccad0cc4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsActionHelper.js @@ -16,85 +16,89 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {actionsEnum as vcActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionsEnum as vcActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; -import {actionTypes} from './RevisionsConstants.js'; +import { actionTypes } from './RevisionsConstants.js'; function baseUrl(itemId, version) { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/items/${itemId}/versions/${version.id}`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/items/${itemId}/versions/${version.id}`; } -function fetchRevisions(itemId, version){ - let fetchUrl = `${baseUrl(itemId, version)}/revisions`; - return RestAPIUtil.fetch(fetchUrl); +function fetchRevisions(itemId, version) { + let fetchUrl = `${baseUrl(itemId, version)}/revisions`; + return RestAPIUtil.fetch(fetchUrl); } function revertToRevision(itemId, version, revisionId) { - let putUrl = `${baseUrl(itemId, version)}/actions`; - let requestBody = { - action: vcActionsEnum.REVERT, - revisionRequest: { - revisionId: revisionId - } - }; - return RestAPIUtil.put(putUrl, requestBody); + let putUrl = `${baseUrl(itemId, version)}/actions`; + let requestBody = { + action: vcActionsEnum.REVERT, + revisionRequest: { + revisionId: revisionId + } + }; + return RestAPIUtil.put(putUrl, requestBody); } const RevisionaActionHelper = { - openRevisionsView(dispatch, {itemId, version, itemType}) { - this.fetchRevisions(dispatch, {itemId, version}).then(() => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.REVISIONS_LIST, - modalClassName: 'manage-revisions-modal', - title: i18n('Revert'), - modalComponentProps: { - itemId: itemId, - version: version, - itemType - } - } - }); - }); - }, + openRevisionsView(dispatch, { itemId, version, itemType }) { + this.fetchRevisions(dispatch, { itemId, version }).then(() => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.REVISIONS_LIST, + modalClassName: 'manage-revisions-modal', + title: i18n('Revert'), + modalComponentProps: { + itemId: itemId, + version: version, + itemType + } + } + }); + }); + }, - closeRevisionsView(dispatch) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - }, + closeRevisionsView(dispatch) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + }, + fetchRevisions(dispatch, { itemId, version }) { + return fetchRevisions(itemId, version).then(response => { + dispatch({ + type: actionTypes.ITEM_REVISIONS_LOADED, + response: response + }); + }); + }, - fetchRevisions(dispatch, {itemId, version}) { - return fetchRevisions(itemId, version).then((response) => { - dispatch({ - type: actionTypes.ITEM_REVISIONS_LOADED, - response: response - }); - }); - }, - - revertToRevision(dispatch, {itemId, version, revisionId, itemType}) { - return revertToRevision(itemId, version, revisionId).then(() => { - this.closeRevisionsView(dispatch); - if (itemType === screenTypes.LICENSE_MODEL) { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId: itemId, version}}); - } else { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId: itemId, version}}); - } - }); - - } + revertToRevision(dispatch, { itemId, version, revisionId, itemType }) { + return revertToRevision(itemId, version, revisionId).then(() => { + this.closeRevisionsView(dispatch); + if (itemType === screenTypes.LICENSE_MODEL) { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId: itemId, version } + }); + } else { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId: itemId, version } + }); + } + }); + } }; export default RevisionaActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsConstants.js b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsConstants.js index 28a9fa0ff5..dc1845c59c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsConstants.js @@ -16,5 +16,5 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - ITEM_REVISIONS_LOADED: null + ITEM_REVISIONS_LOADED: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsReducer.js b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsReducer.js index 778350b93f..a3e6ce8ab0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './RevisionsConstants.js'; +import { actionTypes } from './RevisionsConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.ITEM_REVISIONS_LOADED: - return action.response.results; - default: - return state; - } -};
\ No newline at end of file + switch (action.type) { + case actionTypes.ITEM_REVISIONS_LOADED: + return action.response.results; + default: + return state; + } +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsView.jsx b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsView.jsx index d6ef604a22..1fc8c06925 100644 --- a/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/revisions/RevisionsView.jsx @@ -23,65 +23,111 @@ import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; - class RevisionsView extends React.Component { - constructor(props) { - super(props); - this.state = { - revertId : null - }; - } - - render() { - let {onCancel, onRevert, revisions, users} = this.props; - return ( - <div className='manage-revisions-page'> - <Form - hasButtons={true} - onSubmit={() => onRevert(this.state.revertId)} - onReset={() => onCancel() } - submitButtonText={i18n('Revert')} - labledButtons={true}> - <ListEditorView - title={i18n('Select a Commit')} - isReadOnlyMode={false}> - {revisions.map((revision) => { - return ( - <div key={revision.id} data-test-id='revision-list-item' className={`revision-list-item ${this.state.revertId === revision.id ? 'selected' : ''}`}> - <ListEditorItemView - isReadOnlyMode={false} - onSelect={() => this.setState({revertId : revision.id})}> - <ListEditorItemViewField> - <div className='revision-list-item-fields'> - <div data-test-id='revision-user' className='revision-user'> - <SVGIcon name='user' label={users.find(userObject => userObject.userId === revision.user).fullName} labelPosition='right'/> - </div> - <div className='revision-date' data-test-id='revision-date'> - <span className='revision-date'>{i18n.dateNormal(revision.time, { - year: 'numeric', month: 'numeric', day: 'numeric' - })}</span> - <span className='revision-time'>{i18n.dateNormal(revision.time, { - hour: 'numeric', minute: 'numeric', - hour12: true - })}</span> - </div> - <div className='revision-message'data-test-id='revision-message'> - {revision.message && <ShowMore anchorClass='more-less' lines={2} more={i18n('More')} less={i18n('Less')}> - {revision.message} - </ShowMore>}</div> - </div> - </ListEditorItemViewField> - </ListEditorItemView> - </div> - - ); - })} - </ListEditorView> - </Form> - </div> - ); - } + constructor(props) { + super(props); + this.state = { + revertId: null + }; + } + render() { + let { onCancel, onRevert, revisions, users } = this.props; + return ( + <div className="manage-revisions-page"> + <Form + hasButtons={true} + onSubmit={() => onRevert(this.state.revertId)} + onReset={() => onCancel()} + submitButtonText={i18n('Revert')} + labledButtons={true}> + <ListEditorView + title={i18n('Select a Commit')} + isReadOnlyMode={false}> + {revisions.map(revision => { + return ( + <div + key={revision.id} + data-test-id="revision-list-item" + className={`revision-list-item ${ + this.state.revertId === revision.id + ? 'selected' + : '' + }`}> + <ListEditorItemView + isReadOnlyMode={false} + onSelect={() => + this.setState({ + revertId: revision.id + }) + }> + <ListEditorItemViewField> + <div className="revision-list-item-fields"> + <div + data-test-id="revision-user" + className="revision-user"> + <SVGIcon + name="user" + label={ + users.find( + userObject => + userObject.userId === + revision.user + ).fullName + } + labelPosition="right" + /> + </div> + <div + className="revision-date" + data-test-id="revision-date"> + <span className="revision-date"> + {i18n.dateNormal( + revision.time, + { + year: 'numeric', + month: + 'numeric', + day: 'numeric' + } + )} + </span> + <span className="revision-time"> + {i18n.dateNormal( + revision.time, + { + hour: 'numeric', + minute: + 'numeric', + hour12: true + } + )} + </span> + </div> + <div + className="revision-message" + data-test-id="revision-message"> + {revision.message && ( + <ShowMore + anchorClass="more-less" + lines={2} + more={i18n('More')} + less={i18n('Less')}> + {revision.message} + </ShowMore> + )} + </div> + </div> + </ListEditorItemViewField> + </ListEditorItemView> + </div> + ); + })} + </ListEditorView> + </Form> + </div> + ); + } } export default RevisionsView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/ArchivedSoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/ArchivedSoftwareProductReducer.js index b484f5e0a0..9faa6ffd68 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/ArchivedSoftwareProductReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/ArchivedSoftwareProductReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductConstants.js'; +import { actionTypes } from './SoftwareProductConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED: - return [...action.response.results]; - default: - return state; - } + switch (action.type) { + case actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/FinalizedSoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/FinalizedSoftwareProductReducer.js index 396f65f5d7..f91c8f31e3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/FinalizedSoftwareProductReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/FinalizedSoftwareProductReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductConstants.js'; +import { actionTypes } from './SoftwareProductConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED: - return [...action.response.results]; - default: - return state; - } + switch (action.type) { + case actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED: + return [...action.response.results]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js index e3ea7e1907..db3cc04f76 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProduct.js @@ -13,359 +13,668 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import TabulatedEditor from 'src/nfvo-components/editor/TabulatedEditor.jsx'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; -import {onboardingMethod as onboardingMethodTypes, onboardingOriginTypes} from './SoftwareProductConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; +import { + onboardingMethod as onboardingMethodTypes, + onboardingOriginTypes +} from './SoftwareProductConstants.js'; import SoftwareProductActionHelper from './SoftwareProductActionHelper.js'; import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js'; import PermissionsActionHelper from './../permissions/PermissionsActionHelper.js'; import RevisionsActionHelper from './../revisions/RevisionsActionHelper.js'; import HeatSetupActionHelper from './attachments/setup/HeatSetupActionHelper.js'; import { actionsEnum as versionControllerActions } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {CommitModalType} from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; -import {onboardingMethod as onboardingMethodType} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -import {SyncStates} from 'sdc-app/common/merge/MergeEditorConstants.js'; -import {catalogItemStatuses} from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; +import { onboardingMethod as onboardingMethodType } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js'; +import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; function getActiveNavigationId(screen, componentId) { - let activeItemId = componentId ? screen + '|' + componentId : screen; - return activeItemId; + let activeItemId = componentId ? screen + '|' + componentId : screen; + return activeItemId; } -const buildComponentNavigationBarGroups = ({componentId, meta}) => { - const groups = ([ - { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL + '|' + componentId, - name: i18n('General'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE + '|' + componentId, - name: i18n('Compute'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING + '|' + componentId, - name: i18n('High Availability & Load Balancing'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK + '|' + componentId, - name: i18n('Networks'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE + '|' + componentId, - name: i18n('Storage'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES + '|' + componentId, - name: i18n('Images'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES + '|' + componentId, - name: i18n('Process Details'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING + '|' + componentId, - name: i18n('Monitoring'), - disabled: false, - meta - } - ]); +const buildComponentNavigationBarGroups = ({ componentId, meta }) => { + const groups = [ + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL + + '|' + + componentId, + name: i18n('General'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_COMPUTE + + '|' + + componentId, + name: i18n('Compute'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_LOAD_BALANCING + + '|' + + componentId, + name: i18n('High Availability & Load Balancing'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_NETWORK + + '|' + + componentId, + name: i18n('Networks'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_STORAGE + + '|' + + componentId, + name: i18n('Storage'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_IMAGES + + '|' + + componentId, + name: i18n('Images'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_PROCESSES + + '|' + + componentId, + name: i18n('Process Details'), + disabled: false, + meta + }, + { + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_MONITORING + + '|' + + componentId, + name: i18n('Monitoring'), + disabled: false, + meta + } + ]; - return groups; + return groups; }; -const buildNavigationBarProps = ({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}) => { - const {softwareProductEditor: {data: currentSoftwareProduct = {}}} = softwareProduct; - const {id, name, onboardingMethod, candidateOnboardingOrigin, onboardingOrigin} = currentSoftwareProduct; - const groups = [{ - id: id, - name: name, - items: [ - { - id: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, - name: i18n('Overview'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, - name: i18n('General'), - disabled: false, - meta - }, - { - id: enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, - name: i18n('Deployment Flavors'), - disabled: false, - hidden: onboardingMethod !== onboardingMethodTypes.MANUAL, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES, - name: i18n('Process Details'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS, - name: i18n('Networks'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, - name: i18n('Attachments'), - disabled: false, - hidden: !candidateOnboardingOrigin && !onboardingOrigin, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, - name: i18n('Activity Log'), - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES, - name: i18n('Component Dependencies'), - hidden: componentsList.length <= 1, - disabled: false, - meta - }, { - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, - name: i18n('Components'), - hidden: componentsList.length <= 0, - meta, - expanded: mapOfExpandedIds[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, - items: [ - ...componentsList.map(({id, displayName}) => ({ - id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + '|' + id, - name: displayName, - meta, - expanded: mapOfExpandedIds[enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + '|' + id] === true && screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, - items: buildComponentNavigationBarGroups({componentId: id, meta}) - })) - ] - } - ] - }]; - let activeItemId = getActiveNavigationId(screen, componentId); - return { - activeItemId, groups, disabled: !!candidateOnboardingOrigin - }; +const buildNavigationBarProps = ({ + softwareProduct, + meta, + screen, + componentId, + componentsList, + mapOfExpandedIds +}) => { + const { + softwareProductEditor: { data: currentSoftwareProduct = {} } + } = softwareProduct; + const { + id, + name, + onboardingMethod, + candidateOnboardingOrigin, + onboardingOrigin + } = currentSoftwareProduct; + const groups = [ + { + id: id, + name: name, + items: [ + { + id: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + name: i18n('Overview'), + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, + name: i18n('General'), + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_DEPLOYMENT, + name: i18n('Deployment Flavors'), + disabled: false, + hidden: onboardingMethod !== onboardingMethodTypes.MANUAL, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES, + name: i18n('Process Details'), + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS, + name: i18n('Networks'), + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS, + name: i18n('Attachments'), + disabled: false, + hidden: !candidateOnboardingOrigin && !onboardingOrigin, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_ACTIVITY_LOG, + name: i18n('Activity Log'), + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_DEPENDENCIES, + name: i18n('Component Dependencies'), + hidden: componentsList.length <= 1, + disabled: false, + meta + }, + { + id: enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS, + name: i18n('Components'), + hidden: componentsList.length <= 0, + meta, + expanded: + mapOfExpandedIds[ + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + ] === true && + screen !== enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + items: [ + ...componentsList.map(({ id, displayName }) => ({ + id: + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + + '|' + + id, + name: displayName, + meta, + expanded: + mapOfExpandedIds[ + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS + + '|' + + id + ] === true && + screen !== + enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + items: buildComponentNavigationBarGroups({ + componentId: id, + meta + }) + })) + ] + } + ] + } + ]; + let activeItemId = getActiveNavigationId(screen, componentId); + return { + activeItemId, + groups, + disabled: !!candidateOnboardingOrigin + }; }; -const buildVersionControllerProps = ({softwareProduct, versions, currentVersion, permissions, userInfo, isArchived, usersList, itemPermission, isReadOnlyMode}) => { - const {softwareProductEditor = {data: {}}} = softwareProduct; - const {isValidityData = true, data: {name, onboardingMethod, candidateOnboardingOrigin}} = softwareProductEditor; - - return { - version: currentVersion, - viewableVersions: versions, - isFormDataValid: isValidityData, - permissions, - itemName: name, - itemPermission, - isReadOnlyMode, - isArchived, - userInfo, - usersList, - isManual: onboardingMethod === onboardingMethodType.MANUAL, - candidateInProcess: !!candidateOnboardingOrigin - }; +const buildVersionControllerProps = ({ + softwareProduct, + versions, + currentVersion, + permissions, + userInfo, + isArchived, + usersList, + itemPermission, + isReadOnlyMode +}) => { + const { softwareProductEditor = { data: {} } } = softwareProduct; + const { + isValidityData = true, + data: { name, onboardingMethod, candidateOnboardingOrigin } + } = softwareProductEditor; + + return { + version: currentVersion, + viewableVersions: versions, + isFormDataValid: isValidityData, + permissions, + itemName: name, + itemPermission, + isReadOnlyMode, + isArchived, + userInfo, + usersList, + isManual: onboardingMethod === onboardingMethodType.MANUAL, + candidateInProcess: !!candidateOnboardingOrigin + }; }; -function buildMeta({softwareProduct, componentId, softwareProductDependencies, isReadOnlyMode}) { - const {softwareProductEditor, softwareProductComponents, softwareProductQuestionnaire, softwareProductAttachments} = softwareProduct; - const {data: currentSoftwareProduct = {}} = softwareProductEditor; - const {version, onboardingOrigin, candidateOnboardingOrigin} = currentSoftwareProduct; - const {qdata} = softwareProductQuestionnaire; - const {heatSetup, heatSetupCache} = softwareProductAttachments; - let currentComponentMeta = {}; - if(componentId) { - const {componentEditor: {data: componentData = {} , qdata: componentQdata}} = softwareProductComponents; - currentComponentMeta = {componentData, componentQdata}; - } - const meta = {softwareProduct: currentSoftwareProduct, qdata, version, onboardingOrigin, candidateOnboardingOrigin, heatSetup, heatSetupCache, - isReadOnlyMode, currentComponentMeta, softwareProductDependencies}; - return meta; +function buildMeta({ + softwareProduct, + componentId, + softwareProductDependencies, + isReadOnlyMode +}) { + const { + softwareProductEditor, + softwareProductComponents, + softwareProductQuestionnaire, + softwareProductAttachments + } = softwareProduct; + const { data: currentSoftwareProduct = {} } = softwareProductEditor; + const { + version, + onboardingOrigin, + candidateOnboardingOrigin + } = currentSoftwareProduct; + const { qdata } = softwareProductQuestionnaire; + const { heatSetup, heatSetupCache } = softwareProductAttachments; + let currentComponentMeta = {}; + if (componentId) { + const { + componentEditor: { data: componentData = {}, qdata: componentQdata } + } = softwareProductComponents; + currentComponentMeta = { componentData, componentQdata }; + } + const meta = { + softwareProduct: currentSoftwareProduct, + qdata, + version, + onboardingOrigin, + candidateOnboardingOrigin, + heatSetup, + heatSetupCache, + isReadOnlyMode, + currentComponentMeta, + softwareProductDependencies + }; + return meta; } const mapStateToProps = ( - { - softwareProduct, - users: {usersList, userInfo}, - versionsPage: {versionsList: {versions}, permissions} - }, - { - currentScreen: {screen, itemPermission, props: {version: currentVersion, componentId, isReadOnlyMode}} - } + { + softwareProduct, + users: { usersList, userInfo }, + versionsPage: { versionsList: { versions }, permissions } + }, + { + currentScreen: { + screen, + itemPermission, + props: { version: currentVersion, componentId, isReadOnlyMode } + } + } ) => { - const {softwareProductEditor, softwareProductComponents, softwareProductDependencies} = softwareProduct; - const {mapOfExpandedIds = []} = softwareProductEditor; - const {componentsList = []} = softwareProductComponents; + const { + softwareProductEditor, + softwareProductComponents, + softwareProductDependencies + } = softwareProduct; + const { mapOfExpandedIds = [] } = softwareProductEditor; + const { componentsList = [] } = softwareProductComponents; - const meta = buildMeta({softwareProduct, componentId, softwareProductDependencies, isReadOnlyMode}); - return { - versionControllerProps: buildVersionControllerProps({ - softwareProduct, - versions, - currentVersion, - userInfo, - usersList, - isArchived: itemPermission.isArchived, - permissions, - itemPermission: {...itemPermission, isDirty: true}, - isReadOnlyMode - }), - navigationBarProps: buildNavigationBarProps({softwareProduct, meta, screen, componentId, componentsList, mapOfExpandedIds}), - meta - }; + const meta = buildMeta({ + softwareProduct, + componentId, + softwareProductDependencies, + isReadOnlyMode + }); + return { + versionControllerProps: buildVersionControllerProps({ + softwareProduct, + versions, + currentVersion, + userInfo, + usersList, + isArchived: itemPermission.isArchived, + permissions, + itemPermission: { ...itemPermission, isDirty: true }, + isReadOnlyMode + }), + navigationBarProps: buildNavigationBarProps({ + softwareProduct, + meta, + screen, + componentId, + componentsList, + mapOfExpandedIds + }), + meta + }; }; -const autoSaveBeforeNavigate = ({dispatch, screen, softwareProductId, version, componentId, - meta: {isReadOnlyMode, softwareProduct, qdata, - currentComponentMeta: {componentData, componentQdata}}}) => { - let promise; - if (isReadOnlyMode) { - promise = Promise.resolve(); - } else { - switch(screen) { - case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: - promise = SoftwareProductActionHelper.updateSoftwareProduct(dispatch, {softwareProduct, version, qdata}); - break; - case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: - promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponent(dispatch, - {softwareProductId, version, vspComponentId: componentId, componentData, qdata: componentQdata}); - break; - 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; - default: - promise = Promise.resolve(); - break; - } - } - return promise; +const autoSaveBeforeNavigate = ({ + dispatch, + screen, + softwareProductId, + version, + componentId, + meta: { + isReadOnlyMode, + softwareProduct, + qdata, + currentComponentMeta: { componentData, componentQdata } + } +}) => { + let promise; + if (isReadOnlyMode) { + promise = Promise.resolve(); + } else { + switch (screen) { + case enums.SCREEN.SOFTWARE_PRODUCT_DETAILS: + promise = SoftwareProductActionHelper.updateSoftwareProduct( + dispatch, + { softwareProduct, version, qdata } + ); + break; + case enums.SCREEN.SOFTWARE_PRODUCT_COMPONENT_GENERAL: + promise = SoftwareProductComponentsActionHelper.updateSoftwareProductComponent( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + componentData, + qdata: componentQdata + } + ); + break; + 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; + default: + promise = Promise.resolve(); + break; + } + } + return promise; }; +const mapActionsToProps = ( + dispatch, + { + currentScreen: { + screen, + props: { + softwareProductId, + licenseModelId, + version, + componentId: currentComponentId + } + } + } +) => { + const props = { + onVersionSwitching: (versionToSwitch, meta) => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId: meta.softwareProduct.id, + version: versionToSwitch + } + }); + }, + onOpenPermissions: ({ users }) => { + return PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId: softwareProductId, + allUsers: users + }); + }, + onOpenRevisionsModal: () => { + return RevisionsActionHelper.openRevisionsView(dispatch, { + itemId: softwareProductId, + version: version, + itemType: screenTypes.SOFTWARE_PRODUCT + }); + }, + onOpenCommentCommitModal: ({ onCommit, title }) => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMMIT_COMMENT, + modalComponentProps: { + onCommit, + type: CommitModalType.COMMIT + }, + title + } + }), + onMoreVersionsClick: ({ itemName, users }) => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + softwareProduct: { + name: itemName, + vendorId: licenseModelId + }, + usersList: users + } + }); + }, + onToggle: (groups, itemIdToExpand) => + groups.map(({ items }) => + SoftwareProductActionHelper.toggleNavigationItems(dispatch, { + items, + itemIdToExpand + }) + ), + onNavigate: ({ id, meta, newVersion }) => { + let navigationVersion = newVersion || version; + let { + onboardingOrigin, + candidateOnboardingOrigin, + heatSetup, + heatSetupCache + } = meta; + let heatSetupPopupPromise = + screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS + ? HeatSetupActionHelper.heatSetupLeaveConfirmation( + dispatch, + { softwareProductId, heatSetup, heatSetupCache } + ) + : Promise.resolve(); + let preNavigate = meta + ? autoSaveBeforeNavigate({ + dispatch, + screen, + meta, + version, + softwareProductId, + componentId: currentComponentId + }) + : Promise.resolve(); + version = version || (meta ? meta.version : undefined); + Promise.all([preNavigate, heatSetupPopupPromise]) + .then(() => { + let [nextScreen, nextComponentId] = id.split('|'); + if ( + nextScreen === + enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS && + nextComponentId && + nextComponentId === currentComponentId + ) { + ScreensHelper.loadScreen(dispatch, { + screen: nextScreen, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + version: navigationVersion + } + }); + } else { + if ( + nextScreen === + enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS + ) { + if ( + onboardingOrigin === + onboardingOriginTypes.ZIP || + candidateOnboardingOrigin === + onboardingOriginTypes.ZIP + ) { + nextScreen = + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP; + } else if ( + onboardingOrigin === onboardingOriginTypes.CSAR + ) { + nextScreen = + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION; + } + } + ScreensHelper.loadScreen(dispatch, { + screen: nextScreen, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + version: navigationVersion, + componentId: nextComponentId + } + }); + } + }) + .catch(e => { + console.error(e); + }); + } + }; -const mapActionsToProps = (dispatch, {currentScreen: {screen, props: {softwareProductId, licenseModelId, version, componentId: currentComponentId}}}) => { - - const props = { - onVersionSwitching: (versionToSwitch, meta) => { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId: meta.softwareProduct.id, version: versionToSwitch}}); - }, - onOpenPermissions: ({users}) => { - return PermissionsActionHelper.fetchItemUsers(dispatch, {itemId: softwareProductId, allUsers: users}); - }, - onOpenRevisionsModal: () => { - return RevisionsActionHelper.openRevisionsView(dispatch, {itemId: softwareProductId, version: version, itemType: screenTypes.SOFTWARE_PRODUCT}); - }, - onOpenCommentCommitModal: ({onCommit, title}) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.COMMIT_COMMENT, - modalComponentProps: { - onCommit, - type: CommitModalType.COMMIT - }, - title - } - }), - onMoreVersionsClick: ({itemName, users}) => { - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.SOFTWARE_PRODUCT_VERSIONS_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, softwareProduct: {name: itemName, vendorId: licenseModelId}, usersList: users}}); - - }, - onToggle: (groups, itemIdToExpand) => groups.map(({items}) => SoftwareProductActionHelper.toggleNavigationItems(dispatch, {items, itemIdToExpand})), - onNavigate: ({id, meta, newVersion}) => { - let navigationVersion = newVersion || version; - let {onboardingOrigin, candidateOnboardingOrigin, heatSetup, heatSetupCache} = meta; - let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS ? - HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) : - Promise.resolve(); - let preNavigate = meta ? autoSaveBeforeNavigate({dispatch, screen, meta, version, softwareProductId, componentId: currentComponentId}) : Promise.resolve(); - version = version || (meta ? meta.version : undefined); - Promise.all([preNavigate, heatSetupPopupPromise]).then(() => { - let [nextScreen, nextComponentId] = id.split('|'); - if(nextScreen === enums.SCREEN.SOFTWARE_PRODUCT_COMPONENTS && nextComponentId && nextComponentId === currentComponentId) { - ScreensHelper.loadScreen(dispatch, { - screen: nextScreen, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version: navigationVersion} - }); - } - else { - if(nextScreen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS) { - if(onboardingOrigin === onboardingOriginTypes.ZIP || candidateOnboardingOrigin === onboardingOriginTypes.ZIP) { - nextScreen = enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP; - } - else if(onboardingOrigin === onboardingOriginTypes.CSAR) { - nextScreen = enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION; - } - } - ScreensHelper.loadScreen(dispatch, { - screen: nextScreen, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version: navigationVersion, componentId: nextComponentId} - }); - } - }).catch((e) => {console.error(e);}); - } - }; - - switch (screen) { - case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: - case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: - case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: - case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: - 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 = () => Promise.resolve(); - break; - default: - props.onSave = ({softwareProduct, qdata}) => SoftwareProductActionHelper.updateSoftwareProduct(dispatch, {softwareProduct, qdata, version}); - break; - } - + switch (screen) { + case enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE: + case enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS: + case enums.SCREEN.SOFTWARE_PRODUCT_PROCESSES: + case enums.SCREEN.SOFTWARE_PRODUCT_NETWORKS: + 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 = () => Promise.resolve(); + break; + default: + props.onSave = ({ softwareProduct, qdata }) => + SoftwareProductActionHelper.updateSoftwareProduct(dispatch, { + softwareProduct, + qdata, + version + }); + break; + } - props.onVersionControllerAction = (action, version, comment, meta) => { - let {heatSetup, heatSetupCache} = meta; - let autoSavePromise = meta ? autoSaveBeforeNavigate({dispatch, screen, meta, version, softwareProductId, componentId: currentComponentId}) : Promise.resolve(); - let heatSetupPopupPromise = screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS && action === versionControllerActions.COMMIT ? - HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) : - Promise.resolve(); - Promise.all([autoSavePromise, heatSetupPopupPromise]).then(() => { - return SoftwareProductActionHelper.performVCAction(dispatch, {softwareProductId, action, version, comment, meta}).then(updatedVersion => { - const inMerge = updatedVersion && updatedVersion.state && updatedVersion.state.synchronizationState === SyncStates.MERGE; - if((action === versionControllerActions.SYNC && !inMerge) || - ((action === versionControllerActions.COMMIT || action === versionControllerActions.SYNC) && updatedVersion.status === catalogItemStatuses.CERTIFIED)) { - ScreensHelper.loadLandingScreen(dispatch, {previousScreenName: screen, props: {softwareProductId, version: updatedVersion}}); - } else { - ScreensHelper.loadScreen(dispatch, {screen, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version: updatedVersion, componentId: currentComponentId}}); - } - }); - }).catch((e) => {console.error(e);}); - }; + props.onVersionControllerAction = (action, version, comment, meta) => { + let { heatSetup, heatSetupCache } = meta; + let autoSavePromise = meta + ? autoSaveBeforeNavigate({ + dispatch, + screen, + meta, + version, + softwareProductId, + componentId: currentComponentId + }) + : Promise.resolve(); + let heatSetupPopupPromise = + screen === enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS && + action === versionControllerActions.COMMIT + ? HeatSetupActionHelper.heatSetupLeaveConfirmation(dispatch, { + softwareProductId, + heatSetup, + heatSetupCache + }) + : Promise.resolve(); + Promise.all([autoSavePromise, heatSetupPopupPromise]) + .then(() => { + return SoftwareProductActionHelper.performVCAction(dispatch, { + softwareProductId, + action, + version, + comment, + meta + }).then(updatedVersion => { + const inMerge = + updatedVersion && + updatedVersion.state && + updatedVersion.state.synchronizationState === + SyncStates.MERGE; + if ( + (action === versionControllerActions.SYNC && + !inMerge) || + ((action === versionControllerActions.COMMIT || + action === versionControllerActions.SYNC) && + updatedVersion.status === + catalogItemStatuses.CERTIFIED) + ) { + ScreensHelper.loadLandingScreen(dispatch, { + previousScreenName: screen, + props: { + softwareProductId, + version: updatedVersion + } + }); + } else { + ScreensHelper.loadScreen(dispatch, { + screen, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + version: updatedVersion, + componentId: currentComponentId + } + }); + } + }); + }) + .catch(e => { + console.error(e); + }); + }; - props.onManagePermissions = () => PermissionsActionHelper.openPermissonsManager(dispatch, {itemId: softwareProductId, askForRights: false}); - return props; + props.onManagePermissions = () => + PermissionsActionHelper.openPermissonsManager(dispatch, { + itemId: softwareProductId, + askForRights: false + }); + return props; }; export default connect(mapStateToProps, mapActionsToProps)(TabulatedEditor); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js index 42786bf752..4a2d7a2ece 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js @@ -21,553 +21,769 @@ import LicenseModelActionHelper from 'sdc-app/onboarding/licenseModel/LicenseMod import LicenseAgreementActionHelper from 'sdc-app/onboarding/licenseModel/licenseAgreement/LicenseAgreementActionHelper.js'; import FeatureGroupsActionHelper from 'sdc-app/onboarding/licenseModel/featureGroups/FeatureGroupsActionHelper.js'; -import {actionTypes, onboardingOriginTypes, PRODUCT_QUESTIONNAIRE, forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { + actionTypes, + onboardingOriginTypes, + PRODUCT_QUESTIONNAIRE, + forms +} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; import SoftwareProductComponentsActionHelper from './components/SoftwareProductComponentsActionHelper.js'; -import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; -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 { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +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 {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {default as ItemsHelper} from 'sdc-app/common/helpers/ItemsHelper.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { default as ItemsHelper } from 'sdc-app/common/helpers/ItemsHelper.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js'; -import {CommitModalType} from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; -import {actionTypes as commonActionTypes} from 'sdc-app/common/reducers/PlainDataReducerConstants.js'; +import { CommitModalType } from 'nfvo-components/panel/versionController/components/CommitCommentModal.jsx'; +import { actionTypes as commonActionTypes } from 'sdc-app/common/reducers/PlainDataReducerConstants.js'; import versionPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import {itemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; -import {catalogItemStatuses} from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; +import { itemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { catalogItemStatuses } from 'sdc-app/onboarding/onboard/onboardingCatalog/OnboardingCatalogConstants.js'; import getValue from 'nfvo-utils/getValue.js'; function getLicensingData(licensingData = {}) { - const {licenseAgreement, featureGroups} = licensingData; - const newlicenseAgreement = getValue(licenseAgreement); - const newfeatureGroups = getValue(featureGroups); - return newlicenseAgreement ? { - licenseAgreement: newlicenseAgreement, - featureGroups: newfeatureGroups - } : undefined; -}; + const { licenseAgreement, featureGroups } = licensingData; + const newlicenseAgreement = getValue(licenseAgreement); + const newfeatureGroups = getValue(featureGroups); + return newlicenseAgreement + ? { + licenseAgreement: newlicenseAgreement, + featureGroups: newfeatureGroups + } + : undefined; +} function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/`; } function softwareProductCategoriesUrl() { - const restCatalogPrefix = Configuration.get('restCatalogPrefix'); - return `${restCatalogPrefix}/v1/categories/resources/`; + const restCatalogPrefix = Configuration.get('restCatalogPrefix'); + return `${restCatalogPrefix}/v1/categories/resources/`; } function uploadFile(vspId, formData, version) { - return RestAPIUtil.post(`${baseUrl()}${vspId}/versions/${version.id}/orchestration-template-candidate`, formData); - + return RestAPIUtil.post( + `${baseUrl()}${vspId}/versions/${ + version.id + }/orchestration-template-candidate`, + formData + ); } -function putSoftwareProduct({softwareProduct, version}) { - return RestAPIUtil.put(`${baseUrl()}${softwareProduct.id}/versions/${version.id}`, { - name: softwareProduct.name, - description: softwareProduct.description, - category: softwareProduct.category, - subCategory: softwareProduct.subCategory, - vendorId: softwareProduct.vendorId, - vendorName: softwareProduct.vendorName, - licensingVersion: softwareProduct.licensingVersion ? softwareProduct.licensingVersion : undefined, - icon: softwareProduct.icon, - licensingData: getLicensingData(softwareProduct.licensingData) - }); +function putSoftwareProduct({ softwareProduct, version }) { + return RestAPIUtil.put( + `${baseUrl()}${softwareProduct.id}/versions/${version.id}`, + { + name: softwareProduct.name, + description: softwareProduct.description, + category: softwareProduct.category, + subCategory: softwareProduct.subCategory, + vendorId: softwareProduct.vendorId, + vendorName: softwareProduct.vendorName, + licensingVersion: softwareProduct.licensingVersion + ? softwareProduct.licensingVersion + : undefined, + icon: softwareProduct.icon, + licensingData: getLicensingData(softwareProduct.licensingData) + } + ); } function putSoftwareProductQuestionnaire(vspId, qdata, version) { - return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/questionnaire`, qdata); + return RestAPIUtil.put( + `${baseUrl()}${vspId}/versions/${version.id}/questionnaire`, + qdata + ); } function putSoftwareProductAction(id, action, version) { - return RestAPIUtil.put(`${baseUrl()}${id}/versions/${version.id}/actions`, {action: action}); + return RestAPIUtil.put(`${baseUrl()}${id}/versions/${version.id}/actions`, { + action: action + }); } function fetchSoftwareProductList() { - return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}`); + return RestAPIUtil.fetch( + `${baseUrl()}?versionFilter=${catalogItemStatuses.DRAFT}` + ); } function fetchArchivedSoftwareProductList() { - return RestAPIUtil.fetch(`${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}`); + return RestAPIUtil.fetch( + `${baseUrl()}?Status=${catalogItemStatuses.ARCHIVED}` + ); } function fetchFinalizedSoftwareProductList() { - return RestAPIUtil.fetch(`${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}`); + return RestAPIUtil.fetch( + `${baseUrl()}?versionFilter=${catalogItemStatuses.CERTIFIED}` + ); } function fetchSoftwareProduct(vspId, version) { - return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}`); + return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}`); } function fetchSoftwareProductQuestionnaire(vspId, version) { - return RestAPIUtil.fetch(`${baseUrl()}${vspId}/versions/${version.id}/questionnaire`); + return RestAPIUtil.fetch( + `${baseUrl()}${vspId}/versions/${version.id}/questionnaire` + ); } -function updateSoftwareProductHeatCandidate(softwareProductId, heatCandidate, version) { - return RestAPIUtil.put(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/manifest`, heatCandidate); +function updateSoftwareProductHeatCandidate( + softwareProductId, + heatCandidate, + version +) { + return RestAPIUtil.put( + `${baseUrl()}${softwareProductId}/versions/${ + version.id + }/orchestration-template-candidate/manifest`, + heatCandidate + ); } function validateHeatCandidate(softwareProductId, version) { - return RestAPIUtil.put(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/process`); + return RestAPIUtil.put( + `${baseUrl()}${softwareProductId}/versions/${ + version.id + }/orchestration-template-candidate/process` + ); } -function fetchOrchestrationTemplateCandidate(softwareProductId, version, ) { - return RestAPIUtil.fetch(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate`, {dataType: 'binary'}); +function fetchOrchestrationTemplateCandidate(softwareProductId, version) { + return RestAPIUtil.fetch( + `${baseUrl()}${softwareProductId}/versions/${ + version.id + }/orchestration-template-candidate`, + { dataType: 'binary' } + ); } function abortValidationProcess(softwareProductId, version) { - return RestAPIUtil.destroy(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate`); + return RestAPIUtil.destroy( + `${baseUrl()}${softwareProductId}/versions/${ + version.id + }/orchestration-template-candidate` + ); } function objToString(obj) { - let str = ''; - if (obj instanceof Array) { - obj.forEach((item) => { - str += objToString(item) + '\n'; - }); - } - else { - for (let p in obj) { - if (obj.hasOwnProperty(p)) { - str += obj[p] + '\n'; - } - } - } - return str.replace(/\n$/, ''); + let str = ''; + if (obj instanceof Array) { + obj.forEach(item => { + str += objToString(item) + '\n'; + }); + } else { + for (let p in obj) { + if (obj.hasOwnProperty(p)) { + str += obj[p] + '\n'; + } + } + } + return str.replace(/\n$/, ''); } function parseUploadErrorMsg(error) { - let message = ''; - for (let key in error) { - if (error.hasOwnProperty(key)) { - message += objToString(error[key]) + '\n'; - } - } - return message.replace(/\n$/, ''); + let message = ''; + for (let key in error) { + if (error.hasOwnProperty(key)) { + message += objToString(error[key]) + '\n'; + } + } + return message.replace(/\n$/, ''); } function fetchSoftwareProductCategories(dispatch) { - let handleResponse = response => dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED, - softwareProductCategories: response - }); - return RestAPIUtil.fetch(softwareProductCategoriesUrl()) - .then(handleResponse) - .catch(() => handleResponse(null)); + let handleResponse = response => + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED, + softwareProductCategories: response + }); + return RestAPIUtil.fetch(softwareProductCategoriesUrl()) + .then(handleResponse) + .catch(() => handleResponse(null)); } -function loadLicensingData(dispatch, {licenseModelId, licensingVersion}) { - return ItemsHelper.fetchVersion({itemId: licenseModelId, versionId: licensingVersion}).then(() => { - return Promise.all([ - LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, {licenseModelId, version: {id: licensingVersion}}), - FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, {licenseModelId, version: {id: licensingVersion}}) - ]); - }); +function loadLicensingData(dispatch, { licenseModelId, licensingVersion }) { + return ItemsHelper.fetchVersion({ + itemId: licenseModelId, + versionId: licensingVersion + }).then(() => { + return Promise.all([ + LicenseAgreementActionHelper.fetchLicenseAgreementList(dispatch, { + licenseModelId, + version: { id: licensingVersion } + }), + FeatureGroupsActionHelper.fetchFeatureGroupsList(dispatch, { + licenseModelId, + version: { id: licensingVersion } + }) + ]); + }); } function getExpandedItemsId(items, itemIdToToggle) { - for (let i = 0; i < items.length; i++) { - if (items[i].id === itemIdToToggle) { - if (items[i].expanded) { - return {}; - } - else { - return {[itemIdToToggle]: true}; - } - } - else if (items[i].items && items[i].items.length > 0) { - let mapOfExpandedIds = getExpandedItemsId(items[i].items, itemIdToToggle); - if (mapOfExpandedIds !== false) { - mapOfExpandedIds[items[i].id] = true; - return mapOfExpandedIds; - } - } - } - return false; + for (let i = 0; i < items.length; i++) { + if (items[i].id === itemIdToToggle) { + if (items[i].expanded) { + return {}; + } else { + return { [itemIdToToggle]: true }; + } + } else if (items[i].items && items[i].items.length > 0) { + let mapOfExpandedIds = getExpandedItemsId( + items[i].items, + itemIdToToggle + ); + if (mapOfExpandedIds !== false) { + mapOfExpandedIds[items[i].id] = true; + return mapOfExpandedIds; + } + } + } + return false; } function migrateSoftwareProduct(vspId, version) { - return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`); + return RestAPIUtil.put(`${baseUrl()}${vspId}/versions/${version.id}/heal`); } - - const SoftwareProductActionHelper = { - - fetchFinalizedSoftwareProductList(dispatch) { - return fetchFinalizedSoftwareProductList().then(response => dispatch({ - type: actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED, - response - })); - }, - - fetchArchivedSoftwareProductList(dispatch) { - return fetchArchivedSoftwareProductList().then(response => dispatch({ - type: actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED, - response - })); - }, - - loadSoftwareProductAssociatedData(dispatch) { - fetchSoftwareProductCategories(dispatch); - LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch); - }, - - loadSoftwareProductDetailsData(dispatch, {licenseModelId, licensingVersion}) { - SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch); - if (licensingVersion) { - return loadLicensingData(dispatch, {licenseModelId, licensingVersion}); - } - return Promise.resolve(); - }, - - fetchSoftwareProductList(dispatch) { - return fetchSoftwareProductList().then(response => dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_LIST_LOADED, - response - })); - }, - - loadSoftwareProductHeatCandidate(dispatch, {softwareProductId, version}){ - return RestAPIUtil.fetch(`${baseUrl()}${softwareProductId}/versions/${version.id}/orchestration-template-candidate/manifest`).then(response => dispatch({ - type: HeatSetupActions.MANIFEST_LOADED, - response - })); - }, - - loadLicensingVersionsList(dispatch, {licenseModelId}){ - return ItemsHelper.fetchVersions({itemId: licenseModelId}).then(response => { - dispatch({ - type: actionTypes.LOAD_LICENSING_VERSIONS_LIST, - licensingVersionsList: response.results - }); - }); - }, - updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version}){ - return updateSoftwareProductHeatCandidate(softwareProductId, heatCandidate, version); - }, - - processAndValidateHeatCandidate(dispatch, {softwareProductId, version}){ - return validateHeatCandidate(softwareProductId, version).then(response => { - if (response.status === 'Success') { - SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents(dispatch, {softwareProductId, version}); - SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version}); - } else { - SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, {softwareProductId, version}); - } - }); - }, - - uploadFile(dispatch, {softwareProductId, formData, failedNotificationTitle, version}) { - dispatch({ - type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, - payload: {} - }); - - Promise.resolve() - .then(() => uploadFile(softwareProductId, formData, version)) - .then(response => { - if (response.status === 'Success') { - dispatch({ - type: commonActionTypes.DATA_CHANGED, - deltaData: {onboardingOrigin: response.onboardingOrigin}, - formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS - }); - switch(response.onboardingOrigin){ - case onboardingOriginTypes.ZIP: - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }); - dispatch({ - type: actionTypes.CANDIDATE_IN_PROCESS, - inProcess: true - }); - break; - case onboardingOriginTypes.CSAR: - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }); - break; - } - } - else { - throw new Error(parseUploadErrorMsg(response.errors)); - } - }) - .catch(error => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: failedNotificationTitle, - msg: error.message || (error.responseJSON && error.responseJSON.message) - } - }); - }); - }, - - downloadHeatFile(dispatch, {softwareProductId, heatCandidate, isReadOnlyMode, version}){ - let p = isReadOnlyMode ? Promise.resolve() : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, { - softwareProductId, - heatCandidate, - version}); - p.then(() => { - fetchOrchestrationTemplateCandidate(softwareProductId, version) - .then((response) => { - showFileSaveDialog({ - blob: response.blob, - headers: response.headers, - defaultFilename: 'HEAT_file.zip', - addTimestamp: true - }); - }); - }, null/* do not download if data was not saved correctly*/); - }, - - hideUploadConfirm (dispatch) { - dispatch({ - type: actionTypes.softwareProductEditor.UPLOAD_CONFIRMATION - }); - }, - updateSoftwareProduct(dispatch, {softwareProduct, version, qdata}) { - return Promise.all([ - SoftwareProductActionHelper.updateSoftwareProductData(dispatch, {softwareProduct, version}).then( - () => dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_LIST_EDIT, - payload: {softwareProduct} - }) - ), - SoftwareProductActionHelper.updateSoftwareProductQuestionnaire(dispatch, { - softwareProductId: softwareProduct.id, - qdata, - version - }) - ]); - }, - - updateSoftwareProductData(dispatch, {softwareProduct, version}) { - return putSoftwareProduct({softwareProduct, version}); - }, - - updateSoftwareProductQuestionnaire(dispatch, {softwareProductId, qdata, version}) { - return putSoftwareProductQuestionnaire(softwareProductId, qdata, version); - }, - - softwareProductEditorDataChanged(dispatch, {deltaData}) { - dispatch({ - type: actionTypes.softwareProductEditor.DATA_CHANGED, - deltaData - }); - }, - - softwareProductQuestionnaireUpdate(dispatch, {data}) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE, - payload: {qdata: data} - }); - }, - - softwareProductEditorVendorChanged(dispatch, {deltaData, formName}) { - if (deltaData.licensingVersion){ - return loadLicensingData(dispatch, {licenseModelId: deltaData.vendorId, licensingVersion: deltaData.licensingVersion}).then(() => { - ValidationHelper.dataChanged(dispatch, {deltaData, formName}); - return Promise.resolve(); - }); - } else if (deltaData.vendorId) { - ValidationHelper.dataChanged(dispatch, {deltaData, formName}); - return SoftwareProductActionHelper.loadLicensingVersionsList(dispatch, { - licenseModelId: deltaData.vendorId - }).then( () => - OnboardingActionHelper.forceBreadCrumbsUpdate(dispatch) - ); - } else { - ValidationHelper.dataChanged(dispatch, {deltaData, formName}); - - dispatch({ - type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED, - response: {results: []} - }); - - dispatch({ - type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED, - response: {results: []} - }); - } - - }, - - setIsValidityData(dispatch, {isValidityData}) { - dispatch({ - type: actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED, - isValidityData - }); - }, - - fetchSoftwareProduct(dispatch, {softwareProductId, version}) { - return Promise.all([ - fetchSoftwareProduct(softwareProductId, version).then(response => { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_LOADED, - response - }); - return response; - }), - fetchSoftwareProductQuestionnaire(softwareProductId, version).then(response => { - ValidationHelper.qDataLoaded(dispatch, {response: {qdata: response.data ? JSON.parse(response.data) : {}, - qschema: JSON.parse(response.schema)}, qName: PRODUCT_QUESTIONNAIRE}); - }) - ]); - }, - - manageSubmitAction(dispatch, {softwareProductId, version, isDirty}) { - if (isDirty) { - const onCommit = comment => { - return this.performVCAction(dispatch, {softwareProductId, action: VersionControllerActionsEnum.COMMIT, version, comment}).then(() => { - return this.performSubmitAction(dispatch, {softwareProductId, version}); - }); - }; - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.COMMIT_COMMENT, - modalComponentProps: { - onCommit, - type: CommitModalType.COMMIT_SUBMIT - }, - title: i18n('Commit & Submit') - } - }); - return Promise.resolve(version); - } - return this.performSubmitAction(dispatch, {softwareProductId, version}); - }, - - performSubmitAction(dispatch, {softwareProductId, version}) { - return putSoftwareProductAction(softwareProductId, VersionControllerActionsEnum.SUBMIT, version).then(() => { - return putSoftwareProductAction(softwareProductId, VersionControllerActionsEnum.CREATE_PACKAGE, version).then(() => { - return ItemsHelper.checkItemStatus(dispatch, {itemId: softwareProductId, versionId: version.id}).then(updatedVersion => { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SUCCESS, - data: { - title: i18n('Submit Succeeded'), - msg: i18n('This software product successfully submitted'), - cancelButtonText: i18n('OK'), - timeout: 2000 - } - }); - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.SOFTWARE_PRODUCT, itemId: softwareProductId}); - return Promise.resolve(updatedVersion); - }); - }); - }, error => - { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - modalComponentName: modalContentMapper.SUMBIT_ERROR_RESPONSE, - title: i18n('Submit Failed'), - modalComponentProps: { - validationResponse: error.responseJSON - }, - cancelButtonText: i18n('OK') - } - }); - return Promise.reject(error.responseJSON); - }); - }, - - performVCAction(dispatch, {softwareProductId, action, version, comment}) { - return MergeEditorActionHelper.analyzeSyncResult(dispatch, {itemId: softwareProductId, version}).then(({inMerge, isDirty, updatedVersion}) => { - if ((updatedVersion.status === catalogItemStatuses.CERTIFIED || updatedVersion.archivedStatus === catalogItemStatuses.ARCHIVED) && - (action === VersionControllerActionsEnum.COMMIT || action === VersionControllerActionsEnum.SYNC)) { - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.SOFTWARE_PRODUCT, itemId: softwareProductId}); - const msg = updatedVersion.archivedStatus === catalogItemStatuses.ARCHIVED ? i18n('Item was Archived') : i18n('Item version already Certified'); - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Commit error'), - msg, - cancelButtonText: i18n('Cancel') - } - }); - return Promise.resolve(updatedVersion); - } - if (!inMerge) { - if (action === VersionControllerActionsEnum.SUBMIT) { - return this.manageSubmitAction(dispatch, {softwareProductId, version, isDirty}); - } - else { - let isCallActionValid = action !== VersionControllerActionsEnum.COMMIT || isDirty; - if(isCallActionValid) { - return ItemsHelper.performVCAction({itemId: softwareProductId, action, version, comment}).then(() => { - versionPageActionHelper.fetchVersions(dispatch, {itemType: itemTypes.LICENSE_MODEL, itemId: softwareProductId}); - if (action === VersionControllerActionsEnum.SYNC) { - return MergeEditorActionHelper.analyzeSyncResult(dispatch, {itemId: softwareProductId, version}).then(({updatedVersion}) => { - return Promise.resolve(updatedVersion); - }); - } else { - return ItemsHelper.checkItemStatus(dispatch, {itemId: softwareProductId, versionId: version.id}); - } - }); - } - else { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Commit Failed'), - msg: i18n('There is nothing to commit') - } - }); - } - } - } - }); - }, - - toggleNavigationItems(dispatch, {items, itemIdToExpand}) { - let mapOfExpandedIds = getExpandedItemsId(items, itemIdToExpand); - dispatch({ - type: actionTypes.TOGGLE_NAVIGATION_ITEM, - mapOfExpandedIds - }); - }, - - /** for the next verision */ - addComponent(dispatch, {softwareProductId, modalClassName, version}) { - SoftwareProductComponentsActionHelper.clearComponentCreationData(dispatch); - dispatch({ - type: componentActionTypes.COMPONENT_CREATE_OPEN - }); - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.COMPONENT_CREATION, - modalComponentProps: {softwareProductId, version}, - modalClassName, - title: 'Create Virtual Function Component' - } - }); - }, - - migrateSoftwareProduct(dispatch, {softwareProduct}) { - let {id: softwareProductId, version} = softwareProduct; - const newVer = version.id; - migrateSoftwareProduct(softwareProductId, version).then(() => ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version: {id: newVer, label: newVer}} - })); - }, - - abortCandidateValidation(dispatch, {softwareProductId, version}) { - return abortValidationProcess(softwareProductId, version); - } - + fetchFinalizedSoftwareProductList(dispatch) { + return fetchFinalizedSoftwareProductList().then(response => + dispatch({ + type: actionTypes.FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED, + response + }) + ); + }, + + fetchArchivedSoftwareProductList(dispatch) { + return fetchArchivedSoftwareProductList().then(response => + dispatch({ + type: actionTypes.ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED, + response + }) + ); + }, + + loadSoftwareProductAssociatedData(dispatch) { + fetchSoftwareProductCategories(dispatch); + LicenseModelActionHelper.fetchFinalizedLicenseModels(dispatch); + }, + + loadSoftwareProductDetailsData( + dispatch, + { licenseModelId, licensingVersion } + ) { + SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch); + if (licensingVersion) { + return loadLicensingData(dispatch, { + licenseModelId, + licensingVersion + }); + } + return Promise.resolve(); + }, + + fetchSoftwareProductList(dispatch) { + return fetchSoftwareProductList().then(response => + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_LIST_LOADED, + response + }) + ); + }, + + loadSoftwareProductHeatCandidate(dispatch, { softwareProductId, version }) { + return RestAPIUtil.fetch( + `${baseUrl()}${softwareProductId}/versions/${ + version.id + }/orchestration-template-candidate/manifest` + ).then(response => + dispatch({ + type: HeatSetupActions.MANIFEST_LOADED, + response + }) + ); + }, + + loadLicensingVersionsList(dispatch, { licenseModelId }) { + return ItemsHelper.fetchVersions({ itemId: licenseModelId }).then( + response => { + dispatch({ + type: actionTypes.LOAD_LICENSING_VERSIONS_LIST, + licensingVersionsList: response.results + }); + } + ); + }, + updateSoftwareProductHeatCandidate( + dispatch, + { softwareProductId, heatCandidate, version } + ) { + return updateSoftwareProductHeatCandidate( + softwareProductId, + heatCandidate, + version + ); + }, + + processAndValidateHeatCandidate(dispatch, { softwareProductId, version }) { + return validateHeatCandidate(softwareProductId, version).then( + response => { + if (response.status === 'Success') { + SoftwareProductComponentsActionHelper.fetchSoftwareProductComponents( + dispatch, + { softwareProductId, version } + ); + SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, { + softwareProductId, + version + }); + } else { + SoftwareProductActionHelper.fetchSoftwareProduct(dispatch, { + softwareProductId, + version + }); + } + } + ); + }, + + uploadFile( + dispatch, + { softwareProductId, formData, failedNotificationTitle, version } + ) { + dispatch({ + type: HeatSetupActions.FILL_HEAT_SETUP_CACHE, + payload: {} + }); + + Promise.resolve() + .then(() => uploadFile(softwareProductId, formData, version)) + .then(response => { + if (response.status === 'Success') { + dispatch({ + type: commonActionTypes.DATA_CHANGED, + deltaData: { + onboardingOrigin: response.onboardingOrigin + }, + formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + }); + switch (response.onboardingOrigin) { + case onboardingOriginTypes.ZIP: + ScreensHelper.loadScreen(dispatch, { + screen: + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_SETUP, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }); + dispatch({ + type: actionTypes.CANDIDATE_IN_PROCESS, + inProcess: true + }); + break; + case onboardingOriginTypes.CSAR: + ScreensHelper.loadScreen(dispatch, { + screen: + enums.SCREEN + .SOFTWARE_PRODUCT_ATTACHMENTS_VALIDATION, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }); + break; + } + } else { + throw new Error(parseUploadErrorMsg(response.errors)); + } + }) + .catch(error => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: failedNotificationTitle, + msg: + error.message || + (error.responseJSON && error.responseJSON.message) + } + }); + }); + }, + + downloadHeatFile( + dispatch, + { softwareProductId, heatCandidate, isReadOnlyMode, version } + ) { + let p = isReadOnlyMode + ? Promise.resolve() + : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate( + dispatch, + { + softwareProductId, + heatCandidate, + version + } + ); + p.then(() => { + fetchOrchestrationTemplateCandidate( + softwareProductId, + version + ).then(response => { + showFileSaveDialog({ + blob: response.blob, + headers: response.headers, + defaultFilename: 'HEAT_file.zip', + addTimestamp: true + }); + }); + }, null /* do not download if data was not saved correctly*/); + }, + + hideUploadConfirm(dispatch) { + dispatch({ + type: actionTypes.softwareProductEditor.UPLOAD_CONFIRMATION + }); + }, + updateSoftwareProduct(dispatch, { softwareProduct, version, qdata }) { + return Promise.all([ + SoftwareProductActionHelper.updateSoftwareProductData(dispatch, { + softwareProduct, + version + }).then(() => + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_LIST_EDIT, + payload: { softwareProduct } + }) + ), + SoftwareProductActionHelper.updateSoftwareProductQuestionnaire( + dispatch, + { + softwareProductId: softwareProduct.id, + qdata, + version + } + ) + ]); + }, + + updateSoftwareProductData(dispatch, { softwareProduct, version }) { + return putSoftwareProduct({ softwareProduct, version }); + }, + + updateSoftwareProductQuestionnaire( + dispatch, + { softwareProductId, qdata, version } + ) { + return putSoftwareProductQuestionnaire( + softwareProductId, + qdata, + version + ); + }, + + softwareProductEditorDataChanged(dispatch, { deltaData }) { + dispatch({ + type: actionTypes.softwareProductEditor.DATA_CHANGED, + deltaData + }); + }, + + softwareProductQuestionnaireUpdate(dispatch, { data }) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE, + payload: { qdata: data } + }); + }, + + softwareProductEditorVendorChanged(dispatch, { deltaData, formName }) { + if (deltaData.licensingVersion) { + return loadLicensingData(dispatch, { + licenseModelId: deltaData.vendorId, + licensingVersion: deltaData.licensingVersion + }).then(() => { + ValidationHelper.dataChanged(dispatch, { deltaData, formName }); + return Promise.resolve(); + }); + } else if (deltaData.vendorId) { + ValidationHelper.dataChanged(dispatch, { deltaData, formName }); + return SoftwareProductActionHelper.loadLicensingVersionsList( + dispatch, + { + licenseModelId: deltaData.vendorId + } + ).then(() => + OnboardingActionHelper.forceBreadCrumbsUpdate(dispatch) + ); + } else { + ValidationHelper.dataChanged(dispatch, { deltaData, formName }); + + dispatch({ + type: licenseAgreementActionTypes.LICENSE_AGREEMENT_LIST_LOADED, + response: { results: [] } + }); + + dispatch({ + type: featureGroupsActionConstants.FEATURE_GROUPS_LIST_LOADED, + response: { results: [] } + }); + } + }, + + setIsValidityData(dispatch, { isValidityData }) { + dispatch({ + type: actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED, + isValidityData + }); + }, + + fetchSoftwareProduct(dispatch, { softwareProductId, version }) { + return Promise.all([ + fetchSoftwareProduct(softwareProductId, version).then(response => { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_LOADED, + response + }); + return response; + }), + fetchSoftwareProductQuestionnaire(softwareProductId, version).then( + response => { + ValidationHelper.qDataLoaded(dispatch, { + response: { + qdata: response.data + ? JSON.parse(response.data) + : {}, + qschema: JSON.parse(response.schema) + }, + qName: PRODUCT_QUESTIONNAIRE + }); + } + ) + ]); + }, + + manageSubmitAction(dispatch, { softwareProductId, version, isDirty }) { + if (isDirty) { + const onCommit = comment => { + return this.performVCAction(dispatch, { + softwareProductId, + action: VersionControllerActionsEnum.COMMIT, + version, + comment + }).then(() => { + return this.performSubmitAction(dispatch, { + softwareProductId, + version + }); + }); + }; + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMMIT_COMMENT, + modalComponentProps: { + onCommit, + type: CommitModalType.COMMIT_SUBMIT + }, + title: i18n('Commit & Submit') + } + }); + return Promise.resolve(version); + } + return this.performSubmitAction(dispatch, { + softwareProductId, + version + }); + }, + + performSubmitAction(dispatch, { softwareProductId, version }) { + return putSoftwareProductAction( + softwareProductId, + VersionControllerActionsEnum.SUBMIT, + version + ).then( + () => { + return putSoftwareProductAction( + softwareProductId, + VersionControllerActionsEnum.CREATE_PACKAGE, + version + ).then(() => { + return ItemsHelper.checkItemStatus(dispatch, { + itemId: softwareProductId, + versionId: version.id + }).then(updatedVersion => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SUCCESS, + data: { + title: i18n('Submit Succeeded'), + msg: i18n( + 'This software product successfully submitted' + ), + cancelButtonText: i18n('OK'), + timeout: 2000 + } + }); + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.SOFTWARE_PRODUCT, + itemId: softwareProductId + }); + return Promise.resolve(updatedVersion); + }); + }); + }, + error => { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + modalComponentName: + modalContentMapper.SUMBIT_ERROR_RESPONSE, + title: i18n('Submit Failed'), + modalComponentProps: { + validationResponse: error.responseJSON + }, + cancelButtonText: i18n('OK') + } + }); + return Promise.reject(error.responseJSON); + } + ); + }, + + performVCAction(dispatch, { softwareProductId, action, version, comment }) { + return MergeEditorActionHelper.analyzeSyncResult(dispatch, { + itemId: softwareProductId, + version + }).then(({ inMerge, isDirty, updatedVersion }) => { + if ( + (updatedVersion.status === catalogItemStatuses.CERTIFIED || + updatedVersion.archivedStatus === + catalogItemStatuses.ARCHIVED) && + (action === VersionControllerActionsEnum.COMMIT || + action === VersionControllerActionsEnum.SYNC) + ) { + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.SOFTWARE_PRODUCT, + itemId: softwareProductId + }); + const msg = + updatedVersion.archivedStatus === + catalogItemStatuses.ARCHIVED + ? i18n('Item was Archived') + : i18n('Item version already Certified'); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Commit error'), + msg, + cancelButtonText: i18n('Cancel') + } + }); + return Promise.resolve(updatedVersion); + } + if (!inMerge) { + if (action === VersionControllerActionsEnum.SUBMIT) { + return this.manageSubmitAction(dispatch, { + softwareProductId, + version, + isDirty + }); + } else { + let isCallActionValid = + action !== VersionControllerActionsEnum.COMMIT || + isDirty; + if (isCallActionValid) { + return ItemsHelper.performVCAction({ + itemId: softwareProductId, + action, + version, + comment + }).then(() => { + versionPageActionHelper.fetchVersions(dispatch, { + itemType: itemTypes.LICENSE_MODEL, + itemId: softwareProductId + }); + if (action === VersionControllerActionsEnum.SYNC) { + return MergeEditorActionHelper.analyzeSyncResult( + dispatch, + { itemId: softwareProductId, version } + ).then(({ updatedVersion }) => { + return Promise.resolve(updatedVersion); + }); + } else { + return ItemsHelper.checkItemStatus(dispatch, { + itemId: softwareProductId, + versionId: version.id + }); + } + }); + } else { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Commit Failed'), + msg: i18n('There is nothing to commit') + } + }); + } + } + } + }); + }, + + toggleNavigationItems(dispatch, { items, itemIdToExpand }) { + let mapOfExpandedIds = getExpandedItemsId(items, itemIdToExpand); + dispatch({ + type: actionTypes.TOGGLE_NAVIGATION_ITEM, + mapOfExpandedIds + }); + }, + + /** for the next verision */ + addComponent(dispatch, { softwareProductId, modalClassName, version }) { + SoftwareProductComponentsActionHelper.clearComponentCreationData( + dispatch + ); + dispatch({ + type: componentActionTypes.COMPONENT_CREATE_OPEN + }); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.COMPONENT_CREATION, + modalComponentProps: { softwareProductId, version }, + modalClassName, + title: 'Create Virtual Function Component' + } + }); + }, + + migrateSoftwareProduct(dispatch, { softwareProduct }) { + let { id: softwareProductId, version } = softwareProduct; + const newVer = version.id; + migrateSoftwareProduct(softwareProductId, version).then(() => + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { + softwareProductId, + version: { id: newVer, label: newVer } + } + }) + ); + }, + + abortCandidateValidation(dispatch, { softwareProductId, version }) { + return abortValidationProcess(softwareProductId, version); + } }; export default SoftwareProductActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js index 9b147415f9..d1ba947f81 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js @@ -14,17 +14,21 @@ * permissions and limitations under the License. */ export default { - - getCurrentCategoryOfSubCategory(selectedSubCategory, softwareProductCategories) { - let category, subCategory; - for (var i = 0; i < softwareProductCategories.length; i++) { - let {subcategories = []} = softwareProductCategories[i]; - subCategory = subcategories.find(sub => sub.uniqueId === selectedSubCategory); - if (subCategory) { - category = softwareProductCategories[i].uniqueId; - break; - } - } - return category; - } + getCurrentCategoryOfSubCategory( + selectedSubCategory, + softwareProductCategories + ) { + let category, subCategory; + for (var i = 0; i < softwareProductCategories.length; i++) { + let { subcategories = [] } = softwareProductCategories[i]; + subCategory = subcategories.find( + sub => sub.uniqueId === selectedSubCategory + ); + if (subCategory) { + category = softwareProductCategories[i].uniqueId; + break; + } + } + return category; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js index d33eb822cf..711bbf8db8 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js @@ -16,41 +16,38 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - SOFTWARE_PRODUCT_LOADED: null, - SOFTWARE_PRODUCT_LIST_LOADED: null, - ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED: null, - FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED: null, - SOFTWARE_PRODUCT_LIST_EDIT: null, - SOFTWARE_PRODUCT_CATEGORIES_LOADED: null, - SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE: null, - LOAD_LICENSING_VERSIONS_LIST: null, - TOGGLE_NAVIGATION_ITEM: null, - CANDIDATE_IN_PROCESS: null, - - softwareProductEditor: { - OPEN: null, - CLOSE: null, - DATA_CHANGED: null, - IS_VALIDITY_DATA_CHANGED: null - } + SOFTWARE_PRODUCT_LOADED: null, + SOFTWARE_PRODUCT_LIST_LOADED: null, + ARCHIVED_SOFTWARE_PRODUCT_LIST_LOADED: null, + FINALIZED_SOFTWARE_PRODUCT_LIST_LOADED: null, + SOFTWARE_PRODUCT_LIST_EDIT: null, + SOFTWARE_PRODUCT_CATEGORIES_LOADED: null, + SOFTWARE_PRODUCT_QUESTIONNAIRE_UPDATE: null, + LOAD_LICENSING_VERSIONS_LIST: null, + TOGGLE_NAVIGATION_ITEM: null, + CANDIDATE_IN_PROCESS: null, + + softwareProductEditor: { + OPEN: null, + CLOSE: null, + DATA_CHANGED: null, + IS_VALIDITY_DATA_CHANGED: null + } }); - - export const onboardingMethod = { - MANUAL: 'Manual', - NETWORK_PACKAGE: 'NetworkPackage' + MANUAL: 'Manual', + NETWORK_PACKAGE: 'NetworkPackage' }; export const onboardingOriginTypes = { - NONE: 'none', - ZIP: 'zip', - CSAR: 'csar' + NONE: 'none', + ZIP: 'zip', + CSAR: 'csar' }; export const forms = keyMirror({ - VENDOR_SOFTWARE_PRODUCT_DETAILS: 'vendor-software-product-details', + VENDOR_SOFTWARE_PRODUCT_DETAILS: 'vendor-software-product-details' }); export const PRODUCT_QUESTIONNAIRE = 'product'; - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductListReducer.js index 31be338ff5..f52153a29f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductListReducer.js @@ -13,16 +13,22 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductConstants.js'; +import { actionTypes } from './SoftwareProductConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.SOFTWARE_PRODUCT_LIST_LOADED: - return [...action.response.results]; - case actionTypes.SOFTWARE_PRODUCT_LIST_EDIT: - const indexForEdit = state.findIndex(vsp => vsp.id === action.payload.softwareProduct.id); - return [...state.slice(0, indexForEdit), action.payload.softwareProduct, ...state.slice(indexForEdit + 1)]; - default: - return state; - } + switch (action.type) { + case actionTypes.SOFTWARE_PRODUCT_LIST_LOADED: + return [...action.response.results]; + case actionTypes.SOFTWARE_PRODUCT_LIST_EDIT: + const indexForEdit = state.findIndex( + vsp => vsp.id === action.payload.softwareProduct.id + ); + return [ + ...state.slice(0, indexForEdit), + action.payload.softwareProduct, + ...state.slice(indexForEdit + 1) + ]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js index d7a6c2ef5c..f3de517a1c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/SoftwareProductReducer.js @@ -13,12 +13,15 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {combineReducers} from 'redux'; -import {actionTypes, PRODUCT_QUESTIONNAIRE} from './SoftwareProductConstants.js'; +import { combineReducers } from 'redux'; +import { + actionTypes, + PRODUCT_QUESTIONNAIRE +} from './SoftwareProductConstants.js'; import SoftwareProductAttachmentsReducer from './attachments/SoftwareProductAttachmentsReducer.js'; import HeatValidationReducer from './attachments/validation/HeatValidationReducer.js'; import HeatSetupReducer from './attachments/setup/HeatSetupReducer.js'; -import {actionTypes as heatSetupActionTypes} from './attachments/setup/HeatSetupConstants.js'; +import { actionTypes as heatSetupActionTypes } from './attachments/setup/HeatSetupConstants.js'; import SoftwareProductCreationReducer from './creation/SoftwareProductCreationReducer.js'; import SoftwareProductDetailsReducer from './details/SoftwareProductDetailsReducer.js'; import SoftwareProductProcessesListReducer from './processes/SoftwareProductProcessesListReducer.js'; @@ -28,10 +31,10 @@ import SoftwareProductDeploymentEditorReducer from './deployment/editor/Software import SoftwareProductNetworksListReducer from './networks/SoftwareProductNetworksListReducer.js'; import SoftwareProductComponentsListReducer from './components/SoftwareProductComponentsListReducer.js'; import SoftwareProductComponentEditorReducer from './components/SoftwareProductComponentEditorReducer.js'; -import {actionTypes as processesActionTypes} from './processes/SoftwareProductProcessesConstants.js'; -import SoftwareProductComponentProcessesListReducer from './components/processes/SoftwareProductComponentProcessesListReducer.js'; +import { actionTypes as processesActionTypes } from './processes/SoftwareProductProcessesConstants.js'; +import SoftwareProductComponentProcessesListReducer from './components/processes/SoftwareProductComponentProcessesListReducer.js'; import SoftwareProductComponentProcessesEditorReducer from './components/processes/SoftwareProductComponentProcessesEditorReducer.js'; -import {actionTypes as componentProcessesActionTypes} from './components/processes/SoftwareProductComponentProcessesConstants.js'; +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'; @@ -40,63 +43,112 @@ import SoftwareProductComponentsNICCreationReducer from './components/network/NI 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 { 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, 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'; +import { + createJSONSchemaReducer, + createComposedJSONSchemaReducer +} from 'sdc-app/common/reducers/JSONSchemaReducer.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({ - attachmentsDetails: SoftwareProductAttachmentsReducer, - heatValidation: HeatValidationReducer, - heatSetup: HeatSetupReducer, - heatSetupCache: (state = {}, action) => action.type === heatSetupActionTypes.FILL_HEAT_SETUP_CACHE ? action.payload : state - }), - softwareProductCreation: createPlainDataReducer(SoftwareProductCreationReducer), - softwareProductEditor: createPlainDataReducer(SoftwareProductDetailsReducer), - softwareProductProcesses: combineReducers({ - processesList: SoftwareProductProcessesListReducer, - 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 - }), - softwareProductDependencies: SoftwareProductDependenciesReducer, - softwareProductComponents: combineReducers({ - componentsList: SoftwareProductComponentsListReducer, - componentEditor: createPlainDataReducer(createComposedJSONSchemaReducer(COMPONENTS_QUESTIONNAIRE, SoftwareProductComponentEditorReducer)), - componentProcesses: combineReducers({ - processesList: SoftwareProductComponentProcessesListReducer, - processesEditor: createPlainDataReducer(SoftwareProductComponentProcessesEditorReducer), - processToDelete: (state = false, action) => action.type === componentProcessesActionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM ? action.processToDelete : state, - }), - network: combineReducers({ - nicList: SoftwareProductComponentsNICListReducer, - nicEditor: createPlainDataReducer(createComposedJSONSchemaReducer(NIC_QUESTIONNAIRE, SoftwareProductComponentsNICEditorReducer)), - nicCreation: createPlainDataReducer(SoftwareProductComponentsNICCreationReducer) - }), - images: combineReducers({ - imagesList: SoftwareProductComponentsImageListReducer, - imageEditor: createPlainDataReducer(createComposedJSONSchemaReducer(IMAGE_QUESTIONNAIRE, SoftwareProductComponentsImageEditorReducer)) - }), - computeFlavor: combineReducers({ - computesList: SoftwareProductComponentsComputeFlavorListReducer, - computeEditor: createPlainDataReducer(createComposedJSONSchemaReducer(COMPONENTS_COMPUTE_QUESTIONNAIRE, SoftwareProductComponentsComputeFlavorReducer)), - }), - monitoring: SoftwareProductComponentsMonitoringReducer - }), - softwareProductCategories: (state = [], action) => { - if (action.type === actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED) { - return action.softwareProductCategories; - } - return state; - }, - softwareProductQuestionnaire: createJSONSchemaReducer(PRODUCT_QUESTIONNAIRE) + softwareProductAttachments: combineReducers({ + attachmentsDetails: SoftwareProductAttachmentsReducer, + heatValidation: HeatValidationReducer, + heatSetup: HeatSetupReducer, + heatSetupCache: (state = {}, action) => + action.type === heatSetupActionTypes.FILL_HEAT_SETUP_CACHE + ? action.payload + : state + }), + softwareProductCreation: createPlainDataReducer( + SoftwareProductCreationReducer + ), + softwareProductEditor: createPlainDataReducer( + SoftwareProductDetailsReducer + ), + softwareProductProcesses: combineReducers({ + processesList: SoftwareProductProcessesListReducer, + 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 + }), + softwareProductDependencies: SoftwareProductDependenciesReducer, + softwareProductComponents: combineReducers({ + componentsList: SoftwareProductComponentsListReducer, + componentEditor: createPlainDataReducer( + createComposedJSONSchemaReducer( + COMPONENTS_QUESTIONNAIRE, + SoftwareProductComponentEditorReducer + ) + ), + componentProcesses: combineReducers({ + processesList: SoftwareProductComponentProcessesListReducer, + processesEditor: createPlainDataReducer( + SoftwareProductComponentProcessesEditorReducer + ), + processToDelete: (state = false, action) => + action.type === + componentProcessesActionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM + ? action.processToDelete + : state + }), + network: combineReducers({ + nicList: SoftwareProductComponentsNICListReducer, + nicEditor: createPlainDataReducer( + createComposedJSONSchemaReducer( + NIC_QUESTIONNAIRE, + SoftwareProductComponentsNICEditorReducer + ) + ), + nicCreation: createPlainDataReducer( + SoftwareProductComponentsNICCreationReducer + ) + }), + images: combineReducers({ + imagesList: SoftwareProductComponentsImageListReducer, + imageEditor: createPlainDataReducer( + createComposedJSONSchemaReducer( + IMAGE_QUESTIONNAIRE, + SoftwareProductComponentsImageEditorReducer + ) + ) + }), + computeFlavor: combineReducers({ + computesList: SoftwareProductComponentsComputeFlavorListReducer, + computeEditor: createPlainDataReducer( + createComposedJSONSchemaReducer( + COMPONENTS_COMPUTE_QUESTIONNAIRE, + SoftwareProductComponentsComputeFlavorReducer + ) + ) + }), + monitoring: SoftwareProductComponentsMonitoringReducer + }), + softwareProductCategories: (state = [], action) => { + if (action.type === actionTypes.SOFTWARE_PRODUCT_CATEGORIES_LOADED) { + return action.softwareProductCategories; + } + return state; + }, + softwareProductQuestionnaire: createJSONSchemaReducer(PRODUCT_QUESTIONNAIRE) }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js index d942172973..4d5887be6f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachments.js @@ -13,100 +13,142 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; import HeatSetupActionHelper from './setup/HeatSetupActionHelper.js'; import SoftwareProductAttachmentsView from './SoftwareProductAttachmentsView.jsx'; -import {errorLevels} from 'sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js'; +import { errorLevels } from 'sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js'; import HeatSetup from './setup/HeatSetup.js'; -import {doesHeatDataExist} from './SoftwareProductAttachmentsUtils.js'; +import { doesHeatDataExist } from './SoftwareProductAttachmentsUtils.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import SoftwareProductAttachmentsActionHelper from './SoftwareProductAttachmentsActionHelper.js'; -export const mapStateToProps = (state) => { - let { - softwareProduct: { - softwareProductEditor:{data: currentSoftwareProduct = {}}, - softwareProductAttachments: {attachmentsDetails: {activeTab}, heatSetup, heatSetupCache, heatValidation : {errorList}} - } - } = state; +export const mapStateToProps = state => { + let { + softwareProduct: { + softwareProductEditor: { data: currentSoftwareProduct = {} }, + softwareProductAttachments: { + attachmentsDetails: { activeTab }, + heatSetup, + heatSetupCache, + heatValidation: { errorList } + } + } + } = state; - let {unassigned = [], modules = []} = heatSetup; - let goToOverview = true; - if (errorList) { - for (let i = 0 ; i < errorList.length ; i++) { - if (errorList[i].level === errorLevels.ERROR) { - goToOverview = false; - } - } - } - let heatDataExist = doesHeatDataExist(heatSetup); + let { unassigned = [], modules = [] } = heatSetup; + let goToOverview = true; + if (errorList) { + for (let i = 0; i < errorList.length; i++) { + if (errorList[i].level === errorLevels.ERROR) { + goToOverview = false; + } + } + } + let heatDataExist = doesHeatDataExist(heatSetup); - let {version, onboardingOrigin} = currentSoftwareProduct; - return { - isValidationAvailable: unassigned.length === 0 && modules.length > 0, - heatSetup, - heatSetupCache, - heatDataExist, - goToOverview, - HeatSetupComponent: HeatSetup, - version, - onboardingOrigin, - activeTab, - candidateInProcess: !!currentSoftwareProduct.candidateOnboardingOrigin - }; + let { version, onboardingOrigin } = currentSoftwareProduct; + return { + isValidationAvailable: unassigned.length === 0 && modules.length > 0, + heatSetup, + heatSetupCache, + heatDataExist, + goToOverview, + HeatSetupComponent: HeatSetup, + version, + onboardingOrigin, + activeTab, + candidateInProcess: !!currentSoftwareProduct.candidateOnboardingOrigin + }; }; -export const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onDownload: ({heatCandidate, isReadOnlyMode}) => SoftwareProductActionHelper.downloadHeatFile(dispatch, {softwareProductId, heatCandidate, isReadOnlyMode, version}), - onUpload: (formData) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Upload will erase existing data. Do you want to continue?'), - confirmationButtonText: i18n('Continue'), - title: i18n('WARNING'), +export const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onDownload: ({ heatCandidate, isReadOnlyMode }) => + SoftwareProductActionHelper.downloadHeatFile(dispatch, { + softwareProductId, + heatCandidate, + isReadOnlyMode, + version + }), + onUpload: formData => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n( + 'Upload will erase existing data. Do you want to continue?' + ), + confirmationButtonText: i18n('Continue'), + title: i18n('WARNING'), - onConfirmed: ()=>SoftwareProductActionHelper.uploadFile(dispatch, { - softwareProductId, - formData, - failedNotificationTitle: i18n('Upload validation failed'), - version - }) - } - }), - onUploadAbort: () => { - SoftwareProductActionHelper.abortCandidateValidation(dispatch, {softwareProductId, version}) - .then(()=>{ - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }); - }); - }, - onInvalidFileUpload: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Upload Failed'), - confirmationButtonText: i18n('Continue'), - msg: i18n('no zip or csar file was uploaded or expected file doesn\'t exist') - } - }), - onSave: (heatCandidate) => SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate, version}), - onGoToOverview: () => ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }), - onProcessAndValidate: ({heatData, heatDataCache, isReadOnlyMode}) => { - return HeatSetupActionHelper.processAndValidateHeat(dispatch, - {softwareProductId, heatData, heatDataCache, isReadOnlyMode, version}); - }, - setActiveTab: ({activeTab}) => SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, {activeTab}) - - }; + onConfirmed: () => + SoftwareProductActionHelper.uploadFile(dispatch, { + softwareProductId, + formData, + failedNotificationTitle: i18n( + 'Upload validation failed' + ), + version + }) + } + }), + onUploadAbort: () => { + SoftwareProductActionHelper.abortCandidateValidation(dispatch, { + softwareProductId, + version + }).then(() => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }); + }); + }, + onInvalidFileUpload: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Upload Failed'), + confirmationButtonText: i18n('Continue'), + msg: i18n( + "no zip or csar file was uploaded or expected file doesn't exist" + ) + } + }), + onSave: heatCandidate => + SoftwareProductActionHelper.updateSoftwareProductHeatCandidate( + dispatch, + { + softwareProductId, + heatCandidate, + version + } + ), + onGoToOverview: () => + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }), + onProcessAndValidate: ({ heatData, heatDataCache, isReadOnlyMode }) => { + return HeatSetupActionHelper.processAndValidateHeat(dispatch, { + softwareProductId, + heatData, + heatDataCache, + isReadOnlyMode, + version + }); + }, + setActiveTab: ({ activeTab }) => + SoftwareProductAttachmentsActionHelper.setActiveTab(dispatch, { + activeTab + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductAttachmentsView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductAttachmentsView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js index ae4a615a40..2d35bc27ee 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsActionHelper.js @@ -14,13 +14,13 @@ * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductAttachmentsConstants'; +import { actionTypes } from './SoftwareProductAttachmentsConstants'; export default { - setActiveTab(dispatch, {activeTab}) { - dispatch({ - type: actionTypes.SET_ACTIVE_TAB, - activeTab - }); - } + setActiveTab(dispatch, { activeTab }) { + dispatch({ + type: actionTypes.SET_ACTIVE_TAB, + activeTab + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js index 67265909d7..aff0a3dbdf 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsConstants.js @@ -16,10 +16,10 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const tabsMapping = { - SETUP: 1, - VALIDATION: 2 + SETUP: 1, + VALIDATION: 2 }; export const actionTypes = keyMirror({ - SET_ACTIVE_TAB: null + SET_ACTIVE_TAB: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js index 5f6538ab7e..5d9a37f98a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductAttachmentsConstants.js'; +import { actionTypes } from './SoftwareProductAttachmentsConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.SET_ACTIVE_TAB: - return {activeTab: action.activeTab}; - default: - return state; - } + switch (action.type) { + case actionTypes.SET_ACTIVE_TAB: + return { activeTab: action.activeTab }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsUtils.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsUtils.js index 2e76b11630..f4e77229e9 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsUtils.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsUtils.js @@ -15,11 +15,11 @@ */ export function doesHeatDataExist(heatData) { - let result = false; - for (let key of Object.keys(heatData)) { - if(heatData[key].length > 0) { - result = true; - } - } - return result; + let result = false; + for (let key of Object.keys(heatData)) { + if (heatData[key].length > 0) { + result = true; + } + } + return result; } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx index 2a849f376e..2007493d48 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/SoftwareProductAttachmentsView.jsx @@ -13,140 +13,208 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import accept from 'attr-accept'; -import {SVGIcon, Tab, Tabs} from 'sdc-ui/lib/react'; -import {tabsMapping} from './SoftwareProductAttachmentsConstants.js'; +import { SVGIcon, Tab, Tabs } from 'sdc-ui/lib/react'; +import { tabsMapping } from './SoftwareProductAttachmentsConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import HeatValidation from './validation/HeatValidation.js'; -import {onboardingOriginTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { onboardingOriginTypes } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import Button from 'sdc-ui/lib/react/Button.js'; class HeatScreenView extends Component { + static propTypes = { + isValidationAvailable: PropTypes.bool, + goToOverview: PropTypes.bool, + setActiveTab: PropTypes.func + }; - static propTypes = { - isValidationAvailable: PropTypes.bool, - goToOverview: PropTypes.bool, - setActiveTab: PropTypes.func - }; + componentDidMount() { + if (!this.props.goToOverview && this.props.candidateInProcess) { + this.props.setActiveTab({ activeTab: tabsMapping.VALIDATION }); + } + } - componentDidMount() { - if (!this.props.goToOverview && this.props.candidateInProcess) { - this.props.setActiveTab({activeTab: tabsMapping.VALIDATION}); - } - } + render() { + let { + isValidationAvailable, + isReadOnlyMode, + heatDataExist, + onDownload, + softwareProductId, + onProcessAndValidate, + onUploadAbort, + candidateInProcess, + heatSetup, + HeatSetupComponent, + onGoToOverview, + version, + onboardingOrigin, + activeTab, + setActiveTab, + ...other + } = this.props; - render() { - let {isValidationAvailable, isReadOnlyMode, heatDataExist, onDownload, softwareProductId, onProcessAndValidate, onUploadAbort, - candidateInProcess, heatSetup, HeatSetupComponent, onGoToOverview, version, onboardingOrigin, activeTab, setActiveTab, ...other} = this.props; + return ( + <div className="vsp-attachments-view"> + <div className="attachments-view-controllers"> + {activeTab === tabsMapping.SETUP && + candidateInProcess && ( + <Button + data-test-id="proceed-to-validation-btn" + disabled={!isValidationAvailable} + className="proceed-to-validation-btn" + onClick={() => this.validate()}> + {i18n('PROCEED TO VALIDATION')} + </Button> + )} + {candidateInProcess && ( + <SVGIcon + onClick={onUploadAbort} + name="close" + className="icon-component abort-btn" + label={i18n('ABORT')} + labelPosition="right" + color="secondary" + data-test-id="abort-btn" + /> + )} + {activeTab === tabsMapping.VALIDATION && + softwareProductId && ( + <Button + btnType="outline" + data-test-id="go-to-overview" + disabled={this.props.goToOverview !== true} + className="go-to-overview-btn" + onClick={ + this.props.goToOverview + ? () => onGoToOverview({ version }) + : undefined + }> + {i18n('GO TO OVERVIEW')} + </Button> + )} + <div className="separator" /> + <SVGIcon + disabled={heatDataExist ? false : true} + name="download" + className="icon-component" + color="dark-gray" + onClick={ + heatDataExist + ? () => + onDownload({ + heatCandidate: heatSetup, + isReadOnlyMode: + isReadOnlyMode || + !candidateInProcess, + version + }) + : undefined + } + data-test-id="download-heat" + /> + <SVGIcon + name="upload" + className="icon-component" + color="dark-gray" + disabled={isReadOnlyMode || candidateInProcess} + onClick={ + isReadOnlyMode + ? undefined + : evt => + this.refs.hiddenImportFileInput.click(evt) + } + data-test-id="upload-heat" + /> + <input + ref="hiddenImportFileInput" + type="file" + name="fileInput" + accept=".zip, .csar" + onChange={evt => this.handleImport(evt)} + /> + </div> + <Tabs + className="attachments-tabs" + type="header" + activeTab={activeTab} + onTabClick={key => this.handleTabPress(key)}> + <Tab + tabId={tabsMapping.SETUP} + title="Setup" + disabled={ + onboardingOrigin === onboardingOriginTypes.CSAR + }> + <HeatSetupComponent + heatDataExist={heatDataExist} + changeAttachmentsTab={tab => + setActiveTab({ activeTab: tab }) + } + onProcessAndValidate={onProcessAndValidate} + softwareProductId={softwareProductId} + isReadOnlyMode={isReadOnlyMode} + version={version} + /> + </Tab> + <Tab + tabId={tabsMapping.VALIDATION} + title="Validation" + disabled={!isValidationAvailable || candidateInProcess}> + <HeatValidation {...other} /> + </Tab> + </Tabs> + </div> + ); + } - return ( - <div className='vsp-attachments-view'> - <div className='attachments-view-controllers'> - {(activeTab === tabsMapping.SETUP) && candidateInProcess && - <Button - data-test-id='proceed-to-validation-btn' - disabled={!isValidationAvailable} - className='proceed-to-validation-btn' - onClick={()=>this.validate()}>{i18n('PROCEED TO VALIDATION')}</Button> - } - {candidateInProcess && <SVGIcon - onClick={onUploadAbort} - name='close' - className='icon-component abort-btn' - label={i18n('ABORT')} - labelPosition='right' - color='secondary' - data-test-id='abort-btn'/> - } - {(activeTab === tabsMapping.VALIDATION && softwareProductId) && - <Button btnType='outline' - data-test-id='go-to-overview' - disabled={this.props.goToOverview !== true} - className='go-to-overview-btn' - onClick={this.props.goToOverview ? () => onGoToOverview({version}) : undefined}>{i18n('GO TO OVERVIEW')}</Button>} - <div className='separator'></div> - <SVGIcon - disabled={heatDataExist ? false : true} - name='download' - className='icon-component' - color='dark-gray' - onClick={heatDataExist ? () => onDownload({heatCandidate: heatSetup, isReadOnlyMode: isReadOnlyMode || !candidateInProcess, version}) : undefined} - data-test-id='download-heat'/> - <SVGIcon - name='upload' - className='icon-component' - color='dark-gray' - disabled={isReadOnlyMode || candidateInProcess} - onClick={isReadOnlyMode ? undefined : evt => this.refs.hiddenImportFileInput.click(evt)} - data-test-id='upload-heat'/> - <input - ref='hiddenImportFileInput' - type='file' - name='fileInput' - accept='.zip, .csar' - onChange={evt => this.handleImport(evt)}/> - </div> - <Tabs - className='attachments-tabs' - type='header' - activeTab={activeTab} - onTabClick={key => this.handleTabPress(key)}> - <Tab tabId={tabsMapping.SETUP} title='Setup' disabled={onboardingOrigin === onboardingOriginTypes.CSAR}> - <HeatSetupComponent - heatDataExist={heatDataExist} - changeAttachmentsTab={tab => setActiveTab({activeTab: tab})} - onProcessAndValidate={onProcessAndValidate} - softwareProductId={softwareProductId} - isReadOnlyMode={isReadOnlyMode} - version={version}/> - </Tab> - <Tab tabId={tabsMapping.VALIDATION} title='Validation' disabled={!isValidationAvailable || candidateInProcess}> - <HeatValidation {...other}/> - </Tab> - </Tabs> - </div> - ); - } - - handleTabPress(key) { - let {setActiveTab} = this.props; - switch (key) { - case tabsMapping.VALIDATION: - setActiveTab({activeTab: tabsMapping.VALIDATION}); - return; - case tabsMapping.SETUP: - setActiveTab({activeTab: tabsMapping.SETUP}); - return; - } - } - - handleImport(evt) { - evt.preventDefault(); - let file = this.refs.hiddenImportFileInput.files[0]; - if(! (file && file.size && accept(file, ['.zip', '.csar'])) ) { - this.props.onInvalidFileUpload(); - return; - } - let {version} = this.props; - let formData = new FormData(); - formData.append('upload', file); - this.refs.hiddenImportFileInput.value = ''; - this.props.onUpload(formData, version); - } - validate() { - let {heatSetup, heatSetupCache, onProcessAndValidate, isReadOnlyMode, version, setActiveTab} = this.props; - onProcessAndValidate({heatData: heatSetup, heatDataCache: heatSetupCache, isReadOnlyMode, version}).then( - () => setActiveTab({activeTab: tabsMapping.VALIDATION}) - ); - } - save() { - return this.props.onboardingOrigin === onboardingOriginTypes.ZIP ? - this.props.onSave(this.props.heatSetup, this.props.version) : - Promise.resolve(); - } + handleTabPress(key) { + let { setActiveTab } = this.props; + switch (key) { + case tabsMapping.VALIDATION: + setActiveTab({ activeTab: tabsMapping.VALIDATION }); + return; + case tabsMapping.SETUP: + setActiveTab({ activeTab: tabsMapping.SETUP }); + return; + } + } + handleImport(evt) { + evt.preventDefault(); + let file = this.refs.hiddenImportFileInput.files[0]; + if (!(file && file.size && accept(file, ['.zip', '.csar']))) { + this.props.onInvalidFileUpload(); + return; + } + let { version } = this.props; + let formData = new FormData(); + formData.append('upload', file); + this.refs.hiddenImportFileInput.value = ''; + this.props.onUpload(formData, version); + } + validate() { + let { + heatSetup, + heatSetupCache, + onProcessAndValidate, + isReadOnlyMode, + version, + setActiveTab + } = this.props; + onProcessAndValidate({ + heatData: heatSetup, + heatDataCache: heatSetupCache, + isReadOnlyMode, + version + }).then(() => setActiveTab({ activeTab: tabsMapping.VALIDATION })); + } + save() { + return this.props.onboardingOrigin === onboardingOriginTypes.ZIP + ? this.props.onSave(this.props.heatSetup, this.props.version) + : Promise.resolve(); + } } export default HeatScreenView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetup.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetup.js index 4c3adc6a7d..d75d464f9e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetup.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetup.js @@ -13,50 +13,65 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import HeatSetupView from './HeatSetupView.jsx'; import HeatSetupActionHelper from './HeatSetupActionHelper.js'; - const BASE = true; function baseExists(modules) { - for (let i in modules) { - if (modules[i].isBase) { - return true; - } - } - return false; + for (let i in modules) { + if (modules[i].isBase) { + return true; + } + } + return false; } -export const mapStateToProps = ({softwareProduct: {softwareProductAttachments: {heatSetup, heatSetupCache}}}) => { - let {modules = [], unassigned = [], artifacts = [], nested = []} = heatSetup; - let isBaseExist = baseExists(modules); +export const mapStateToProps = ({ + softwareProduct: { + softwareProductAttachments: { heatSetup, heatSetupCache } + } +}) => { + let { + modules = [], + unassigned = [], + artifacts = [], + nested = [] + } = heatSetup; + let isBaseExist = baseExists(modules); - return { - heatSetupCache, - modules, - unassigned, - artifacts, - nested, - isBaseExist - }; + return { + heatSetupCache, + modules, + unassigned, + artifacts, + nested, + isBaseExist + }; }; export const mapActionsToProps = (dispatch, {}) => { - return { - onModuleRename: (oldName, newName) => HeatSetupActionHelper.renameModule(dispatch, {oldName, newName}), - onModuleAdd: () => HeatSetupActionHelper.addModule(dispatch, !BASE), - onBaseAdd: () => HeatSetupActionHelper.addModule(dispatch, BASE), - onModuleDelete: moduleName => HeatSetupActionHelper.deleteModule(dispatch, moduleName), - onModuleFileTypeChange: ({module, value, type}) => HeatSetupActionHelper.changeModuleFileType(dispatch, { - module, - value, - type - }), - onArtifactListChange: artifacts => HeatSetupActionHelper.changeArtifactList(dispatch, artifacts), - onAddAllUnassigned: () => HeatSetupActionHelper.addAllUnassignedFilesToArtifacts(dispatch) - }; + return { + onModuleRename: (oldName, newName) => + HeatSetupActionHelper.renameModule(dispatch, { oldName, newName }), + onModuleAdd: () => HeatSetupActionHelper.addModule(dispatch, !BASE), + onBaseAdd: () => HeatSetupActionHelper.addModule(dispatch, BASE), + onModuleDelete: moduleName => + HeatSetupActionHelper.deleteModule(dispatch, moduleName), + onModuleFileTypeChange: ({ module, value, type }) => + HeatSetupActionHelper.changeModuleFileType(dispatch, { + module, + value, + type + }), + onArtifactListChange: artifacts => + HeatSetupActionHelper.changeArtifactList(dispatch, artifacts), + onAddAllUnassigned: () => + HeatSetupActionHelper.addAllUnassignedFilesToArtifacts(dispatch) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(HeatSetupView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(HeatSetupView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupActionHelper.js index 87953bb8aa..05ac408fbb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupActionHelper.js @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './HeatSetupConstants.js'; +import { actionTypes } from './HeatSetupConstants.js'; import isEqual from 'lodash/isEqual.js'; import cloneDeep from 'lodash/cloneDeep.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; @@ -21,46 +21,72 @@ import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/Soft // import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; export default { + addModule(dispatch, isBase) { + dispatch({ type: actionTypes.ADD_MODULE, data: { isBase } }); + }, - addModule(dispatch, isBase){ - dispatch({type: actionTypes.ADD_MODULE, data: {isBase}}); - }, + deleteModule(dispatch, moduleName) { + dispatch({ type: actionTypes.REMOVE_MODULE, data: { moduleName } }); + }, - deleteModule(dispatch, moduleName){ - dispatch({type: actionTypes.REMOVE_MODULE, data: {moduleName}}); - }, + renameModule(dispatch, { oldName, newName }) { + dispatch({ + type: actionTypes.RENAME_MODULE, + data: { oldName, newName } + }); + }, - renameModule(dispatch, {oldName, newName}){ - dispatch({type: actionTypes.RENAME_MODULE, data: {oldName, newName}}); - }, + changeModuleFileType(dispatch, { module, value, type }) { + if (!value) { + value = { value: '' }; + } + dispatch({ + type: actionTypes.FILE_ASSIGN_CHANGED, + data: { module, value, type } + }); + }, - changeModuleFileType(dispatch, {module, value, type}){ - if (!value) { - value = {value: ''}; - } - dispatch({type: actionTypes.FILE_ASSIGN_CHANGED, data: {module, value, type}}); - }, + changeArtifactList(dispatch, artifacts) { + dispatch({ + type: actionTypes.ARTIFACT_LIST_CHANGE, + data: { artifacts: artifacts.map(artifact => artifact.value) } + }); + }, - changeArtifactList(dispatch, artifacts){ - dispatch({type: actionTypes.ARTIFACT_LIST_CHANGE, data: {artifacts: artifacts.map(artifact => artifact.value)}}); - }, + processAndValidateHeat( + dispatch, + { softwareProductId, heatData, heatDataCache, isReadOnlyMode, version } + ) { + return isEqual({ ...heatData, softwareProductId }, heatDataCache) || + isReadOnlyMode + ? Promise.resolve() + : SoftwareProductActionHelper.updateSoftwareProductHeatCandidate( + dispatch, + { softwareProductId, heatCandidate: heatData, version } + ) + .then(() => + SoftwareProductActionHelper.processAndValidateHeatCandidate( + dispatch, + { softwareProductId, version } + ) + ) + .then(() => + dispatch({ + type: actionTypes.FILL_HEAT_SETUP_CACHE, + payload: { ...cloneDeep(heatData), softwareProductId } + }) + ); + }, - processAndValidateHeat(dispatch, {softwareProductId, heatData, heatDataCache, isReadOnlyMode, version}){ - return (isEqual({...heatData, softwareProductId}, heatDataCache) || isReadOnlyMode) ? Promise.resolve() : - SoftwareProductActionHelper.updateSoftwareProductHeatCandidate(dispatch, {softwareProductId, heatCandidate: heatData, version}) - .then(() => SoftwareProductActionHelper.processAndValidateHeatCandidate(dispatch, {softwareProductId, version})) - .then(() => dispatch({type: actionTypes.FILL_HEAT_SETUP_CACHE, payload: {...cloneDeep(heatData), softwareProductId}})); - }, + addAllUnassignedFilesToArtifacts(dispatch) { + dispatch({ type: actionTypes.ADD_ALL_UNASSIGNED_TO_ARTIFACTS }); + }, - addAllUnassignedFilesToArtifacts(dispatch){ - dispatch({type: actionTypes.ADD_ALL_UNASSIGNED_TO_ARTIFACTS}); - }, + heatSetupLeaveConfirmation() { + return Promise.resolve(); + } - heatSetupLeaveConfirmation() { - return Promise.resolve(); - } - - /*heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) { + /*heatSetupLeaveConfirmation(dispatch, {softwareProductId, heatSetup, heatSetupCache}) { return new Promise((resolve, reject) => { if (isEqual({...heatSetup, softwareProductId}, heatSetupCache)) { resolve(); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js index 2d6bd574a7..ff53fad27f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupConstants.js @@ -16,27 +16,25 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ + ARTIFACT_LIST_CHANGE: null, + ADD_ALL_UNASSIGNED_TO_ARTIFACTS: null, + ADD_ALL_ARTIFACTS_TO_UNASSIGNED: null, - ARTIFACT_LIST_CHANGE: null, - ADD_ALL_UNASSIGNED_TO_ARTIFACTS: null, - ADD_ALL_ARTIFACTS_TO_UNASSIGNED: null, + ADD_MODULE: null, + REMOVE_MODULE: null, + RENAME_MODULE: null, + FILL_HEAT_SETUP_CACHE: null, + FILE_ASSIGN_CHANGED: null, - ADD_MODULE: null, - REMOVE_MODULE: null, - RENAME_MODULE: null, - FILL_HEAT_SETUP_CACHE: null, - FILE_ASSIGN_CHANGED: null, - - MANIFEST_LOADED: null, - - GO_TO_VALIDATION: null, - IN_VALIDATION: null + MANIFEST_LOADED: null, + GO_TO_VALIDATION: null, + IN_VALIDATION: null }); export const fileTypes = { - YAML: {label: 'yaml', regex: /(yaml|yml)/g}, - ENV: {label: 'env', regex: /env/g}, - VOL: {label: 'vol', regex: /(yaml|yml)/g}, - VOL_ENV: {label: 'volEnv', regex: /env/g} + YAML: { label: 'yaml', regex: /(yaml|yml)/g }, + ENV: { label: 'env', regex: /env/g }, + VOL: { label: 'vol', regex: /(yaml|yml)/g }, + VOL_ENV: { label: 'volEnv', regex: /env/g } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupReducer.js index f49339ce35..8840a11c3e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/setup/HeatSetupReducer.js @@ -13,112 +13,163 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './HeatSetupConstants.js'; +import { actionTypes } from './HeatSetupConstants.js'; import differenceWith from 'lodash/differenceWith.js'; - const emptyModule = (isBase, currentLength) => ({ - name: `${isBase ? 'base_' : 'module_'}${currentLength + 1}`, - isBase: isBase + name: `${isBase ? 'base_' : 'module_'}${currentLength + 1}`, + isBase: isBase }); -function syncUnassignedFilesWithArtifactsChanges(unassigned, artifacts, oldArtifacts) { - if (artifacts.length > oldArtifacts.length) { - return differenceWith(unassigned, artifacts, (unassignedFile, artifact) => unassignedFile === artifact); - } - else { - const removedArtifact = differenceWith(oldArtifacts, artifacts, (oldArtifact, artifact) => artifact === oldArtifact); - return [...unassigned, removedArtifact[0]]; - } +function syncUnassignedFilesWithArtifactsChanges( + unassigned, + artifacts, + oldArtifacts +) { + if (artifacts.length > oldArtifacts.length) { + return differenceWith( + unassigned, + artifacts, + (unassignedFile, artifact) => unassignedFile === artifact + ); + } else { + const removedArtifact = differenceWith( + oldArtifacts, + artifacts, + (oldArtifact, artifact) => artifact === oldArtifact + ); + return [...unassigned, removedArtifact[0]]; + } } function findModuleIndexByName(modules, name) { - return modules.findIndex(module => module.name === name); + return modules.findIndex(module => module.name === name); } -function addDeletedModuleFilesToUnassigned(unassigned, deletedModule){ - let files = []; - for(let i in deletedModule){ - if (deletedModule.hasOwnProperty(i)) { - if (typeof deletedModule[i] === 'string' && deletedModule[i] && i !== 'name') { - files.push(deletedModule[i]); - } - } - } +function addDeletedModuleFilesToUnassigned(unassigned, deletedModule) { + let files = []; + for (let i in deletedModule) { + if (deletedModule.hasOwnProperty(i)) { + if ( + typeof deletedModule[i] === 'string' && + deletedModule[i] && + i !== 'name' + ) { + files.push(deletedModule[i]); + } + } + } - return unassigned.concat(files); + return unassigned.concat(files); } export default (state = {}, action) => { - switch (action.type) { - case actionTypes.MANIFEST_LOADED: - return { - ...state, - ...action.response, - modules: action.response.modules.map(module => ({...module, name: module.name || module.yaml.substring(0, module.yaml.lastIndexOf('.'))})) - }; - case actionTypes.ARTIFACT_LIST_CHANGE: - return { - ...state, - artifacts: action.data.artifacts, - unassigned: syncUnassignedFilesWithArtifactsChanges(state.unassigned, action.data.artifacts, state.artifacts) - }; - case actionTypes.ADD_ALL_UNASSIGNED_TO_ARTIFACTS: - return { - ...state, - artifacts: [...state.artifacts,...state.unassigned], - unassigned: [] - }; - case actionTypes.ADD_ALL_ARTIFACTS_TO_UNASSIGNED: - return { - ...state, - artifacts: [], - unassigned: [...state.unassigned, ...state.artifacts] - }; - case actionTypes.ADD_MODULE: - return { - ...state, - modules: state.modules.concat({...emptyModule(action.data.isBase, state.modules.length)}) - }; - case actionTypes.REMOVE_MODULE: - const moduleIndexToDelete = findModuleIndexByName(state.modules, action.data.moduleName); - let unassigned = addDeletedModuleFilesToUnassigned(state.unassigned, state.modules[moduleIndexToDelete]); - return { - ...state, - unassigned, - modules: [...state.modules.slice(0, moduleIndexToDelete), ...state.modules.slice(moduleIndexToDelete + 1)] - }; - case actionTypes.RENAME_MODULE: - const indexToRename = findModuleIndexByName(state.modules, action.data.oldName); - let moduleToRename = state.modules[indexToRename]; - moduleToRename.name = action.data.newName; - return { - ...state, - modules: [...state.modules.slice(0, indexToRename), moduleToRename, ...state.modules.slice(indexToRename + 1)] - }; - case actionTypes.FILE_ASSIGN_CHANGED: - let {module, value:{value}, type} = action.data; - const moduleIndexToModify = findModuleIndexByName(state.modules, module.name); - let moduleToModify = state.modules[moduleIndexToModify]; - let dumpedFile = moduleToModify[type]; - if (dumpedFile !== value) { - if(value) { - moduleToModify[type] = value; - } - else { - delete moduleToModify[type]; - } - const newUnassignedList = dumpedFile ? [...state.unassigned.filter(file => file !== value), dumpedFile] : state.unassigned.filter(file => file !== value); - return { - ...state, - modules: [...state.modules.slice(0, moduleIndexToModify), moduleToModify, ...state.modules.slice(moduleIndexToModify + 1)], - unassigned: newUnassignedList - }; - } - else { - return state; - } - default: - return state; - } + switch (action.type) { + case actionTypes.MANIFEST_LOADED: + return { + ...state, + ...action.response, + modules: action.response.modules.map(module => ({ + ...module, + name: + module.name || + module.yaml.substring(0, module.yaml.lastIndexOf('.')) + })) + }; + case actionTypes.ARTIFACT_LIST_CHANGE: + return { + ...state, + artifacts: action.data.artifacts, + unassigned: syncUnassignedFilesWithArtifactsChanges( + state.unassigned, + action.data.artifacts, + state.artifacts + ) + }; + case actionTypes.ADD_ALL_UNASSIGNED_TO_ARTIFACTS: + return { + ...state, + artifacts: [...state.artifacts, ...state.unassigned], + unassigned: [] + }; + case actionTypes.ADD_ALL_ARTIFACTS_TO_UNASSIGNED: + return { + ...state, + artifacts: [], + unassigned: [...state.unassigned, ...state.artifacts] + }; + case actionTypes.ADD_MODULE: + return { + ...state, + modules: state.modules.concat({ + ...emptyModule(action.data.isBase, state.modules.length) + }) + }; + case actionTypes.REMOVE_MODULE: + const moduleIndexToDelete = findModuleIndexByName( + state.modules, + action.data.moduleName + ); + let unassigned = addDeletedModuleFilesToUnassigned( + state.unassigned, + state.modules[moduleIndexToDelete] + ); + return { + ...state, + unassigned, + modules: [ + ...state.modules.slice(0, moduleIndexToDelete), + ...state.modules.slice(moduleIndexToDelete + 1) + ] + }; + case actionTypes.RENAME_MODULE: + const indexToRename = findModuleIndexByName( + state.modules, + action.data.oldName + ); + let moduleToRename = state.modules[indexToRename]; + moduleToRename.name = action.data.newName; + return { + ...state, + modules: [ + ...state.modules.slice(0, indexToRename), + moduleToRename, + ...state.modules.slice(indexToRename + 1) + ] + }; + case actionTypes.FILE_ASSIGN_CHANGED: + let { module, value: { value }, type } = action.data; + const moduleIndexToModify = findModuleIndexByName( + state.modules, + module.name + ); + let moduleToModify = state.modules[moduleIndexToModify]; + let dumpedFile = moduleToModify[type]; + if (dumpedFile !== value) { + if (value) { + moduleToModify[type] = value; + } else { + delete moduleToModify[type]; + } + const newUnassignedList = dumpedFile + ? [ + ...state.unassigned.filter(file => file !== value), + dumpedFile + ] + : state.unassigned.filter(file => file !== value); + return { + ...state, + modules: [ + ...state.modules.slice(0, moduleIndexToModify), + moduleToModify, + ...state.modules.slice(moduleIndexToModify + 1) + ], + unassigned: newUnassignedList + }; + } else { + return state; + } + default: + return state; + } }; 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 ce6d5260d7..1d4efd9104 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 @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; 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'; @@ -21,307 +21,476 @@ 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 SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -import {fileTypes} from './HeatSetupConstants.js'; -import {tabsMapping} from '../SoftwareProductAttachmentsConstants.js'; -import {sortable} from 'react-sortable'; +import { fileTypes } from './HeatSetupConstants.js'; +import { tabsMapping } from '../SoftwareProductAttachmentsConstants.js'; +import { sortable } from 'react-sortable'; class ListItem extends Component { - - render() { - return ( - <li {...this.props}>{this.props.children}</li> - ); - } + render() { + return <li {...this.props}>{this.props.children}</li>; + } } - const SortableListItem = sortable(ListItem); class SortableModuleFileList extends Component { - - state = { - draggingIndex: null, - data: this.props.modules - }; - - - componentWillReceiveProps(nextProps) { - this.setState({data: nextProps.modules}); - } - - render() { - - let {unassigned, onModuleRename, onModuleDelete, onModuleAdd, onBaseAdd, onModuleFileTypeChange, isBaseExist, isReadOnlyMode} = this.props; - const childProps = module => ({ - module, - onModuleRename, - onModuleDelete, - onModuleFileTypeChange: (value, type) => onModuleFileTypeChange({module, value, type}), - files: unassigned - }); - let listItems = this.state.data.map(function (item, i) { - return ( - <SortableListItem - key={i} - updateState={data => this.setState(data)} - items={this.state.data} - draggingIndex={this.state.draggingIndex} - sortId={i} - outline='list'><ModuleFile {...childProps(item)} isReadOnlyMode={this.props.isReadOnlyMode} /></SortableListItem> - ); - }, this); - - return ( - <div className={`modules-list-wrapper ${(listItems.length > 0) ? 'modules-list-wrapper-divider' : ''}`}> - <div className='modules-list-header'> - {!isBaseExist && <div><Button btnType='link' onClick={onBaseAdd} disabled={isReadOnlyMode || unassigned.length === 0}>{i18n('Add Base')}</Button></div>} - <div><Button btnType='link' onClick={onModuleAdd} disabled={isReadOnlyMode || unassigned.length === 0}>{i18n('Add Module')}</Button></div> - </div> - {(listItems.length > 0) && <ul>{listItems}</ul>} - </div> - ); - } + state = { + draggingIndex: null, + data: this.props.modules + }; + + componentWillReceiveProps(nextProps) { + this.setState({ data: nextProps.modules }); + } + + render() { + let { + unassigned, + onModuleRename, + onModuleDelete, + onModuleAdd, + onBaseAdd, + onModuleFileTypeChange, + isBaseExist, + isReadOnlyMode + } = this.props; + const childProps = module => ({ + module, + onModuleRename, + onModuleDelete, + onModuleFileTypeChange: (value, type) => + onModuleFileTypeChange({ module, value, type }), + files: unassigned + }); + let listItems = this.state.data.map(function(item, i) { + return ( + <SortableListItem + key={i} + updateState={data => this.setState(data)} + items={this.state.data} + draggingIndex={this.state.draggingIndex} + sortId={i} + outline="list"> + <ModuleFile + {...childProps(item)} + isReadOnlyMode={this.props.isReadOnlyMode} + /> + </SortableListItem> + ); + }, this); + + return ( + <div + className={`modules-list-wrapper ${ + listItems.length > 0 ? 'modules-list-wrapper-divider' : '' + }`}> + <div className="modules-list-header"> + {!isBaseExist && ( + <div> + <Button + btnType="link" + onClick={onBaseAdd} + disabled={ + isReadOnlyMode || unassigned.length === 0 + }> + {i18n('Add Base')} + </Button> + </div> + )} + <div> + <Button + btnType="link" + onClick={onModuleAdd} + disabled={ + isReadOnlyMode || unassigned.length === 0 + }> + {i18n('Add Module')} + </Button> + </div> + </div> + {listItems.length > 0 && <ul>{listItems}</ul>} + </div> + ); + } } -const tooltip = (name) => <Tooltip id='tooltip-bottom'>{name}</Tooltip>; -const UnassignedFileList = (props) => { - return ( - <div> - <div className='modules-list-header'/> - <div className='unassigned-files'> - <div className='unassigned-files-title'>{i18n('UNASSIGNED FILES')}</div> - <div className='unassigned-files-list'>{props.children}</div> - </div> - </div> - ); +const tooltip = name => <Tooltip id="tooltip-bottom">{name}</Tooltip>; +const UnassignedFileList = props => { + return ( + <div> + <div className="modules-list-header" /> + <div className="unassigned-files"> + <div className="unassigned-files-title"> + {i18n('UNASSIGNED FILES')} + </div> + <div className="unassigned-files-list">{props.children}</div> + </div> + </div> + ); }; const EmptyListContent = props => { - let {heatDataExist} = props; - let displayText = heatDataExist ? 'All Files Are Assigned' : ''; - return ( - <div className='go-to-validation-button-wrapper'> - <div className='all-files-assigned'>{i18n(displayText)}</div> - </div> - ); + let { heatDataExist } = props; + let displayText = heatDataExist ? 'All Files Are Assigned' : ''; + return ( + <div className="go-to-validation-button-wrapper"> + <div className="all-files-assigned">{i18n(displayText)}</div> + </div> + ); }; -const UnassignedFile = (props) => ( - <OverlayTrigger placement='bottom' overlay={tooltip(props.name)} delayShow={1000}> - <li data-test-id='unassigned-files' className='unassigned-files-list-item'>{props.name}</li> - </OverlayTrigger> +const UnassignedFile = props => ( + <OverlayTrigger + placement="bottom" + overlay={tooltip(props.name)} + delayShow={1000}> + <li + data-test-id="unassigned-files" + className="unassigned-files-list-item"> + {props.name} + </li> + </OverlayTrigger> ); -const AddOrDeleteVolumeFiles = ({add = true, onAdd, onDelete, isReadOnlyMode}) => { - const displayText = add ? 'Add Volume Files' : 'Delete Volume Files'; - const action = add ? onAdd : onDelete; - return ( - <Button disabled={isReadOnlyMode} onClick={action} btnType='link' className='add-or-delete-volumes' iconName={add ? 'plus' : 'close'}>{i18n(displayText)}</Button> - ); +const AddOrDeleteVolumeFiles = ({ + add = true, + onAdd, + onDelete, + isReadOnlyMode +}) => { + const displayText = add ? 'Add Volume Files' : 'Delete Volume Files'; + const action = add ? onAdd : onDelete; + return ( + <Button + disabled={isReadOnlyMode} + onClick={action} + btnType="link" + className="add-or-delete-volumes" + iconName={add ? 'plus' : 'close'}> + {i18n(displayText)} + </Button> + ); }; -const SelectWithFileType = ({type, selected, files, onChange}) => { - - let filteredFiledAccordingToType = files.filter(file => file.label.search(type.regex) > -1); - if (selected) { - filteredFiledAccordingToType = filteredFiledAccordingToType.concat({label: selected, value: selected}); - } - - return ( - <SelectInput - data-test-id={`${type.label}-list`} - label={type.label} - value={selected} - onChange={value => value !== selected && onChange(value, type.label)} - disabled={filteredFiledAccordingToType.length === 0} - placeholder={filteredFiledAccordingToType.length === 0 ? '' : undefined} - clearable={true} - options={filteredFiledAccordingToType} /> - ); +const SelectWithFileType = ({ type, selected, files, onChange }) => { + let filteredFiledAccordingToType = files.filter( + file => file.label.search(type.regex) > -1 + ); + if (selected) { + filteredFiledAccordingToType = filteredFiledAccordingToType.concat({ + label: selected, + value: selected + }); + } + + return ( + <SelectInput + data-test-id={`${type.label}-list`} + label={type.label} + value={selected} + onChange={value => + value !== selected && onChange(value, type.label) + } + disabled={filteredFiledAccordingToType.length === 0} + placeholder={ + filteredFiledAccordingToType.length === 0 ? '' : undefined + } + clearable={true} + options={filteredFiledAccordingToType} + /> + ); }; class NameEditInput extends Component { - componentDidMount() { - this.input.focus(); - } - - render() { - return ( - <FormControl {...this.props} className='name-edit' inputRef={input => this.input = input}/> - ); - } + componentDidMount() { + this.input.focus(); + } + + render() { + return ( + <FormControl + {...this.props} + className="name-edit" + inputRef={input => (this.input = input)} + /> + ); + } } class ModuleFile extends Component { - constructor(props) { - super(props); - this.state = { - isInNameEdit: false, - displayVolumes: Boolean(props.module.vol || props.module.volEnv) - }; - } - - handleSubmit(event, name) { - if (event.keyCode === 13) { - this.handleModuleRename(event, name); - } - } - - componentWillReceiveProps(nextProps) { - this.setState({displayVolumes: Boolean(nextProps.module.vol || nextProps.module.volEnv)}); - } - - handleModuleRename(event, name) { - this.setState({isInNameEdit: false}); - this.props.onModuleRename(name, event.target.value); - } - - deleteVolumeFiles() { - const { onModuleFileTypeChange} = this.props; - onModuleFileTypeChange(null, fileTypes.VOL.label); - onModuleFileTypeChange(null, fileTypes.VOL_ENV.label); - this.setState({displayVolumes: false}); - } - - renderNameAccordingToEditState() { - const {module: {name}} = this.props; - if (this.state.isInNameEdit) { - return (<NameEditInput defaultValue={name} onBlur={evt => this.handleModuleRename(evt, name)} onKeyDown={evt => this.handleSubmit(evt, name)}/>); - } - return (<span className='filename-text'>{name}</span>); - } - - render() { - const {module: {name, isBase, yaml, env, vol, volEnv}, onModuleDelete, files, onModuleFileTypeChange, isReadOnlyMode} = this.props; - const {displayVolumes} = this.state; - const moduleType = isBase ? 'BASE' : 'MODULE'; - return ( - <div className='modules-list-item' data-test-id='module-item'> - <div className='modules-list-item-controllers'> - <div className='modules-list-item-filename'> - <SVGIcon name={isBase ? 'base' : 'module'} color='primary' iconClassName='heat-setup-module-icon' /> - <span className='module-title-by-type'>{`${moduleType}: `}</span> - <div className={`text-and-icon ${this.state.isInNameEdit ? 'in-edit' : ''}`}> - {this.renderNameAccordingToEditState()} - {!this.state.isInNameEdit && <SVGIcon - name='pencil' - onClick={() => this.setState({isInNameEdit: true})} - data-test-id={isBase ? 'base-name' : 'module-name'}/>} - </div> - </div> - <SVGIcon name='trashO' onClick={() => onModuleDelete(name)} data-test-id='module-delete'/> - </div> - <div className='modules-list-item-selectors'> - <SelectWithFileType - type={fileTypes.YAML} - files={files} - selected={yaml} - onChange={onModuleFileTypeChange}/> - <SelectWithFileType - type={fileTypes.ENV} - files={files} - selected={env} - onChange={onModuleFileTypeChange}/> - {displayVolumes && <SelectWithFileType - type={fileTypes.VOL} - files={files} - selected={vol} - onChange={onModuleFileTypeChange}/>} - {displayVolumes && <SelectWithFileType - type={fileTypes.VOL_ENV} - files={files} - selected={volEnv} - onChange={onModuleFileTypeChange}/>} - <AddOrDeleteVolumeFiles isReadOnlyMode={isReadOnlyMode} onAdd={() => this.setState({displayVolumes: true})} onDelete={() => this.deleteVolumeFiles()} add={!displayVolumes}/> - </div> - </div> - ); - } + constructor(props) { + super(props); + this.state = { + isInNameEdit: false, + displayVolumes: Boolean(props.module.vol || props.module.volEnv) + }; + } + + handleSubmit(event, name) { + if (event.keyCode === 13) { + this.handleModuleRename(event, name); + } + } + + componentWillReceiveProps(nextProps) { + this.setState({ + displayVolumes: Boolean( + nextProps.module.vol || nextProps.module.volEnv + ) + }); + } + + handleModuleRename(event, name) { + this.setState({ isInNameEdit: false }); + this.props.onModuleRename(name, event.target.value); + } + + deleteVolumeFiles() { + const { onModuleFileTypeChange } = this.props; + onModuleFileTypeChange(null, fileTypes.VOL.label); + onModuleFileTypeChange(null, fileTypes.VOL_ENV.label); + this.setState({ displayVolumes: false }); + } + + renderNameAccordingToEditState() { + const { module: { name } } = this.props; + if (this.state.isInNameEdit) { + return ( + <NameEditInput + defaultValue={name} + onBlur={evt => this.handleModuleRename(evt, name)} + onKeyDown={evt => this.handleSubmit(evt, name)} + /> + ); + } + return <span className="filename-text">{name}</span>; + } + + render() { + const { + module: { name, isBase, yaml, env, vol, volEnv }, + onModuleDelete, + files, + onModuleFileTypeChange, + isReadOnlyMode + } = this.props; + const { displayVolumes } = this.state; + const moduleType = isBase ? 'BASE' : 'MODULE'; + return ( + <div className="modules-list-item" data-test-id="module-item"> + <div className="modules-list-item-controllers"> + <div className="modules-list-item-filename"> + <SVGIcon + name={isBase ? 'base' : 'module'} + color="primary" + iconClassName="heat-setup-module-icon" + /> + <span className="module-title-by-type">{`${moduleType}: `}</span> + <div + className={`text-and-icon ${ + this.state.isInNameEdit ? 'in-edit' : '' + }`}> + {this.renderNameAccordingToEditState()} + {!this.state.isInNameEdit && ( + <SVGIcon + name="pencil" + onClick={() => + this.setState({ isInNameEdit: true }) + } + data-test-id={ + isBase ? 'base-name' : 'module-name' + } + /> + )} + </div> + </div> + <SVGIcon + name="trashO" + onClick={() => onModuleDelete(name)} + data-test-id="module-delete" + /> + </div> + <div className="modules-list-item-selectors"> + <SelectWithFileType + type={fileTypes.YAML} + files={files} + selected={yaml} + onChange={onModuleFileTypeChange} + /> + <SelectWithFileType + type={fileTypes.ENV} + files={files} + selected={env} + onChange={onModuleFileTypeChange} + /> + {displayVolumes && ( + <SelectWithFileType + type={fileTypes.VOL} + files={files} + selected={vol} + onChange={onModuleFileTypeChange} + /> + )} + {displayVolumes && ( + <SelectWithFileType + type={fileTypes.VOL_ENV} + files={files} + selected={volEnv} + onChange={onModuleFileTypeChange} + /> + )} + <AddOrDeleteVolumeFiles + isReadOnlyMode={isReadOnlyMode} + onAdd={() => this.setState({ displayVolumes: true })} + onDelete={() => this.deleteVolumeFiles()} + add={!displayVolumes} + /> + </div> + </div> + ); + } } class ArtifactOrNestedFileList extends Component { - - render() { - let {type, title, selected, options, onSelectChanged, onAddAllUnassigned, isReadOnlyMode, headerClassName} = this.props; - return ( - <div className={`artifact-files ${type === 'nested' ? 'nested' : ''} ${headerClassName} `}> - <div className='artifact-files-header'> - <span> - {type === 'artifact' && (<SVGIcon color='primary' name='artifacts' iconClassName='heat-setup-module-icon' />)} - {`${title}`} - </span> - {type === 'artifact' && <Button disabled={isReadOnlyMode} btnType='link' className='add-all-unassigned' onClick={onAddAllUnassigned}>{i18n('Add All Unassigned Files')}</Button>} - </div> - {type === 'nested' ? ( - <ul className='nested-list'>{selected.map(nested => - <li key={nested} className='nested-list-item'>{nested}</li> - )}</ul>) : - (<SelectInput - options={options} - onMultiSelectChanged={onSelectChanged || (() => { - })} - value={selected} - clearable={false} - placeholder={i18n('Add Artifact')} - multi/>) - } - </div> - ); - } + render() { + let { + type, + title, + selected, + options, + onSelectChanged, + onAddAllUnassigned, + isReadOnlyMode, + headerClassName + } = this.props; + return ( + <div + className={`artifact-files ${ + type === 'nested' ? 'nested' : '' + } ${headerClassName} `}> + <div className="artifact-files-header"> + <span> + {type === 'artifact' && ( + <SVGIcon + color="primary" + name="artifacts" + iconClassName="heat-setup-module-icon" + /> + )} + {`${title}`} + </span> + {type === 'artifact' && ( + <Button + disabled={isReadOnlyMode} + btnType="link" + className="add-all-unassigned" + onClick={onAddAllUnassigned}> + {i18n('Add All Unassigned Files')} + </Button> + )} + </div> + {type === 'nested' ? ( + <ul className="nested-list"> + {selected.map(nested => ( + <li key={nested} className="nested-list-item"> + {nested} + </li> + ))} + </ul> + ) : ( + <SelectInput + options={options} + onMultiSelectChanged={onSelectChanged || (() => {})} + value={selected} + clearable={false} + placeholder={i18n('Add Artifact')} + multi + /> + )} + </div> + ); + } } -const buildLabelValueObject = str => (typeof str === 'string' ? {value: str, label: str} : str); +const buildLabelValueObject = str => + typeof str === 'string' ? { value: str, label: str } : str; class SoftwareProductHeatSetupView extends Component { - - processAndValidateHeat(heatData, heatDataCache){ - let {onProcessAndValidate, changeAttachmentsTab, version} = this.props; - onProcessAndValidate({heatData, heatDataCache, version}).then( - () => changeAttachmentsTab(tabsMapping.VALIDATION) - ); - } - - render() { - let {modules, isReadOnlyMode, heatDataExist, unassigned, artifacts, nested, onArtifactListChange, onAddAllUnassigned} = this.props; - - const formattedUnassigned = unassigned.map(buildLabelValueObject); - const formattedArtifacts = artifacts.map(buildLabelValueObject); - return ( - <div className={`heat-setup-view ${isReadOnlyMode ? 'disabled' : ''}`}> - <div className='heat-setup-view-modules-and-artifacts'> - <SortableModuleFileList - {...this.props} - isReadOnlyMode={this.props.isReadOnlyMode} - artifacts={formattedArtifacts} - unassigned={formattedUnassigned}/> - <ArtifactOrNestedFileList - type={'artifact'} - title={i18n('ARTIFACTS')} - options={formattedUnassigned} - selected={formattedArtifacts} - onSelectChanged={onArtifactListChange} - isReadOnlyMode={this.props.isReadOnlyMode} - headerClassName={(modules && modules.length > 0) ? 'with-list-items' : ''} - onAddAllUnassigned={onAddAllUnassigned}/> - <ArtifactOrNestedFileList - type={'nested'} - title={i18n('NESTED HEAT FILES')} - options={[]} - isReadOnlyMode={this.props.isReadOnlyMode} - selected={nested}/> - </div> - <UnassignedFileList> - { - formattedUnassigned.length > 0 ? - (<ul>{formattedUnassigned.map(file => <UnassignedFile key={file.label} name={file.label}/>)}</ul>) - : - (<EmptyListContent - heatDataExist={heatDataExist}/>) - } - </UnassignedFileList> - </div> - ); - } - + processAndValidateHeat(heatData, heatDataCache) { + let { + onProcessAndValidate, + changeAttachmentsTab, + version + } = this.props; + onProcessAndValidate({ heatData, heatDataCache, version }).then(() => + changeAttachmentsTab(tabsMapping.VALIDATION) + ); + } + + render() { + let { + modules, + isReadOnlyMode, + heatDataExist, + unassigned, + artifacts, + nested, + onArtifactListChange, + onAddAllUnassigned + } = this.props; + + const formattedUnassigned = unassigned.map(buildLabelValueObject); + const formattedArtifacts = artifacts.map(buildLabelValueObject); + return ( + <div + className={`heat-setup-view ${ + isReadOnlyMode ? 'disabled' : '' + }`}> + <div className="heat-setup-view-modules-and-artifacts"> + <SortableModuleFileList + {...this.props} + isReadOnlyMode={this.props.isReadOnlyMode} + artifacts={formattedArtifacts} + unassigned={formattedUnassigned} + /> + <ArtifactOrNestedFileList + type={'artifact'} + title={i18n('ARTIFACTS')} + options={formattedUnassigned} + selected={formattedArtifacts} + onSelectChanged={onArtifactListChange} + isReadOnlyMode={this.props.isReadOnlyMode} + headerClassName={ + modules && modules.length > 0 + ? 'with-list-items' + : '' + } + onAddAllUnassigned={onAddAllUnassigned} + /> + <ArtifactOrNestedFileList + type={'nested'} + title={i18n('NESTED HEAT FILES')} + options={[]} + isReadOnlyMode={this.props.isReadOnlyMode} + selected={nested} + /> + </div> + <UnassignedFileList> + {formattedUnassigned.length > 0 ? ( + <ul> + {formattedUnassigned.map(file => ( + <UnassignedFile + key={file.label} + name={file.label} + /> + ))} + </ul> + ) : ( + <EmptyListContent heatDataExist={heatDataExist} /> + )} + </UnassignedFileList> + </div> + ); + } } export default SoftwareProductHeatSetupView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidation.js index 21f6e6c77f..00130e4bc7 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidation.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidation.js @@ -13,39 +13,55 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import HeatValidationView from './HeatValidationView.jsx'; import HeatValidationActionHelper from './HeatValidationActionHelper.js'; -import {errorLevels, nodeFilters} from './HeatValidationConstants.js'; +import { errorLevels, nodeFilters } from './HeatValidationConstants.js'; -export const mapStateToProps = ({softwareProduct: {softwareProductAttachments: {heatValidation}}}) => { - let {attachmentsTree, selectedNode, errorList} = heatValidation; - let currentErrors = [], currentWarnings = []; - if (errorList) { - for (let i = 0 ; i < errorList.length ; i++) { - if (errorList[i].level === errorLevels.ERROR && (errorList[i].name === selectedNode || selectedNode === nodeFilters.ALL)) { - currentErrors[currentErrors.length] = errorList[i]; - } - if (errorList[i].level === errorLevels.WARNING && (errorList[i].name === selectedNode || selectedNode === nodeFilters.ALL)) { - currentWarnings[currentWarnings.length] = errorList[i]; - } - } - } - return { - attachmentsTree, - selectedNode, - errorList, - currentErrors, - currentWarnings - }; +export const mapStateToProps = ({ + softwareProduct: { softwareProductAttachments: { heatValidation } } +}) => { + let { attachmentsTree, selectedNode, errorList } = heatValidation; + let currentErrors = [], + currentWarnings = []; + if (errorList) { + for (let i = 0; i < errorList.length; i++) { + if ( + errorList[i].level === errorLevels.ERROR && + (errorList[i].name === selectedNode || + selectedNode === nodeFilters.ALL) + ) { + currentErrors[currentErrors.length] = errorList[i]; + } + if ( + errorList[i].level === errorLevels.WARNING && + (errorList[i].name === selectedNode || + selectedNode === nodeFilters.ALL) + ) { + currentWarnings[currentWarnings.length] = errorList[i]; + } + } + } + return { + attachmentsTree, + selectedNode, + errorList, + currentErrors, + currentWarnings + }; }; -const mapActionsToProps = (dispatch) => { - return { - toggleExpanded: (path) => HeatValidationActionHelper.toggleExpanded(dispatch, {path}), - onSelectNode: (nodeName) => HeatValidationActionHelper.onSelectNode(dispatch, {nodeName}), - onDeselectNode: () => HeatValidationActionHelper.onDeselectNode(dispatch) - }; +const mapActionsToProps = dispatch => { + return { + toggleExpanded: path => + HeatValidationActionHelper.toggleExpanded(dispatch, { path }), + onSelectNode: nodeName => + HeatValidationActionHelper.onSelectNode(dispatch, { nodeName }), + onDeselectNode: () => + HeatValidationActionHelper.onDeselectNode(dispatch) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(HeatValidationView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(HeatValidationView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationActionHelper.js index 73366c20cc..5e8e49cf8a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationActionHelper.js @@ -13,27 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './HeatValidationConstants.js'; +import { actionTypes } from './HeatValidationConstants.js'; export default { + toggleExpanded(dispatch, { path }) { + dispatch({ + type: actionTypes.TOGGLE_EXPANDED, + path + }); + }, - toggleExpanded(dispatch, {path}) { - dispatch({ - type: actionTypes.TOGGLE_EXPANDED, - path - }); - }, + onSelectNode(dispatch, { nodeName }) { + dispatch({ + type: actionTypes.SELECTED_NODE, + nodeName + }); + }, - onSelectNode(dispatch, {nodeName}) { - dispatch({ - type: actionTypes.SELECTED_NODE, - nodeName - }); - }, - - onDeselectNode(dispatch) { - dispatch({ - type: actionTypes.UNSELECTED_NODE - }); - } + onDeselectNode(dispatch) { + dispatch({ + type: actionTypes.UNSELECTED_NODE + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js index f783fe6482..8c9f54b5ba 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationConstants.js @@ -17,41 +17,48 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; export const actionTypes = keyMirror({ - TOGGLE_EXPANDED: null, - SELECTED_NODE: null, - UNSELECTED_NODE: null + TOGGLE_EXPANDED: null, + SELECTED_NODE: null, + UNSELECTED_NODE: null }); export const errorTypes = keyMirror({ - MISSING_FILE_IN_ZIP: i18n('missing file in zip'), - MISSING_FILE_IN_MANIFEST: i18n('missing file in manifest'), - MISSING_OR_ILLEGAL_FILE_TYPE_IN_MANIFEST: i18n('missing or illegal file type in manifest'), - FILE_IS_YML_WITHOUT_YML_EXTENSION: i18n('file is defined as a heat file but it doesn\'t have .yml or .yaml extension'), - FILE_IS_ENV_WITHOUT_ENV_EXTENSION: i18n('file is defined as an env file but it doesn\'t have .env extension'), - ILLEGAL_YAML_FILE_CONTENT: i18n('illegal yaml file content'), - ILLEGAL_HEAT_YAML_FILE_CONTENT: i18n('illegal HEAT yaml file content'), - MISSING_FILE_NAME_IN_MANIFEST: i18n('a file is written in manifest without file name'), - MISSING_ENV_FILE_IN_ZIP: i18n('missing env file in zip'), - ARTIFACT_NOT_IN_USE: i18n('artifact not in use') + MISSING_FILE_IN_ZIP: i18n('missing file in zip'), + MISSING_FILE_IN_MANIFEST: i18n('missing file in manifest'), + MISSING_OR_ILLEGAL_FILE_TYPE_IN_MANIFEST: i18n( + 'missing or illegal file type in manifest' + ), + FILE_IS_YML_WITHOUT_YML_EXTENSION: i18n( + "file is defined as a heat file but it doesn't have .yml or .yaml extension" + ), + FILE_IS_ENV_WITHOUT_ENV_EXTENSION: i18n( + "file is defined as an env file but it doesn't have .env extension" + ), + ILLEGAL_YAML_FILE_CONTENT: i18n('illegal yaml file content'), + ILLEGAL_HEAT_YAML_FILE_CONTENT: i18n('illegal HEAT yaml file content'), + MISSING_FILE_NAME_IN_MANIFEST: i18n( + 'a file is written in manifest without file name' + ), + MISSING_ENV_FILE_IN_ZIP: i18n('missing env file in zip'), + ARTIFACT_NOT_IN_USE: i18n('artifact not in use') }); export const errorLevels = keyMirror({ - WARNING: 'WARNING', - ERROR: 'ERROR' + WARNING: 'WARNING', + ERROR: 'ERROR' }); export const nodeFilters = keyMirror({ - ALL: 'All' + ALL: 'All' }); export const nodeTypes = keyMirror({ - heat: i18n('Heat'), - volume: i18n('Volume'), - network: i18n('Network'), - artifact: i18n('Artifact'), - env: i18n('Environment'), - other: i18n('') + heat: i18n('Heat'), + volume: i18n('Volume'), + network: i18n('Network'), + artifact: i18n('Artifact'), + env: i18n('Environment'), + other: i18n('') }); export const mouseActions = keyMirror({ - MOUSE_BUTTON_CLICK: 0 + MOUSE_BUTTON_CLICK: 0 }); - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js index 1d11bdd6b7..67e36ca040 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/attachments/validation/HeatValidationReducer.js @@ -13,185 +13,242 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes as softwareProductsActionTypes} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -import {actionTypes, nodeFilters} from './HeatValidationConstants.js'; +import { actionTypes as softwareProductsActionTypes } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { actionTypes, nodeFilters } from './HeatValidationConstants.js'; -const mapVolumeData = ({fileName, env, errors}) => ({ - name: fileName, - expanded: true, - type: 'volume', - children: env && [{ - name: env.fileName, - errors: env.errors, - type: 'env' - }], - errors +const mapVolumeData = ({ fileName, env, errors }) => ({ + name: fileName, + expanded: true, + type: 'volume', + children: env && [ + { + name: env.fileName, + errors: env.errors, + type: 'env' + } + ], + errors }); -const mapNetworkData = ({fileName, env, errors}) => ({ - name: fileName, - expanded: true, - type: 'network', - children: env && [{ - name: env.fileName, - errors: env.errors, - type: 'env' - }], - errors +const mapNetworkData = ({ fileName, env, errors }) => ({ + name: fileName, + expanded: true, + type: 'network', + children: env && [ + { + name: env.fileName, + errors: env.errors, + type: 'env' + } + ], + errors }); -const mapArtifactsData = ({fileName, errors}) => ({ - name: fileName, - type: 'artifact', - errors +const mapArtifactsData = ({ fileName, errors }) => ({ + name: fileName, + type: 'artifact', + errors }); -const mapOtherData = ({fileName, errors}) => ({ - name: fileName, - type: 'other', - errors +const mapOtherData = ({ fileName, errors }) => ({ + name: fileName, + type: 'other', + errors }); - -const mapHeatData = ({fileName, env, nested, volume, network, artifacts, errors, other}) => ({ - name: fileName, - expanded: true, - type: 'heat', - errors, - children: [ - ...(volume ? volume.map(mapVolumeData) : []), - ...(network ? network.map(mapNetworkData) : []), - ...(env ? [{ - name: env.fileName, - errors: env.errors, - type: 'env' - }] : []), - ...(artifacts ? artifacts.map(mapArtifactsData) : []), - ...(other ? other.map(mapOtherData) : []), - ...(nested ? nested.map(mapHeatData) : []) - ] +const mapHeatData = ({ + fileName, + env, + nested, + volume, + network, + artifacts, + errors, + other +}) => ({ + name: fileName, + expanded: true, + type: 'heat', + errors, + children: [ + ...(volume ? volume.map(mapVolumeData) : []), + ...(network ? network.map(mapNetworkData) : []), + ...(env + ? [ + { + name: env.fileName, + errors: env.errors, + type: 'env' + } + ] + : []), + ...(artifacts ? artifacts.map(mapArtifactsData) : []), + ...(other ? other.map(mapOtherData) : []), + ...(nested ? nested.map(mapHeatData) : []) + ] }); function createErrorList(node, parent, deep = 0, errorList = []) { - if (node.errors) { - errorList.push(...node.errors.map((error) => ({ - level: error.level, - errorMessage: error.message, - name: node.name, - hasParent: deep > 2, - parentName: parent.name, - type: node.type, - }))); - } - if (node.children && node.children.length) { - node.children.map((child) => createErrorList(child, node, deep + 1, errorList)); - } - return errorList; + if (node.errors) { + errorList.push( + ...node.errors.map(error => ({ + level: error.level, + errorMessage: error.message, + name: node.name, + hasParent: deep > 2, + parentName: parent.name, + type: node.type + })) + ); + } + if (node.children && node.children.length) { + node.children.map(child => + createErrorList(child, node, deep + 1, errorList) + ); + } + return errorList; } const mapValidationDataToTree = (validationData, packageName) => { - let {heat, nested, volume, network, artifacts, other} = validationData.importStructure || {}; - return { - children: [ - { - name: packageName, - expanded: true, - type: 'heat', - header: true, - children: (heat ? heat.map(mapHeatData) : nested ? nested.map(mapHeatData) : []) - }, - ...(artifacts ? [{ - name: 'artifacts', - expanded: true, - type: 'artifact', - children: (artifacts ? artifacts.map(mapArtifactsData) : []) - }] : []), - ...(network ? [{ - name: 'networks', - expanded: true, - type: 'network', - children: (network ? network.map(mapNetworkData) : []), - }] : []), - ...(volume ? [{ - name: 'volume', - expanded: true, - type: 'volume', - children: (volume ? volume.map(mapVolumeData) : []), - }] : []), - ...(other ? [{ - name: 'other', - expanded: true, - type: 'other', - children: (other ? other.map(mapOtherData) : []), - }] : []) - ] - }; + let { heat, nested, volume, network, artifacts, other } = + validationData.importStructure || {}; + return { + children: [ + { + name: packageName, + expanded: true, + type: 'heat', + header: true, + children: heat + ? heat.map(mapHeatData) + : nested ? nested.map(mapHeatData) : [] + }, + ...(artifacts + ? [ + { + name: 'artifacts', + expanded: true, + type: 'artifact', + children: artifacts + ? artifacts.map(mapArtifactsData) + : [] + } + ] + : []), + ...(network + ? [ + { + name: 'networks', + expanded: true, + type: 'network', + children: network ? network.map(mapNetworkData) : [] + } + ] + : []), + ...(volume + ? [ + { + name: 'volume', + expanded: true, + type: 'volume', + children: volume ? volume.map(mapVolumeData) : [] + } + ] + : []), + ...(other + ? [ + { + name: 'other', + expanded: true, + type: 'other', + children: other ? other.map(mapOtherData) : [] + } + ] + : []) + ] + }; }; const toggleExpanded = (node, path) => { - let newNode = {...node}; - if (path.length === 0) { - newNode.expanded = !node.expanded; - } else { - let index = path[0]; - newNode.children = [ - ...node.children.slice(0, index), - toggleExpanded(node.children[index], path.slice(1)), - ...node.children.slice(index + 1) - ]; - } - return newNode; + let newNode = { ...node }; + if (path.length === 0) { + newNode.expanded = !node.expanded; + } else { + let index = path[0]; + newNode.children = [ + ...node.children.slice(0, index), + toggleExpanded(node.children[index], path.slice(1)), + ...node.children.slice(index + 1) + ]; + } + return newNode; }; const expandSelected = (node, selectedNode) => { - let shouldExpand = node.name === selectedNode; - let children = node.children && node.children.map(child => { - let {shouldExpand: shouldExpandChild, node: newChild} = expandSelected(child, selectedNode); - shouldExpand = shouldExpand || shouldExpandChild; - return newChild; - }); + let shouldExpand = node.name === selectedNode; + let children = + node.children && + node.children.map(child => { + let { + shouldExpand: shouldExpandChild, + node: newChild + } = expandSelected(child, selectedNode); + shouldExpand = shouldExpand || shouldExpandChild; + return newChild; + }); - return { - node: { - ...node, - expanded: node.expanded || shouldExpand, - children - }, - shouldExpand - }; + return { + node: { + ...node, + expanded: node.expanded || shouldExpand, + children + }, + shouldExpand + }; }; -export default (state = {attachmentsTree: {}}, action) => { - switch (action.type) { - case softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED: - let currentSoftwareProduct = action.response; - const packageName = currentSoftwareProduct.networkPackageName; - let attachmentsTree = currentSoftwareProduct.validationData ? mapValidationDataToTree(currentSoftwareProduct.validationData, packageName) : {}; - let errorList = createErrorList(attachmentsTree); - return { - ...state, - attachmentsTree, - errorList, - selectedNode: nodeFilters.ALL - }; - case actionTypes.TOGGLE_EXPANDED: - return { - ...state, - attachmentsTree: toggleExpanded(state.attachmentsTree, action.path) - }; - case actionTypes.SELECTED_NODE: - let selectedNode = action.nodeName; - return { - ...state, - attachmentsTree: expandSelected(state.attachmentsTree, selectedNode).node, - selectedNode - }; - case actionTypes.UNSELECTED_NODE: - return { - ...state, - selectedNode: nodeFilters.ALL - }; - default: - return state; - } +export default (state = { attachmentsTree: {} }, action) => { + switch (action.type) { + case softwareProductsActionTypes.SOFTWARE_PRODUCT_LOADED: + let currentSoftwareProduct = action.response; + const packageName = currentSoftwareProduct.networkPackageName; + let attachmentsTree = currentSoftwareProduct.validationData + ? mapValidationDataToTree( + currentSoftwareProduct.validationData, + packageName + ) + : {}; + let errorList = createErrorList(attachmentsTree); + return { + ...state, + attachmentsTree, + errorList, + selectedNode: nodeFilters.ALL + }; + case actionTypes.TOGGLE_EXPANDED: + return { + ...state, + attachmentsTree: toggleExpanded( + state.attachmentsTree, + action.path + ) + }; + case actionTypes.SELECTED_NODE: + let selectedNode = action.nodeName; + return { + ...state, + attachmentsTree: expandSelected( + state.attachmentsTree, + selectedNode + ).node, + selectedNode + }; + case actionTypes.UNSELECTED_NODE: + return { + ...state, + selectedNode: nodeFilters.ALL + }; + default: + return state; + } }; 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 3fdaa9c591..c6ee5efd36 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 @@ -13,254 +13,352 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; import Collapse from 'react-bootstrap/lib/Collapse.js'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {mouseActions, errorLevels, nodeFilters} from './HeatValidationConstants.js'; +import { + mouseActions, + errorLevels, + nodeFilters +} from './HeatValidationConstants.js'; const leftPanelWidth = 250; const typeToIcon = Object.freeze({ - heat: 'nestedHeat', - volume: 'base', - network: 'network', - artifact: 'artifacts', - env: 'env', - other: 'other' + heat: 'nestedHeat', + volume: 'base', + network: 'network', + artifact: 'artifacts', + env: 'env', + other: 'other' }); - class HeatValidationView extends Component { + static propTypes = { + attachmentsTree: PropTypes.object.isRequired, + errorList: PropTypes.array.isRequired, + currentErrors: PropTypes.array.isRequired, + currentWarnings: PropTypes.array.isRequired, + onSelectNode: PropTypes.func.isRequired, + onDeselectNode: PropTypes.func.isRequired, + toggleExpanded: PropTypes.func.isRequired, + selectedNode: PropTypes.string + }; - static propTypes = { - attachmentsTree: PropTypes.object.isRequired, - errorList: PropTypes.array.isRequired, - currentErrors: PropTypes.array.isRequired, - currentWarnings: PropTypes.array.isRequired, - onSelectNode: PropTypes.func.isRequired, - onDeselectNode: PropTypes.func.isRequired, - toggleExpanded: PropTypes.func.isRequired, - selectedNode: PropTypes.string - }; - - render() { - return (<div className='vsp-attachments-heat-validation' data-test-id='heat-validation-editor'> - <HeatFileTree errorList={this.props.errorList} attachmentsTree={this.props.attachmentsTree} - onSelectNode={this.props.onSelectNode} toggleExpanded={this.props.toggleExpanded} - selectedNode={this.props.selectedNode} onDeselectNode={this.props.onDeselectNode} /> - <HeatMessageBoard errors={this.props.currentErrors} warnings={this.props.currentWarnings} selectedNode={this.props.selectedNode} /> - </div> ); - } + render() { + return ( + <div + className="vsp-attachments-heat-validation" + data-test-id="heat-validation-editor"> + <HeatFileTree + errorList={this.props.errorList} + attachmentsTree={this.props.attachmentsTree} + onSelectNode={this.props.onSelectNode} + toggleExpanded={this.props.toggleExpanded} + selectedNode={this.props.selectedNode} + onDeselectNode={this.props.onDeselectNode} + /> + <HeatMessageBoard + errors={this.props.currentErrors} + warnings={this.props.currentWarnings} + selectedNode={this.props.selectedNode} + /> + </div> + ); + } } function HeatFileTreeRow(props) { - let {node, path, toggleExpanded, selectedNode, selectNode} = props; - let isFolder = node.children && node.children.length > 0; - return ( - <div onDoubleClick={() => toggleExpanded(path)} className={classNames({ - 'tree-node-row': true, - 'tree-node-clicked': node.name === props.selectedNode - })} data-test-id='validation-tree-node'> - <div className='name-section'> - { - isFolder && - <div onClick={() => toggleExpanded(path)} - className='tree-node-expander'> - <SVGIcon name={!node.expanded ? 'chevronUp' : 'chevronDown'} data-test-id='validation-tree-block-toggle'/> - </div> - } - { - - <span className='tree-node-icon'> - <SVGIcon name={typeToIcon[node.type]} color={selectedNode === node.name ? 'primary' : 'secondary'}/> - </span> - } - { - - <span className='tree-node-name' onClick={() => selectNode(node.name)} data-test-id='validation-tree-node-name'> - {node.name ? node.name : 'UNKNOWN'} - </span> - } - </div> - <ErrorsAndWarningsCount errorList={node.errors} onClick={() => selectNode(node.name)} /> - </div>); + let { node, path, toggleExpanded, selectedNode, selectNode } = props; + let isFolder = node.children && node.children.length > 0; + return ( + <div + onDoubleClick={() => toggleExpanded(path)} + className={classNames({ + 'tree-node-row': true, + 'tree-node-clicked': node.name === props.selectedNode + })} + data-test-id="validation-tree-node"> + <div className="name-section"> + {isFolder && ( + <div + onClick={() => toggleExpanded(path)} + className="tree-node-expander"> + <SVGIcon + name={!node.expanded ? 'chevronUp' : 'chevronDown'} + data-test-id="validation-tree-block-toggle" + /> + </div> + )} + { + <span className="tree-node-icon"> + <SVGIcon + name={typeToIcon[node.type]} + color={ + selectedNode === node.name + ? 'primary' + : 'secondary' + } + /> + </span> + } + { + <span + className="tree-node-name" + onClick={() => selectNode(node.name)} + data-test-id="validation-tree-node-name"> + {node.name ? node.name : 'UNKNOWN'} + </span> + } + </div> + <ErrorsAndWarningsCount + errorList={node.errors} + onClick={() => selectNode(node.name)} + /> + </div> + ); } function HeatFileTreeHeader(props) { - let hasErrors = props.errorList.filter(error => error.level === errorLevels.ERROR).length > 0; - return ( - <div onClick={() => props.selectNode(nodeFilters.ALL)} className={classNames({'attachments-tree-header': true, - 'header-selected' : props.selectedNode === nodeFilters.ALL})} data-test-id='validation-tree-header'> - <div className='tree-header-title' > - {/*<SVGIcon name='zip' color={props.selectedNode === nodeFilters.ALL ? 'primary' : ''} iconClassName='header-icon' />*/} - <span className={classNames({'tree-header-title-text' : true, - 'tree-header-title-selected' : props.selectedNode === nodeFilters.ALL})}>{i18n('{title} {hasErrors}', {title: props.headerTitle, hasErrors: hasErrors ? '(Draft)' : ''})}</span> - </div> - <ErrorsAndWarningsCount errorList={props.errorList} size='large' /> - </div>); + let hasErrors = + props.errorList.filter(error => error.level === errorLevels.ERROR) + .length > 0; + return ( + <div + onClick={() => props.selectNode(nodeFilters.ALL)} + className={classNames({ + 'attachments-tree-header': true, + 'header-selected': props.selectedNode === nodeFilters.ALL + })} + data-test-id="validation-tree-header"> + <div className="tree-header-title"> + {/*<SVGIcon name='zip' color={props.selectedNode === nodeFilters.ALL ? 'primary' : ''} iconClassName='header-icon' />*/} + <span + className={classNames({ + 'tree-header-title-text': true, + 'tree-header-title-selected': + props.selectedNode === nodeFilters.ALL + })}> + {i18n('{title} {hasErrors}', { + title: props.headerTitle, + hasErrors: hasErrors ? '(Draft)' : '' + })} + </span> + </div> + <ErrorsAndWarningsCount errorList={props.errorList} size="large" /> + </div> + ); } -class HeatFileTree extends React.Component { - static propTypes = { - attachmentsTree: PropTypes.object.isRequired, - errorList: PropTypes.array.isRequired, - onSelectNode: PropTypes.func.isRequired, - onDeselectNode: PropTypes.func.isRequired, - toggleExpanded: PropTypes.func.isRequired, - selectedNode: PropTypes.string - }; - state = { - treeWidth: '400' - }; - render() { - let {attachmentsTree} = this.props; - return ( - <div className='validation-tree-section' style={{'width' : this.state.treeWidth + 'px'}}> - <div className='vsp-attachments-heat-validation-tree'> - <div className='tree-wrapper'> - {attachmentsTree && attachmentsTree.children && attachmentsTree.children.map((child, ind) => this.renderNode(child, [ind]))} - </div> - </div> - <div onMouseDown={(e) => this.onChangeTreeWidth(e)} - className='vsp-attachments-heat-validation-separator' data-test-id='validation-tree-separator'></div> - </div>); - } - renderNode(node, path) { - let rand = Math.random() * (3000 - 1) + 1; - let isFolder = node.children && node.children.length > 0; - let {selectedNode} = this.props; - return ( - <div key={node.name + rand} className={classNames({'tree-block-inside' : !node.header})}> - { - node.header ? - <HeatFileTreeHeader headerTitle={node.name} selectedNode={selectedNode} errorList={this.props.errorList} selectNode={(nodeName) => this.selectNode(nodeName)} /> : - <HeatFileTreeRow toggleExpanded={this.props.toggleExpanded} node={node} path={path} selectedNode={selectedNode} selectNode={() => this.selectNode(node.name)} /> - } - { - isFolder && - <Collapse in={node.expanded}> - <div className='tree-node-children'> - { - node.children.map((child, ind) => this.renderNode(child, [...path, ind])) - } - </div> - </Collapse> - } - </div> - ); - } - - - - - - selectNode(currentSelectedNode) { - let {onDeselectNode, onSelectNode, selectedNode} = this.props; - if (currentSelectedNode !== selectedNode) { - onSelectNode(currentSelectedNode); - } else { - onDeselectNode(); - } - - +class HeatFileTree extends React.Component { + static propTypes = { + attachmentsTree: PropTypes.object.isRequired, + errorList: PropTypes.array.isRequired, + onSelectNode: PropTypes.func.isRequired, + onDeselectNode: PropTypes.func.isRequired, + toggleExpanded: PropTypes.func.isRequired, + selectedNode: PropTypes.string + }; + state = { + treeWidth: '400' + }; + render() { + let { attachmentsTree } = this.props; + return ( + <div + className="validation-tree-section" + style={{ width: this.state.treeWidth + 'px' }}> + <div className="vsp-attachments-heat-validation-tree"> + <div className="tree-wrapper"> + {attachmentsTree && + attachmentsTree.children && + attachmentsTree.children.map((child, ind) => + this.renderNode(child, [ind]) + )} + </div> + </div> + <div + onMouseDown={e => this.onChangeTreeWidth(e)} + className="vsp-attachments-heat-validation-separator" + data-test-id="validation-tree-separator" + /> + </div> + ); + } + renderNode(node, path) { + let rand = Math.random() * (3000 - 1) + 1; + let isFolder = node.children && node.children.length > 0; + let { selectedNode } = this.props; + return ( + <div + key={node.name + rand} + className={classNames({ 'tree-block-inside': !node.header })}> + {node.header ? ( + <HeatFileTreeHeader + headerTitle={node.name} + selectedNode={selectedNode} + errorList={this.props.errorList} + selectNode={nodeName => this.selectNode(nodeName)} + /> + ) : ( + <HeatFileTreeRow + toggleExpanded={this.props.toggleExpanded} + node={node} + path={path} + selectedNode={selectedNode} + selectNode={() => this.selectNode(node.name)} + /> + )} + {isFolder && ( + <Collapse in={node.expanded}> + <div className="tree-node-children"> + {node.children.map((child, ind) => + this.renderNode(child, [...path, ind]) + )} + </div> + </Collapse> + )} + </div> + ); + } - } + selectNode(currentSelectedNode) { + let { onDeselectNode, onSelectNode, selectedNode } = this.props; + if (currentSelectedNode !== selectedNode) { + onSelectNode(currentSelectedNode); + } else { + onDeselectNode(); + } + } - onChangeTreeWidth(e) { - if (e.button === mouseActions.MOUSE_BUTTON_CLICK) { - let onMouseMove = (e) => { - this.setState({treeWidth: e.clientX - leftPanelWidth}); - }; - let onMouseUp = () => { - document.removeEventListener('mousemove', onMouseMove); - document.removeEventListener('mouseup', onMouseUp); - }; - document.addEventListener('mousemove', onMouseMove); - document.addEventListener('mouseup', onMouseUp); - } - } + onChangeTreeWidth(e) { + if (e.button === mouseActions.MOUSE_BUTTON_CLICK) { + let onMouseMove = e => { + this.setState({ treeWidth: e.clientX - leftPanelWidth }); + }; + let onMouseUp = () => { + document.removeEventListener('mousemove', onMouseMove); + document.removeEventListener('mouseup', onMouseUp); + }; + document.addEventListener('mousemove', onMouseMove); + document.addEventListener('mouseup', onMouseUp); + } + } } class HeatMessageBoard extends Component { - static propTypes = { - currentErrors: PropTypes.array, - currentWarnings: PropTypes.array, - selectedNode: PropTypes.string - }; - render() { - let {errors, warnings} = this.props; - let allItems = [...errors, ...warnings]; - return ( - <div className='message-board-section'> - { allItems.map(error => this.renderError(error)) } - </div> - ); - } - renderError(error) { - let rand = Math.random() * (3000 - 1) + 1; - return ( - <div - key={error.name + error.errorMessage + error.parentName + rand} - className='error-item' data-test-id='validation-error'> - {error.level === errorLevels.WARNING ? - <SVGIcon name='exclamationTriangleLine' iconClassName='large' color='warning' /> : <SVGIcon name='error' iconClassName='large' color='negative' /> } - <span className='error-item-file-type'> - { - (this.props.selectedNode === nodeFilters.ALL) ? - <span> - <span className='error-file-name'> - {error.name} - </span> - <span> - {error.errorMessage} - </span> - </span> : - error.errorMessage - } - </span> - </div> - ); - } + static propTypes = { + currentErrors: PropTypes.array, + currentWarnings: PropTypes.array, + selectedNode: PropTypes.string + }; + render() { + let { errors, warnings } = this.props; + let allItems = [...errors, ...warnings]; + return ( + <div className="message-board-section"> + {allItems.map(error => this.renderError(error))} + </div> + ); + } + renderError(error) { + let rand = Math.random() * (3000 - 1) + 1; + return ( + <div + key={error.name + error.errorMessage + error.parentName + rand} + className="error-item" + data-test-id="validation-error"> + {error.level === errorLevels.WARNING ? ( + <SVGIcon + name="exclamationTriangleLine" + iconClassName="large" + color="warning" + /> + ) : ( + <SVGIcon + name="error" + iconClassName="large" + color="negative" + /> + )} + <span className="error-item-file-type"> + {this.props.selectedNode === nodeFilters.ALL ? ( + <span> + <span className="error-file-name"> + {error.name} + </span> + <span>{error.errorMessage}</span> + </span> + ) : ( + error.errorMessage + )} + </span> + </div> + ); + } } class ErrorsAndWarningsCount extends Component { - static propTypes = { - errorList: PropTypes.array, - size: PropTypes.string - }; - render() { - let errors = this.getErrorsAndWarningsCount(this.props.errorList); - if (!errors) { - return null; - } - let {size} = this.props; - return (<div className='counters'> - {(errors.errorCount > 0) && <div className='counter'> - <SVGIcon name='error' color='negative' iconClassName={size}/> - <div className={'error-text ' + (size ? size : '')} data-test-id='validation-error-count'>{errors.errorCount}</div> - </div>} - {(errors.warningCount > 0) && <div className='counter'> - <SVGIcon name='exclamationTriangleLine' iconClassName={size} color='warning'/> - <div className={'warning-text ' + (size ? size : '')} data-test-id='validation-warning-count'>{errors.warningCount}</div> - </div>} - </div>); - } - getErrorsAndWarningsCount(errorList) { - let errorCount = 0, warningCount = 0; - if (errorList && errorList.length > 0) { - for (let i = 0; i < errorList.length; i++) { - if (errorList[i].level === errorLevels.ERROR) { - errorCount++; - } else if (errorList[i].level === errorLevels.WARNING) { - warningCount++; - } - } - } - if (errorCount === 0 && warningCount === 0) { - return null; - } - return {errorCount, warningCount}; - } + static propTypes = { + errorList: PropTypes.array, + size: PropTypes.string + }; + render() { + let errors = this.getErrorsAndWarningsCount(this.props.errorList); + if (!errors) { + return null; + } + let { size } = this.props; + return ( + <div className="counters"> + {errors.errorCount > 0 && ( + <div className="counter"> + <SVGIcon + name="error" + color="negative" + iconClassName={size} + /> + <div + className={'error-text ' + (size ? size : '')} + data-test-id="validation-error-count"> + {errors.errorCount} + </div> + </div> + )} + {errors.warningCount > 0 && ( + <div className="counter"> + <SVGIcon + name="exclamationTriangleLine" + iconClassName={size} + color="warning" + /> + <div + className={'warning-text ' + (size ? size : '')} + data-test-id="validation-warning-count"> + {errors.warningCount} + </div> + </div> + )} + </div> + ); + } + getErrorsAndWarningsCount(errorList) { + let errorCount = 0, + warningCount = 0; + if (errorList && errorList.length > 0) { + for (let i = 0; i < errorList.length; i++) { + if (errorList[i].level === errorLevels.ERROR) { + errorCount++; + } else if (errorList[i].level === errorLevels.WARNING) { + warningCount++; + } + } + } + if (errorCount === 0 && warningCount === 0) { + return null; + } + return { errorCount, warningCount }; + } } export default HeatValidationView; 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 b13bde03c8..e59337c122 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentEditorReducer.js @@ -13,79 +13,83 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, forms} from './SoftwareProductComponentsConstants.js'; +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, - data: action.component, - formReady: null, - formName: forms.ALL_SPC_FORMS, - genericFieldInfo: { - 'displayName' : { - isValid: true, - errorText: '', - validations: [] - }, - 'vfcCode' : { - isValid: true, - errorText: '', - validations: [] - }, - 'nfcFunction' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 30}] - }, - 'description' : { - isValid: true, - errorText: '', - validations: [] - } - } - }; - 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; - } + 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, + data: action.component, + formReady: null, + formName: forms.ALL_SPC_FORMS, + genericFieldInfo: { + displayName: { + isValid: true, + errorText: '', + validations: [] + }, + vfcCode: { + isValid: true, + errorText: '', + validations: [] + }, + nfcFunction: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 30 }] + }, + description: { + isValid: true, + errorText: '', + validations: [] + } + } + }; + 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 index f74b2fe2fb..bffa9f7d25 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js @@ -1,50 +1,71 @@ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SoftwareProductComponentsActionHelper from '../components/SoftwareProductComponentsActionHelper.js'; -import {onboardingMethod as onboardingMethodTypes} from '../SoftwareProductConstants.js'; +import { onboardingMethod as onboardingMethodTypes } from '../SoftwareProductConstants.js'; import ConfirmationModalConstants from 'nfvo-components/modal/GlobalModalConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import SoftwareProductComponentsView from './SoftwareProductComponentsListView.jsx'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; -const generateMessage = (name) => { - return i18n('Are you sure you want to delete {name}?', {name: name}); +const generateMessage = name => { + return i18n('Are you sure you want to delete {name}?', { name: name }); }; -const mapStateToProps = ({softwareProduct, currentScreen: {props: {version}}}) => { - let {softwareProductEditor: {data: currentSoftwareProduct = {}}, softwareProductComponents} = softwareProduct; - let {componentsList} = softwareProductComponents; - let {onboardingMethod = onboardingMethodTypes.HEAT} = currentSoftwareProduct; - return { - currentSoftwareProduct, - componentsList, - isManual: onboardingMethod === onboardingMethodTypes.MANUAL, - version - }; +const mapStateToProps = ({ + softwareProduct, + currentScreen: { props: { version } } +}) => { + let { + softwareProductEditor: { data: currentSoftwareProduct = {} }, + softwareProductComponents + } = softwareProduct; + let { componentsList } = softwareProductComponents; + let { + onboardingMethod = onboardingMethodTypes.HEAT + } = currentSoftwareProduct; + return { + currentSoftwareProduct, + componentsList, + isManual: onboardingMethod === onboardingMethodTypes.MANUAL, + version + }; }; -const mapActionToProps = (dispatch) => { - return { - onComponentSelect: ({id: softwareProductId, componentId, version}) => - ScreensHelper.loadScreen(dispatch, { - screen: screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version, componentId} - }), - onAddComponent: (softwareProductId, version) => SoftwareProductActionHelper.addComponent(dispatch, {softwareProductId, version, modalClassName: 'create-vfc-modal'}), - onDeleteComponent: (component, softwareProductId, version) => dispatch({ - type: ConfirmationModalConstants.GLOBAL_MODAL_WARNING, - data:{ - msg: generateMessage(component.displayName), - onConfirmed: ()=>SoftwareProductComponentsActionHelper.deleteComponent(dispatch, { - softwareProductId, - componentId: component.id, - version - }) - } - }) - }; +const mapActionToProps = dispatch => { + return { + onComponentSelect: ({ id: softwareProductId, componentId, version }) => + ScreensHelper.loadScreen(dispatch, { + screen: screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version, componentId } + }), + onAddComponent: (softwareProductId, version) => + SoftwareProductActionHelper.addComponent(dispatch, { + softwareProductId, + version, + modalClassName: 'create-vfc-modal' + }), + 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); +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 cf63ad79d0..73a971ccbb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js @@ -16,157 +16,265 @@ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes, COMPONENTS_QUESTIONNAIRE} from './SoftwareProductComponentsConstants.js'; +import { + actionTypes, + COMPONENTS_QUESTIONNAIRE +} from './SoftwareProductComponentsConstants.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; function baseUrl(softwareProductId, version) { - const versionId = version.id; - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components`; + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/components`; } function fetchSoftwareProductComponents(softwareProductId, version) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); } -function putSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId, vspComponent) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${vspComponentId}/questionnaire`, vspComponent); +function putSoftwareProductComponentQuestionnaire( + softwareProductId, + version, + vspComponentId, + vspComponent +) { + return RestAPIUtil.put( + `${baseUrl( + softwareProductId, + version + )}/${vspComponentId}/questionnaire`, + vspComponent + ); } -function fetchSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId){ - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}/${vspComponentId}/questionnaire`); +function fetchSoftwareProductComponentQuestionnaire( + softwareProductId, + version, + vspComponentId +) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version)}/${vspComponentId}/questionnaire` + ); } -function fetchSoftwareProductComponent(softwareProductId, version, vspComponentId){ - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}/${vspComponentId}`); +function fetchSoftwareProductComponent( + softwareProductId, + version, + vspComponentId +) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version)}/${vspComponentId}` + ); } -function putSoftwareProductComponent(softwareProductId, version, vspComponentId, vspComponent) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${vspComponentId}`, { - name: vspComponent.name, - displayName: vspComponent.displayName, - vfcCode: vspComponent.vfcCode, - nfcFunction: vspComponent.nfcFunction, - description: vspComponent.description - }); +function putSoftwareProductComponent( + softwareProductId, + version, + vspComponentId, + vspComponent +) { + return RestAPIUtil.put( + `${baseUrl(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 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 + }); +} -function postSoftwareProductComponent(softwareProductId, vspComponent, version) { +const SoftwareProductComponentsActionHelper = { + fetchSoftwareProductComponents(dispatch, { softwareProductId, version }) { + return fetchSoftwareProductComponents(softwareProductId, version).then( + response => { + dispatch({ + type: actionTypes.COMPONENTS_LIST_UPDATE, + componentsList: response.results + }); + return response; + } + ); + }, - return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { - name: vspComponent.displayName, - displayName: vspComponent.displayName, - description: vspComponent.description - }); -} + updateSoftwareProductComponent( + dispatch, + { softwareProductId, version, vspComponentId, componentData, qdata } + ) { + return Promise.all([ + SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { softwareProductId, version, vspComponentId, qdata } + ), + SoftwareProductComponentsActionHelper.updateSoftwareProductComponentData( + dispatch, + { softwareProductId, version, vspComponentId, componentData } + ) + ]); + }, + updateSoftwareProductComponentQuestionnaire( + dispatch, + { softwareProductId, version, vspComponentId, qdata } + ) { + return putSoftwareProductComponentQuestionnaire( + softwareProductId, + version, + vspComponentId, + qdata + ); + }, -const SoftwareProductComponentsActionHelper = { - fetchSoftwareProductComponents(dispatch, {softwareProductId, version}) { - return fetchSoftwareProductComponents(softwareProductId, version).then(response => { - dispatch({ - type: actionTypes.COMPONENTS_LIST_UPDATE, - componentsList: response.results - }); - return response; - }); - }, - - updateSoftwareProductComponent(dispatch, {softwareProductId, version, vspComponentId, componentData, qdata}) { - return Promise.all([ - SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId, qdata}), - SoftwareProductComponentsActionHelper.updateSoftwareProductComponentData(dispatch, {softwareProductId, version, vspComponentId, componentData}) - ]); - }, - - updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId, qdata}) { - return putSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId, qdata); - }, - - updateSoftwareProductComponentData(dispatch, {softwareProductId, version, vspComponentId, componentData}) { - return putSoftwareProductComponent(softwareProductId, version, vspComponentId, componentData).then(() => dispatch({ - type: actionTypes.COMPONENTS_LIST_EDIT, - component: { - id: vspComponentId, - ...componentData - } - })); - }, - - fetchSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId}) { - return fetchSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId).then(response => { - ValidationHelper.qDataLoaded(dispatch, {qName: COMPONENTS_QUESTIONNAIRE, response: {qdata: response.data ? JSON.parse(response.data) : {}, - qschema: JSON.parse(response.schema)}}); - }); - }, - - fetchSoftwareProductComponent(dispatch, {softwareProductId, version, vspComponentId}) { - return Promise.all([ - fetchSoftwareProductComponent(softwareProductId, version, vspComponentId).then(response => { - dispatch({ - type: actionTypes.COMPONENT_LOAD, - component: response.data - }); - return response; - }), - fetchSoftwareProductComponentQuestionnaire(softwareProductId, version, vspComponentId).then(response => { - ValidationHelper.qDataLoaded(dispatch, {qName: COMPONENTS_QUESTIONNAIRE, response: {qdata: response.data ? JSON.parse(response.data) : {}, - qschema: JSON.parse(response.schema)}}); - }) - ]); - }, - - - clearComponentsStore(dispatch) { - dispatch({ - 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 - }); - }, + updateSoftwareProductComponentData( + dispatch, + { softwareProductId, version, vspComponentId, componentData } + ) { + return putSoftwareProductComponent( + softwareProductId, + version, + vspComponentId, + componentData + ).then(() => + dispatch({ + type: actionTypes.COMPONENTS_LIST_EDIT, + component: { + id: vspComponentId, + ...componentData + } + }) + ); + }, + + fetchSoftwareProductComponentQuestionnaire( + dispatch, + { softwareProductId, version, vspComponentId } + ) { + return fetchSoftwareProductComponentQuestionnaire( + softwareProductId, + version, + vspComponentId + ).then(response => { + ValidationHelper.qDataLoaded(dispatch, { + qName: COMPONENTS_QUESTIONNAIRE, + response: { + qdata: response.data ? JSON.parse(response.data) : {}, + qschema: JSON.parse(response.schema) + } + }); + }); + }, + + fetchSoftwareProductComponent( + dispatch, + { softwareProductId, version, vspComponentId } + ) { + return Promise.all([ + fetchSoftwareProductComponent( + softwareProductId, + version, + vspComponentId + ).then(response => { + dispatch({ + type: actionTypes.COMPONENT_LOAD, + component: response.data + }); + return response; + }), + fetchSoftwareProductComponentQuestionnaire( + softwareProductId, + version, + vspComponentId + ).then(response => { + ValidationHelper.qDataLoaded(dispatch, { + qName: COMPONENTS_QUESTIONNAIRE, + response: { + qdata: response.data ? JSON.parse(response.data) : {}, + qschema: JSON.parse(response.schema) + } + }); + }) + ]); + }, + + clearComponentsStore(dispatch) { + dispatch({ + 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 35633b65cf..cc120d359a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js @@ -16,40 +16,40 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - COMPONENTS_LIST_UPDATE: null, - COMPONENTS_LIST_EDIT: 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 + COMPONENTS_LIST_UPDATE: null, + COMPONENTS_LIST_EDIT: 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({ - backupType: { - ON_SITE: 'OnSite', - OFF_SITE: 'OffSite' - } +export const storageConstants = keyMirror({ + backupType: { + ON_SITE: 'OnSite', + OFF_SITE: 'OffSite' + } }); export const forms = keyMirror({ - ALL_SPC_FORMS: null, - NIC_EDIT_FORM: null, - CREATE_FORM: null, - IMAGE_EDIT_FORM: null + ALL_SPC_FORMS: 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' + 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/SoftwareProductComponentsListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js index 92211e0fd2..e1cf5f4fc3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListReducer.js @@ -13,18 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentsConstants.js'; +import { actionTypes } from './SoftwareProductComponentsConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.COMPONENTS_LIST_UPDATE: - return [...action.componentsList]; - 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; - } + switch (action.type) { + case actionTypes.COMPONENTS_LIST_UPDATE: + return [...action.componentsList]; + 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 0bf32df1a3..fc8abf6ff6 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsListView.jsx @@ -22,85 +22,113 @@ import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.js import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; const ComponentPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - displayName: PropTypes.string, - description: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + displayName: PropTypes.string, + description: PropTypes.string }); class SoftwareProductComponentsListView extends React.Component { + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; + static propTypes = { + isReadOnlyMode: PropTypes.bool, + componentsList: PropTypes.arrayOf(ComponentPropType), + onComponentSelect: PropTypes.func + }; - static propTypes = { - isReadOnlyMode: PropTypes.bool, - componentsList: PropTypes.arrayOf(ComponentPropType), - onComponentSelect: PropTypes.func - }; + render() { + let { componentsList = [], isManual } = this.props; + return ( + <div className=""> + {(componentsList.length > 0 || isManual) && + this.renderComponents()} + </div> + ); + } - render() { - let {componentsList = [], isManual} = this.props; - return ( - <div className=''> - { - (componentsList.length > 0 || isManual) && this.renderComponents() - } - </div> - ); - } + renderComponents() { + const { localFilter } = this.state; + const { + isManual, + onAddComponent, + isReadOnlyMode, + version, + 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 || !!this.filterList().length} + plusButtonTitle={i18n('Add Component')} + onAdd={ + isManual && componentsList.length === 0 + ? () => onAddComponent(softwareProductId, version) + : false + } + twoColumns> + {this.filterList().map(component => + this.renderComponentsListItem(component) + )} + </ListEditorView> + ); + } - renderComponents() { - const {localFilter} = this.state; - const {isManual, onAddComponent, isReadOnlyMode, version, 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 || !!this.filterList().length} - plusButtonTitle={i18n('Add Component')} - onAdd={isManual && componentsList.length === 0 ? () => onAddComponent(softwareProductId, version) : false} - twoColumns> - {this.filterList().map(component => this.renderComponentsListItem(component))} - </ListEditorView> - ); - } + renderComponentsListItem(component) { + let { + id: componentId, + name, + displayName, + description = '' + } = component; + let { + currentSoftwareProduct: { id }, + onComponentSelect, + version + } = this.props; + return ( + <ListEditorItemView + key={ + name + Math.floor(Math.random() * (100 - 1) + 1).toString() + } + className="list-editor-item-view" + onSelect={() => + onComponentSelect({ id, componentId, version }) + }> + <ListEditorItemViewField> + <div className="name">{displayName}</div> + </ListEditorItemViewField> + <ListEditorItemViewField> + <div className="description">{description}</div> + </ListEditorItemViewField> + </ListEditorItemView> + ); + } - renderComponentsListItem(component) { - let {id: componentId, name, displayName, description = ''} = component; - let {currentSoftwareProduct: {id}, onComponentSelect, version} = this.props; - return ( - <ListEditorItemView - key={name + Math.floor(Math.random() * (100 - 1) + 1).toString()} - className='list-editor-item-view' - onSelect={() => onComponentSelect({id, componentId, version})}> - <ListEditorItemViewField> - <div className='name'>{displayName}</div> - </ListEditorItemViewField> - <ListEditorItemViewField> - <div className='description'>{description}</div> - </ListEditorItemViewField> - </ListEditorItemView> - ); - } + filterList() { + let { componentsList = [] } = this.props; - 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; - } - } + 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; + } + } } export default SoftwareProductComponentsListView; 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 index 02c09fbdf8..cd37c317af 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/compute/ComputeFlavorActionHelper.js @@ -16,154 +16,270 @@ 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 { 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'; +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`; + 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 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 fetchComputesList(softwareProductId, componentId, version) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, componentId, version)}` + ); } -function fetchComputesListForVSP(softwareProductId, version){ - return RestAPIUtil.fetch(`${baseUrlVSPLevel(softwareProductId, 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}`); + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, componentId, version)}/${computeId}` + ); } -function fetchComputeQuestionnaire({softwareProductId, componentId, computeId, version}) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, componentId, version)}/${computeId}/questionnaire`); +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 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 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 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}`); +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 - })); - } + 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 574828c9ef..d595a82e11 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 @@ -13,35 +13,63 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductComponentComputeView from './SoftwareProductComponentComputeView.jsx'; import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; -import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.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'; +import { onboardingMethod } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { data: currentVSP }, + softwareProductComponents + } = softwareProduct; + let { + componentEditor: { qdata, dataMap, qgenericFieldInfo }, + computeFlavor: { computesList: computeFlavorsList } + } = softwareProductComponents; -const mapStateToProps = ({softwareProduct}) => { - let {softwareProductEditor: {data: currentVSP}, softwareProductComponents} = softwareProduct; - let {componentEditor: {qdata, dataMap, qgenericFieldInfo}, computeFlavor: {computesList: computeFlavorsList}} = softwareProductComponents; - - return { - qdata, - dataMap, - qgenericFieldInfo, - computeFlavorsList, - isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL - }; + return { + qdata, + dataMap, + qgenericFieldInfo, + computeFlavorsList, + isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL + }; }; -const mapActionToProps = (dispatch, {softwareProductId, version, componentId}) => { - return { - onQDataChanged: (deltaData, customValidations) => ValidationHelper.qDataChanged(dispatch, {deltaData, customValidations: customValidations, - qName: COMPONENTS_QUESTIONNAIRE}), - onSubmit: ({qdata}) =>{ return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId: componentId, qdata});}, - qValidateData: (data, customValidations) => ValidationHelper.qValidateData(dispatch, {data, customValidations: customValidations, - qName: COMPONENTS_QUESTIONNAIRE}) - }; +const mapActionToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onQDataChanged: (deltaData, customValidations) => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + customValidations: customValidations, + qName: COMPONENTS_QUESTIONNAIRE + }), + onSubmit: ({ qdata }) => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + qdata + } + ); + }, + qValidateData: (data, customValidations) => + ValidationHelper.qValidateData(dispatch, { + data, + customValidations: customValidations, + qName: COMPONENTS_QUESTIONNAIRE + }) + }; }; -export default connect(mapStateToProps, mapActionToProps, null, {withRef: true}) (SoftwareProductComponentComputeView); +export default connect(mapStateToProps, mapActionToProps, null, { + withRef: true +})(SoftwareProductComponentComputeView); 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 55e5e2b30b..e6ce96666e 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 @@ -22,67 +22,99 @@ import ComputeFlavors from './computeComponents/ComputeFlavors.js'; import Validator from 'nfvo-utils/Validator.js'; class SoftwareProductComponentComputeView extends React.Component { + static propTypes = { + dataMap: PropTypes.object, + qgenericFieldInfo: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + isManual: PropTypes.bool, + onQDataChanged: PropTypes.func.isRequired, + qValidateData: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired + }; - static propTypes = { - dataMap: PropTypes.object, - qgenericFieldInfo: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - isManual: PropTypes.bool, - onQDataChanged: PropTypes.func.isRequired, - qValidateData: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired - }; + render() { + let { + softwareProductId, + componentId, + version, + qdata, + dataMap, + qgenericFieldInfo, + isReadOnlyMode, + onQDataChanged, + qValidateData, + onSubmit, + computeFlavorsList, + isManual + } = this.props; - render() { - let {softwareProductId, componentId, version, qdata, dataMap, qgenericFieldInfo, isReadOnlyMode, onQDataChanged, qValidateData, - onSubmit, computeFlavorsList, isManual} = this.props; + return ( + <div className="vsp-component-questionnaire-view"> + {qgenericFieldInfo && ( + <Form + ref={form => { + this.form = form; + }} + formReady={null} + isValid={true} + hasButtons={false} + onSubmit={() => onSubmit({ qdata })} + className="component-questionnaire-validation-form" + isReadOnlyMode={isReadOnlyMode}> + <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> + ); + } - return ( - <div className='vsp-component-questionnaire-view'> - { qgenericFieldInfo && <Form - ref={ (form) => { this.form = form; }} - formReady={null} - isValid={true} - hasButtons={false} - onSubmit={() => onSubmit({qdata})} - className='component-questionnaire-validation-form' - isReadOnlyMode={isReadOnlyMode} > - <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> - ); - } + save() { + return this.form.handleFormSubmit(new Event('dummy')); + } - save(){ - return this.form.handleFormSubmit(new Event('dummy')); - } + validateMin(value, state) { + let maxVal = state.dataMap['compute/numOfVMs/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'); + } + } - validateMin(value, state) { - let maxVal = state.dataMap['compute/numOfVMs/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']; - 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'); - } - } + validateMax(value, state) { + let minVal = state.dataMap['compute/numOfVMs/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'); + } + } } export default SoftwareProductComponentComputeView; 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 index 2b6d84f381..2004c94137 100644 --- 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 @@ -15,103 +15,159 @@ */ import React from 'react'; import PropTypes from 'prop-types'; -import {connect} from 'react-redux'; +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'; +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}"?', {name: name}), - onConfirmed: () => ComputeFlavorActionHelper.deleteCompute(dispatch, {softwareProductId, componentId, computeId: id, version}) - } - }) - }; +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}"?', { + name: name + }), + onConfirmed: () => + ComputeFlavorActionHelper.deleteCompute(dispatch, { + softwareProductId, + componentId, + computeId: id, + version + }) + } + }) + }; }; const computeItemPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string }); class ComputeFlavors extends React.Component { + static propTypes = { + isReadOnlyMode: PropTypes.bool, + isManual: PropTypes.bool, + onAddComputeClick: PropTypes.func, + computeFlavorsList: PropTypes.arrayOf(computeItemPropType) + }; - static propTypes = { - isReadOnlyMode: PropTypes.bool, - isManual: PropTypes.bool, - onAddComputeClick: PropTypes.func, - computeFlavorsList: PropTypes.arrayOf(computeItemPropType) - }; + state = { + localFilter: '' + }; - 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> + ); + } - 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; - 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 { 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> - ); +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); +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 8ae9961859..c16ab5cdfe 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 @@ -19,57 +19,91 @@ 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 GuestOs = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { - return( - <div> - <GridSection title={i18n('Guest OS')} hasLastColSet> - <GridItem> - <div className='vertical-flex'> - <label key='label' className='control-label'>{i18n('OS Bit Size')}</label> - <div className='radio-options-content-row'> - {qgenericFieldInfo['compute/guestOS/bitSize'].enum.map(bitSize => ( - <Input - data-test-id='guestOS-bitSize' - type='radio' - key={bitSize.enum} - name={'compute/guestOS/bitSize'} - className='radio-field' - value={bitSize.enum} - label={bitSize.title} - onChange={(bit) => onQDataChanged({'compute/guestOS/bitSize' : Number(bit)})} - isValid={qgenericFieldInfo['compute/guestOS/bitSize'].isValid} - errorText={qgenericFieldInfo['compute/guestOS/bitSize'].errorText} - checked={dataMap['compute/guestOS/bitSize'] === bitSize.enum} /> )) } - </div> - </div> - </GridItem> - <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} lastColInRow> - <Input - data-test-id='guestOS-tools' - type='textarea' - label={i18n('Guest OS Tools:')} - onChange={(tools) => onQDataChanged({'compute/guestOS/tools' : tools})} - isValid={qgenericFieldInfo['compute/guestOS/tools'].isValid} - errorText={qgenericFieldInfo['compute/guestOS/tools'].errorText} - value={dataMap['compute/guestOS/tools']} /> - </GridItem> - </GridSection> - - - </div> - ); +const GuestOs = ({ qgenericFieldInfo, dataMap, onQDataChanged }) => { + return ( + <div> + <GridSection title={i18n('Guest OS')} hasLastColSet> + <GridItem> + <div className="vertical-flex"> + <label key="label" className="control-label"> + {i18n('OS Bit Size')} + </label> + <div className="radio-options-content-row"> + {qgenericFieldInfo[ + 'compute/guestOS/bitSize' + ].enum.map(bitSize => ( + <Input + data-test-id="guestOS-bitSize" + type="radio" + key={bitSize.enum} + name={'compute/guestOS/bitSize'} + className="radio-field" + value={bitSize.enum} + label={bitSize.title} + onChange={bit => + onQDataChanged({ + 'compute/guestOS/bitSize': Number( + bit + ) + }) + } + isValid={ + qgenericFieldInfo[ + 'compute/guestOS/bitSize' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'compute/guestOS/bitSize' + ].errorText + } + checked={ + dataMap['compute/guestOS/bitSize'] === + bitSize.enum + } + /> + ))} + </div> + </div> + </GridItem> + <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} lastColInRow> + <Input + data-test-id="guestOS-tools" + type="textarea" + label={i18n('Guest OS Tools:')} + onChange={tools => + onQDataChanged({ 'compute/guestOS/tools': tools }) + } + isValid={ + qgenericFieldInfo['compute/guestOS/tools'].isValid + } + errorText={ + qgenericFieldInfo['compute/guestOS/tools'].errorText + } + value={dataMap['compute/guestOS/tools']} + /> + </GridItem> + </GridSection> + </div> + ); }; export default GuestOs; 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 967c6f7aef..5451354502 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 @@ -20,38 +20,77 @@ 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 NumberOfVms = ({qgenericFieldInfo, dataMap, onQDataChanged, qValidateData, customValidations}) => { - return( - <GridSection titleClassName='software-product-compute-number-of-vms' title={i18n('NUMBER OF VMs')}> - <GridItem> - <Input - data-test-id='numOfVMs-minimum' - type='number' - label={i18n('Minimum')} - onChange={(tools) => { onQDataChanged({'compute/numOfVMs/minimum' : tools}, customValidations); - qValidateData({'compute/numOfVMs/maximum' : dataMap['compute/numOfVMs/maximum']}, customValidations); } } - isValid={qgenericFieldInfo['compute/numOfVMs/minimum'].isValid} - errorText={qgenericFieldInfo['compute/numOfVMs/minimum'].errorText} - value={dataMap['compute/numOfVMs/minimum']} /> - </GridItem> - <GridItem> - <Input - data-test-id='numOfVMs-maximum' - type='number' - label={i18n('Maximum')} - onChange={(tools) => { onQDataChanged({'compute/numOfVMs/maximum' : tools}, customValidations); - qValidateData({'compute/numOfVMs/minimum' : dataMap['compute/numOfVMs/minimum']}, customValidations); } } - isValid={qgenericFieldInfo['compute/numOfVMs/maximum'].isValid} - errorText={qgenericFieldInfo['compute/numOfVMs/maximum'].errorText} - value={dataMap['compute/numOfVMs/maximum']} /> - </GridItem> - </GridSection> - ); +const NumberOfVms = ({ + qgenericFieldInfo, + dataMap, + onQDataChanged, + qValidateData, + customValidations +}) => { + return ( + <GridSection + titleClassName="software-product-compute-number-of-vms" + title={i18n('NUMBER OF VMs')}> + <GridItem> + <Input + data-test-id="numOfVMs-minimum" + type="number" + label={i18n('Minimum')} + onChange={tools => { + onQDataChanged( + { 'compute/numOfVMs/minimum': tools }, + customValidations + ); + qValidateData( + { + 'compute/numOfVMs/maximum': + dataMap['compute/numOfVMs/maximum'] + }, + customValidations + ); + }} + isValid={ + qgenericFieldInfo['compute/numOfVMs/minimum'].isValid + } + errorText={ + qgenericFieldInfo['compute/numOfVMs/minimum'].errorText + } + value={dataMap['compute/numOfVMs/minimum']} + /> + </GridItem> + <GridItem> + <Input + data-test-id="numOfVMs-maximum" + type="number" + label={i18n('Maximum')} + onChange={tools => { + onQDataChanged( + { 'compute/numOfVMs/maximum': tools }, + customValidations + ); + qValidateData( + { + 'compute/numOfVMs/minimum': + dataMap['compute/numOfVMs/minimum'] + }, + customValidations + ); + }} + isValid={ + qgenericFieldInfo['compute/numOfVMs/maximum'].isValid + } + errorText={ + qgenericFieldInfo['compute/numOfVMs/maximum'].errorText + } + value={dataMap['compute/numOfVMs/maximum']} + /> + </GridItem> + </GridSection> + ); }; NumberOfVms.propTypes = { - minNumberOfVMsSelectedByUser: PropTypes.number + minNumberOfVMsSelectedByUser: PropTypes.number }; export default NumberOfVms; 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 index 41728eefb0..58c27c6bba 100644 --- 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 @@ -19,14 +19,14 @@ 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 - } + 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 index a3ba5fbc4a..06f9e8fd19 100644 --- 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 @@ -13,49 +13,78 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ComputeFlavorEditorView from './ComputeFlavorEditorView.jsx'; -import {COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js'; +import { COMPUTE_FLAVOR_FORM } from './ComputeFlavorConstants.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'; +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 = {}}} - }, - currentScreen: { - props: {isReadOnlyMode} - } + softwareProduct: { + softwareProductEditor, + softwareProductComponents: { computeFlavor: { computeEditor = {} } } + }, + currentScreen: { props: { isReadOnlyMode } } }) => { - const {data: currentSoftwareProduct = {}} = softwareProductEditor; - let {data , qdata, qgenericFieldInfo, dataMap, genericFieldInfo, formReady} = computeEditor; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + const { data: currentSoftwareProduct = {} } = softwareProductEditor; + 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 - }; + 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) - }; +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); +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 index e542ce1fd1..840f722bb2 100644 --- 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 @@ -23,75 +23,112 @@ import VmSizing from './VmSizing.jsx'; import i18n from 'nfvo-utils/i18n/i18n.js'; class ComputeEditorView extends React.Component { + static propTypes = { + data: PropTypes.object, + qdata: PropTypes.object, + qschema: PropTypes.object, + isReadOnlyMode: PropTypes.bool, + isManual: PropTypes.bool, + onDataChanged: PropTypes.func.isRequired, + onQDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - static propTypes = { - data: PropTypes.object, - qdata: PropTypes.object, - qschema: PropTypes.object, - isReadOnlyMode: PropTypes.bool, - isManual: PropTypes.bool, - onDataChanged: PropTypes.func.isRequired, - onQDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: 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); - 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 hasLostColSet> + <GridItem + colSpan={edittingComputeMode ? 2 : 4} + lastColInRow={!edittingComputeMode}> + <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} + lastColInRow> + <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> + ); + } - 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 hasLostColSet> - <GridItem colSpan={edittingComputeMode ? 2 : 4} lastColInRow={!edittingComputeMode}> - <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} lastColInRow> - <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')); - } + 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 index 6c02f36c90..b691084cc3 100644 --- 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 @@ -14,20 +14,26 @@ * permissions and limitations under the License. */ -import {actionTypes} from './ComputeFlavorConstants.js'; +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 + 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; + } +}; 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 index a476f85a19..00d76eff23 100644 --- 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 @@ -13,33 +13,32 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, COMPUTE_FLAVOR_FORM} from './ComputeFlavorConstants.js'; +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; - } + 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 index 54f22e0760..2f40706736 100644 --- 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 @@ -18,89 +18,146 @@ 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')} hasLastColSet> - <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 lastColInRow> - <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> - ); +const VmSizing = ({ qgenericFieldInfo, dataMap, onQDataChanged }) => { + return ( + <GridSection title={i18n('VM Sizing')} hasLastColSet> + <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 lastColInRow> + <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 index 9f59cd5b27..d831765674 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreation.js @@ -14,36 +14,50 @@ * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +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'; +import { forms } from '../SoftwareProductComponentsConstants.js'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductComponents: {componentEditor: {data, genericFieldInfo, formReady}}} = softwareProduct; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - return { - data, - genericFieldInfo, - formReady, - isFormValid - }; +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductComponents: { + componentEditor: { data, genericFieldInfo, formReady } + } + } = softwareProduct; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + return { + data, + genericFieldInfo, + formReady, + isFormValid + }; }; - -const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.CREATE_FORM}), - //onDataChanged: deltaData => SoftwareProductComponentsActionHelper.componentDataChanged(dispatch, {deltaData}), - onSubmit: (componentData) => { - return SoftwareProductComponentsActionHelper.createSoftwareProductComponent(dispatch, - {softwareProductId, componentData, version}); - }, - onCancel: () => SoftwareProductComponentsActionHelper.closeComponentCreationModal(dispatch), - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; - +const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: forms.CREATE_FORM + }), + //onDataChanged: deltaData => SoftwareProductComponentsActionHelper.componentDataChanged(dispatch, {deltaData}), + onSubmit: componentData => { + return SoftwareProductComponentsActionHelper.createSoftwareProductComponent( + dispatch, + { softwareProductId, componentData, version } + ); + }, + onCancel: () => + SoftwareProductComponentsActionHelper.closeComponentCreationModal( + dispatch + ), + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentCreationView); +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 index 42804ce5a6..0b33b4017f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/creation/SoftwareProductComponentCreationView.jsx @@ -21,59 +21,80 @@ 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'; +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 hasLastColSet> - <GridItem colSpan={4} lastColInRow> - <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} lastColInRow> - <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> - ); - } + 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 hasLastColSet> + <GridItem colSpan={4} lastColInRow> + <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} lastColInRow> + <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} = this.props; - onSubmit(data); - } + submit() { + const { onSubmit, data } = this.props; + onSubmit(data); + } } 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 8c06fd0ab8..f3f64e4b20 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 @@ -13,41 +13,79 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductComponentsGeneralView from './SoftwareProductComponentsGeneralView.jsx'; import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; -import {forms, COMPONENTS_QUESTIONNAIRE} from '../SoftwareProductComponentsConstants.js'; -import {onboardingMethod} from '../../SoftwareProductConstants.js'; +import { + forms, + COMPONENTS_QUESTIONNAIRE +} from '../SoftwareProductComponentsConstants.js'; +import { onboardingMethod } from '../../SoftwareProductConstants.js'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductEditor: {data: currentVSP}, softwareProductComponents} = softwareProduct; - let {componentEditor: {data: componentData = {} , qdata, qgenericFieldInfo : qGenericFieldInfo, dataMap, genericFieldInfo}} = softwareProductComponents; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { data: currentVSP }, + softwareProductComponents + } = softwareProduct; + let { + componentEditor: { + data: componentData = {}, + qdata, + qgenericFieldInfo: qGenericFieldInfo, + dataMap, + genericFieldInfo + } + } = softwareProductComponents; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - return { - componentData, - qdata, - isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL, - genericFieldInfo, - qGenericFieldInfo, - dataMap, - isFormValid - }; + return { + componentData, + qdata, + isManual: currentVSP.onboardingMethod === onboardingMethod.MANUAL, + genericFieldInfo, + qGenericFieldInfo, + dataMap, + isFormValid + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => { - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: forms.ALL_SPC_FORMS}), - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_QUESTIONNAIRE}), - onSubmit: ({componentData, qdata}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponent(dispatch, - {softwareProductId, version, vspComponentId: componentId, componentData, qdata}); - }, - onValidityChanged: isValidityData => SoftwareProductActionHelper.setIsValidityData(dispatch, {isValidityData}) - }; - +const mapActionsToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: forms.ALL_SPC_FORMS + }), + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: COMPONENTS_QUESTIONNAIRE + }), + onSubmit: ({ componentData, qdata }) => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponent( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + componentData, + qdata + } + ); + }, + onValidityChanged: isValidityData => + SoftwareProductActionHelper.setIsValidityData(dispatch, { + isValidityData + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsGeneralView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductComponentsGeneralView); 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 6aa51d1609..ad1fcaacff 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,9 +21,18 @@ 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, nfcFunction, description, isReadOnlyMode, genericFieldInfo, isManual}) => ( - <GridSection title={i18n('General')}> - {/* disabled until backend will be ready to implement it +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'> <div className='form-group'> <label className='control-label'>{i18n('Name')}</label> @@ -32,156 +41,248 @@ const GeneralSection = ({onDataChanged, displayName, vfcCode, nfcFunction, descr </div> */} - <GridItem> - <Input - data-test-id='name' - label={i18n('Name')} - value={displayName} - disabled={!isManual || isReadOnlyMode} - type='text'/> - {!isManual && <Input - data-test-id='vfcCode' - label={i18n('Naming Code')} - value={vfcCode} - isValid={genericFieldInfo.vfcCode.isValid} - 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}> - <Input - label={i18n('Description')} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - onChange={description => onDataChanged({description})} - disabled={isReadOnlyMode} - value={description} - groupClassName='multi-line-textarea' - data-test-id='description' - type='textarea'/> - </GridItem> - <GridItem /> - </GridSection> + <GridItem> + <Input + data-test-id="name" + label={i18n('Name')} + value={displayName} + disabled={!isManual || isReadOnlyMode} + type="text" + /> + {!isManual && ( + <Input + data-test-id="vfcCode" + label={i18n('Naming Code')} + value={vfcCode} + isValid={genericFieldInfo.vfcCode.isValid} + 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}> + <Input + label={i18n('Description')} + isValid={genericFieldInfo.description.isValid} + errorText={genericFieldInfo.description.errorText} + onChange={description => onDataChanged({ description })} + disabled={isReadOnlyMode} + value={description} + groupClassName="multi-line-textarea" + data-test-id="description" + type="textarea" + /> + </GridItem> + <GridItem /> + </GridSection> ); -const HypervisorSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Hypervisor')}> - <GridItem> - <Input - data-test-id='hypervisor' - label={i18n('Supported Hypervisors')} - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - isValid={qgenericFieldInfo['general/hypervisor/hypervisor'].isValid} - errorText={qgenericFieldInfo['general/hypervisor/hypervisor'].errorText} - value={dataMap['general/hypervisor/hypervisor']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'general/hypervisor/hypervisor' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['general/hypervisor/hypervisor'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)} - </Input> - </GridItem> - <GridItem colSpan={2}> - <Input - data-test-id='drivers' - onChange={(driver) => onQDataChanged({'general/hypervisor/drivers' : driver})} - label={i18n('Hypervisor Drivers')} - type='text' - isValid={qgenericFieldInfo['general/hypervisor/drivers'].isValid} - errorText={qgenericFieldInfo['general/hypervisor/drivers'].errorText} - value={dataMap['general/hypervisor/drivers']}/> - </GridItem> - <GridItem colSpan={3}> - <Input - data-test-id='containerFeaturesDescription' - label={i18n('Describe Container Features')} - type='textarea' - onChange={(containerFeaturesDescription) => onQDataChanged({'general/hypervisor/containerFeaturesDescription' : containerFeaturesDescription})} - isValid={qgenericFieldInfo['general/hypervisor/containerFeaturesDescription'].isValid} - errorText={qgenericFieldInfo['general/hypervisor/containerFeaturesDescription'].errorText} - value={dataMap['general/hypervisor/containerFeaturesDescription']}/> - </GridItem> - </GridSection> +const HypervisorSection = ({ dataMap, onQDataChanged, qgenericFieldInfo }) => ( + <GridSection title={i18n('Hypervisor')}> + <GridItem> + <Input + data-test-id="hypervisor" + label={i18n('Supported Hypervisors')} + type="select" + className="input-options-select" + groupClassName="bootstrap-input-options" + isValid={ + qgenericFieldInfo['general/hypervisor/hypervisor'].isValid + } + errorText={ + qgenericFieldInfo['general/hypervisor/hypervisor'].errorText + } + value={dataMap['general/hypervisor/hypervisor']} + onChange={e => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({ 'general/hypervisor/hypervisor': val }); + }}> + <option key="placeholder" value=""> + {i18n('Select...')} + </option> + {qgenericFieldInfo['general/hypervisor/hypervisor'].enum.map( + hv => ( + <option value={hv.enum} key={hv.enum}> + {hv.title} + </option> + ) + )} + </Input> + </GridItem> + <GridItem colSpan={2}> + <Input + data-test-id="drivers" + onChange={driver => + onQDataChanged({ 'general/hypervisor/drivers': driver }) + } + label={i18n('Hypervisor Drivers')} + type="text" + isValid={ + qgenericFieldInfo['general/hypervisor/drivers'].isValid + } + errorText={ + qgenericFieldInfo['general/hypervisor/drivers'].errorText + } + value={dataMap['general/hypervisor/drivers']} + /> + </GridItem> + <GridItem colSpan={3}> + <Input + data-test-id="containerFeaturesDescription" + label={i18n('Describe Container Features')} + type="textarea" + onChange={containerFeaturesDescription => + onQDataChanged({ + 'general/hypervisor/containerFeaturesDescription': containerFeaturesDescription + }) + } + isValid={ + qgenericFieldInfo[ + 'general/hypervisor/containerFeaturesDescription' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'general/hypervisor/containerFeaturesDescription' + ].errorText + } + value={ + dataMap['general/hypervisor/containerFeaturesDescription'] + } + /> + </GridItem> + </GridSection> ); -const ImageSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Disk')}> - <GridItem> - <Input - data-test-id='bootDiskSizePerVM' - onChange={(bootDiskSizePerVM) => onQDataChanged({'general/disk/bootDiskSizePerVM' : bootDiskSizePerVM})} - label={i18n('Size of boot disk per VM (GB)')} - type='number' - 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/disk/ephemeralDiskSizePerVM' : ephemeralDiskSizePerVM})} - label={i18n('Size of ephemeral disk per VM (GB)')} - type='number' - isValid={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].isValid} - errorText={qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'].errorText} - value={dataMap['general/disk/ephemeralDiskSizePerVM']}/> - </GridItem> - </GridSection> +const ImageSection = ({ dataMap, onQDataChanged, qgenericFieldInfo }) => ( + <GridSection title={i18n('Disk')}> + <GridItem> + <Input + data-test-id="bootDiskSizePerVM" + onChange={bootDiskSizePerVM => + onQDataChanged({ + 'general/disk/bootDiskSizePerVM': bootDiskSizePerVM + }) + } + label={i18n('Size of boot disk per VM (GB)')} + type="number" + 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/disk/ephemeralDiskSizePerVM': ephemeralDiskSizePerVM + }) + } + label={i18n('Size of ephemeral disk per VM (GB)')} + type="number" + isValid={ + qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'] + .isValid + } + errorText={ + qgenericFieldInfo['general/disk/ephemeralDiskSizePerVM'] + .errorText + } + value={dataMap['general/disk/ephemeralDiskSizePerVM']} + /> + </GridItem> + </GridSection> ); -const RecoverySection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Recovery')}> - <GridItem> - <Input - data-test-id='pointObjective' - label={i18n('VM Recovery Point Objective (Minutes)')} - type='number' - onChange={(pointObjective) => onQDataChanged({'general/recovery/pointObjective' : pointObjective})} - isValid={qgenericFieldInfo['general/recovery/pointObjective'].isValid} - errorText={qgenericFieldInfo['general/recovery/pointObjective'].errorText} - value={dataMap['general/recovery/pointObjective']}/> - </GridItem> - <GridItem> - <Input - data-test-id='timeObjective' - label={i18n('VM Recovery Time Objective (Minutes)')} - type='number' - onChange={(timeObjective) => onQDataChanged({'general/recovery/timeObjective' : timeObjective})} - isValid={qgenericFieldInfo['general/recovery/timeObjective'].isValid} - errorText={qgenericFieldInfo['general/recovery/timeObjective'].errorText} - value={dataMap['general/recovery/timeObjective']}/> - <div className='empty-two-col' /> - </GridItem> - <GridItem colSpan={2} /> - <GridItem colSpan={2}> - <Input - data-test-id='vmProcessFailuresHandling' - className='textarea' - label={i18n('How are in VM process failures handled?')} - type='textarea' - onChange={(vmProcessFailuresHandling) => onQDataChanged({'general/recovery/vmProcessFailuresHandling' : vmProcessFailuresHandling})} - isValid={qgenericFieldInfo['general/recovery/vmProcessFailuresHandling'].isValid} - errorText={qgenericFieldInfo['general/recovery/vmProcessFailuresHandling'].errorText} - value={dataMap['general/recovery/vmProcessFailuresHandling']}/> - <div className='empty-two-col' /> - - </GridItem> - { - /** disabled until backend will be ready to implement it +const RecoverySection = ({ dataMap, onQDataChanged, qgenericFieldInfo }) => ( + <GridSection title={i18n('Recovery')}> + <GridItem> + <Input + data-test-id="pointObjective" + label={i18n('VM Recovery Point Objective (Minutes)')} + type="number" + onChange={pointObjective => + onQDataChanged({ + 'general/recovery/pointObjective': pointObjective + }) + } + isValid={ + qgenericFieldInfo['general/recovery/pointObjective'].isValid + } + errorText={ + qgenericFieldInfo['general/recovery/pointObjective'] + .errorText + } + value={dataMap['general/recovery/pointObjective']} + /> + </GridItem> + <GridItem> + <Input + data-test-id="timeObjective" + label={i18n('VM Recovery Time Objective (Minutes)')} + type="number" + onChange={timeObjective => + onQDataChanged({ + 'general/recovery/timeObjective': timeObjective + }) + } + isValid={ + qgenericFieldInfo['general/recovery/timeObjective'].isValid + } + errorText={ + qgenericFieldInfo['general/recovery/timeObjective'] + .errorText + } + value={dataMap['general/recovery/timeObjective']} + /> + <div className="empty-two-col" /> + </GridItem> + <GridItem colSpan={2} /> + <GridItem colSpan={2}> + <Input + data-test-id="vmProcessFailuresHandling" + className="textarea" + label={i18n('How are in VM process failures handled?')} + type="textarea" + onChange={vmProcessFailuresHandling => + onQDataChanged({ + 'general/recovery/vmProcessFailuresHandling': vmProcessFailuresHandling + }) + } + isValid={ + qgenericFieldInfo[ + 'general/recovery/vmProcessFailuresHandling' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'general/recovery/vmProcessFailuresHandling' + ].errorText + } + value={dataMap['general/recovery/vmProcessFailuresHandling']} + /> + <div className="empty-two-col" /> + </GridItem> + {/** disabled until backend will be ready to implement it <div className='row'> <div className='col-md-3'> <Input @@ -190,78 +291,127 @@ const RecoverySection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( pointer='/general/recovery/VMRecoveryDocument'/> </div> </div> - */ - } - </GridSection> + */} + </GridSection> ); -const DNSConfigurationSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('DNS Configuration')}> - <GridItem colSpan={2}> - <Input - data-test-id='dnsConfiguration' - label={i18n('Do you have a need for DNS as a Service? Please describe.')} - type='textarea' - onChange={(dnsConfiguration) => onQDataChanged({'general/dnsConfiguration' : dnsConfiguration})} - isValid={qgenericFieldInfo['general/dnsConfiguration'].isValid} - errorText={qgenericFieldInfo['general/dnsConfiguration'].errorText} - value={dataMap['general/dnsConfiguration']}/> - </GridItem> - </GridSection> +const DNSConfigurationSection = ({ + dataMap, + onQDataChanged, + qgenericFieldInfo +}) => ( + <GridSection title={i18n('DNS Configuration')}> + <GridItem colSpan={2}> + <Input + data-test-id="dnsConfiguration" + label={i18n( + 'Do you have a need for DNS as a Service? Please describe.' + )} + type="textarea" + onChange={dnsConfiguration => + onQDataChanged({ + 'general/dnsConfiguration': dnsConfiguration + }) + } + isValid={qgenericFieldInfo['general/dnsConfiguration'].isValid} + errorText={ + qgenericFieldInfo['general/dnsConfiguration'].errorText + } + value={dataMap['general/dnsConfiguration']} + /> + </GridItem> + </GridSection> ); -const CloneSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Clone')}> - <GridItem colSpan={2}> - <Input - data-test-id='vmCloneUsage' - label={i18n('Describe VM Clone Use')} - type='textarea' - onChange={(vmCloneUsage) => onQDataChanged({'general/vmCloneUsage' : vmCloneUsage})} - isValid={qgenericFieldInfo['general/vmCloneUsage'].isValid} - errorText={qgenericFieldInfo['general/vmCloneUsage'].errorText} - value={dataMap['general/vmCloneUsage']}/> - </GridItem> - </GridSection> +const CloneSection = ({ dataMap, onQDataChanged, qgenericFieldInfo }) => ( + <GridSection title={i18n('Clone')}> + <GridItem colSpan={2}> + <Input + data-test-id="vmCloneUsage" + label={i18n('Describe VM Clone Use')} + type="textarea" + onChange={vmCloneUsage => + onQDataChanged({ 'general/vmCloneUsage': vmCloneUsage }) + } + isValid={qgenericFieldInfo['general/vmCloneUsage'].isValid} + errorText={qgenericFieldInfo['general/vmCloneUsage'].errorText} + value={dataMap['general/vmCloneUsage']} + /> + </GridItem> + </GridSection> ); class SoftwareProductComponentsGeneralView extends React.Component { + render() { + 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"> + {genericFieldInfo && + qGenericFieldInfo && ( + <Form + isValid={this.props.isFormValid} + formReady={null} + isReadOnlyMode={isReadOnlyMode} + onValidityChanged={isValidityData => + this.props.onValidityChanged(isValidityData) + } + hasButtons={false}> + <GeneralSection + onDataChanged={onDataChanged} + displayName={displayName} + vfcCode={vfcCode} + nfcFunction={nfcFunction} + description={description} + isManual={isManual} + isReadOnlyMode={isReadOnlyMode} + genericFieldInfo={genericFieldInfo} + /> + <HypervisorSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <ImageSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <RecoverySection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <DNSConfigurationSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <CloneSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + </Form> + )} + </div> + </div> + ); + } - render() { - 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'> - {genericFieldInfo && qGenericFieldInfo && <Form - isValid={this.props.isFormValid} - formReady={null} - isReadOnlyMode={isReadOnlyMode} - onValidityChanged={(isValidityData) => this.props.onValidityChanged(isValidityData)} - hasButtons={false}> - <GeneralSection - onDataChanged={onDataChanged} - displayName={displayName} - vfcCode={vfcCode} - nfcFunction={nfcFunction} - description={description} - isManual={isManual} - isReadOnlyMode={isReadOnlyMode} - genericFieldInfo={genericFieldInfo}/> - <HypervisorSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <ImageSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <RecoverySection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <DNSConfigurationSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <CloneSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - </Form> } - </div> - </div> - ); - } - - save() { - let {onSubmit, componentData, qdata} = this.props; - return onSubmit({componentData, qdata}); - } + save() { + let { onSubmit, componentData, qdata } = this.props; + return onSubmit({ componentData, qdata }); + } } export default SoftwareProductComponentsGeneralView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/ImageValidations.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/ImageValidations.js index 2483d0aaa2..900a9a1c46 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/ImageValidations.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/ImageValidations.js @@ -1,6 +1,6 @@ - import Validator from 'nfvo-utils/Validator.js'; -export const imageCustomValidations = { - 'version': value => Validator.validate('version', value, [{type: 'required', data: true}]) +export const imageCustomValidations = { + version: value => + Validator.validate('version', value, [{ type: 'required', data: true }]) }; 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 index 8d70d6f14c..3f661b76fe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageActionHelper.js @@ -17,157 +17,268 @@ 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'; +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`; + 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 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 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 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 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 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 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); +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}) { - 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, - image, - data - }); - }); - }); - }, - - openImageEditor(dispatch, {image = {}, data = {}, softwareProductId, componentId, version, isReadOnlyMode}) { - - let {id} = image; - let title = id ? i18n('Edit Image') : i18n('Create New Image'); - let className = id ? 'image-modal-edit' : 'image-modal-new'; - - dispatch({ - type: actionTypes.ImageEditor.OPEN, - image: {...data, id} - }); - - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR, - title: title, - modalClassName: className, - modalComponentProps: {softwareProductId, componentId, version, isReadOnlyMode} - } - }); - - }, - - 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}); - }); - } - } + 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 } + ) { + 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, + image, + data + } + ); + }); + }); + }, + + openImageEditor( + dispatch, + { + image = {}, + data = {}, + softwareProductId, + componentId, + version, + isReadOnlyMode + } + ) { + let { id } = image; + let title = id ? i18n('Edit Image') : i18n('Create New Image'); + let className = id ? 'image-modal-edit' : 'image-modal-new'; + + dispatch({ + type: actionTypes.ImageEditor.OPEN, + image: { ...data, id } + }); + + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: + modalContentMapper.SOFTWARE_PRODUCT_COMPONENT_IMAGE_EDITOR, + title: title, + modalClassName: className, + modalComponentProps: { + softwareProductId, + componentId, + version, + isReadOnlyMode + } + } + }); + }, + + 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/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js index 6b6c9a30e5..300b2898e1 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageConstants.js @@ -16,12 +16,12 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - IMAGES_LIST_UPDATE: null, + IMAGES_LIST_UPDATE: null, - ImageEditor: { - CLOSE: null, - OPEN: null - } + ImageEditor: { + CLOSE: null, + OPEN: null + } }); 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 index c5f23e7681..0243a38f1b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditor.js @@ -13,56 +13,93 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +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 {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; -import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; -import {IMAGE_QUESTIONNAIRE} from './SoftwareProductComponentsImageConstants.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, - currentScreen: {props: {isReadOnlyMode}} + softwareProduct, + currentScreen: { props: { isReadOnlyMode } } }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {}, + isValidityData = true + }, + softwareProductComponents + } = softwareProduct; - let {softwareProductEditor: {data:currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; - - let {images: {imageEditor = {}}} = softwareProductComponents; - let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = imageEditor; - 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 - }; + let { images: { imageEditor = {} } } = softwareProductComponents; + let { + data, + qdata, + genericFieldInfo, + qgenericFieldInfo, + dataMap, + formReady + } = imageEditor; + 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: customValidations => { - ValidationHelper.validateForm(dispatch, forms.IMAGE_EDIT_FORM); - ValidationHelper.qValidateForm(dispatch, IMAGE_QUESTIONNAIRE, customValidations); - }, - onQDataChanged: (deltaData, customValidations) => ValidationHelper.qDataChanged(dispatch, {deltaData, - qName: IMAGE_QUESTIONNAIRE, customValidations}), - }; +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: customValidations => { + ValidationHelper.validateForm(dispatch, forms.IMAGE_EDIT_FORM); + ValidationHelper.qValidateForm( + dispatch, + IMAGE_QUESTIONNAIRE, + customValidations + ); + }, + onQDataChanged: (deltaData, customValidations) => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: IMAGE_QUESTIONNAIRE, + customValidations + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentsImageEditorView); +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 index 7c357429e5..3846d45772 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorReducer.js @@ -13,30 +13,29 @@ * 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'; +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}] - } - }, - formName: forms.IMAGE_EDIT_FORM - }; - default: - return state; - } + 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 }] + } + }, + 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 index a5ef152e01..3670ab910d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageEditorView.jsx @@ -21,53 +21,81 @@ import Form from 'nfvo-components/input/validation/Form.jsx'; import FileDetails from './imagesEditorComponents/FileDetails.jsx'; import ImageDetails from './imagesEditorComponents/ImageDetails.jsx'; -import {imageCustomValidations} from './ImageValidations.js'; +import { imageCustomValidations } from './ImageValidations.js'; class SoftwareProductComponentsImageEditorView extends React.Component { - static propTypes = { - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; + static propTypes = { + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: 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(imageCustomValidations) } - 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}); - } + 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(imageCustomValidations) + } + 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 index d071647058..f3c39c3048 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageList.js @@ -13,73 +13,122 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.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 { 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'; +import { onboardingMethod as onboardingMethodTypes } from '../../SoftwareProductConstants.js'; -export const mapStateToProps = ({softwareProduct}) => { +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {}, + isValidityData = true + }, + softwareProductComponents + } = softwareProduct; + let { + images: { imagesList = [] }, + componentEditor: { + data: componentData, + qdata, + dataMap, + qgenericFieldInfo + } + } = softwareProductComponents; + let { onboardingMethod } = currentSoftwareProduct; + let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; - let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; - let {images: {imagesList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; - let {onboardingMethod} = currentSoftwareProduct; - let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; - - return { - componentData, - qdata, - dataMap, - qgenericFieldInfo, - isValidityData, - imagesList, - isManual : isManual - }; + return { + componentData, + qdata, + dataMap, + qgenericFieldInfo, + isValidityData, + imagesList, + isManual: isManual + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { - return { - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, - qName: COMPONENTS_QUESTIONNAIRE}), - onAddImage: (isReadOnlyMode) => { - SoftwareProductComponentsImagesActionHelper.openImageEditor(dispatch, - {isReadOnlyMode, softwareProductId, - componentId, version} - );}, - onDeleteImage: (image) => { - 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}"?', {shortenedFileName: shortenedFileName}), - onConfirmed: () => ImageHelper.deleteImage(dispatch, { - softwareProductId, - componentId, - version, - imageId: image.id - }) - } - }); - }, - onEditImageClick: (image, isReadOnlyMode) => { - SoftwareProductComponentsImagesActionHelper.openEditImageEditor(dispatch, { - image, isReadOnlyMode, softwareProductId, componentId, version, modalClassName: 'image-modal-edit'} - ); - }, - onSubmit: (qdata) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, - {softwareProductId, - vspComponentId: componentId, - version, - qdata}); - } - }; +const mapActionsToProps = ( + dispatch, + { softwareProductId, componentId, version } +) => { + return { + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: COMPONENTS_QUESTIONNAIRE + }), + onAddImage: isReadOnlyMode => { + SoftwareProductComponentsImagesActionHelper.openImageEditor( + dispatch, + { + isReadOnlyMode, + softwareProductId, + componentId, + version + } + ); + }, + onDeleteImage: image => { + 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}"?', + { + shortenedFileName: shortenedFileName + } + ), + onConfirmed: () => + ImageHelper.deleteImage(dispatch, { + softwareProductId, + componentId, + version, + imageId: image.id + }) + } + }); + }, + onEditImageClick: (image, isReadOnlyMode) => { + SoftwareProductComponentsImagesActionHelper.openEditImageEditor( + dispatch, + { + image, + isReadOnlyMode, + softwareProductId, + componentId, + version, + modalClassName: 'image-modal-edit' + } + ); + }, + onSubmit: qdata => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { + softwareProductId, + vspComponentId: componentId, + version, + qdata + } + ); + } + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsImageListView); +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 index 5dd2fb623b..a7c1bfafbe 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListReducer.js @@ -13,14 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentsImageConstants.js'; +import { actionTypes } from './SoftwareProductComponentsImageConstants.js'; export default (state = [], action) => { - switch (action.type) { - - case actionTypes.IMAGES_LIST_UPDATE: - return [...action.response]; - default: - return state; - } + 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 index 004cbebe5d..cb67856caa 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/images/SoftwareProductComponentsImageListView.jsx @@ -20,113 +20,152 @@ 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'; +import Input from 'nfvo-components/input/validation/Input.jsx'; class SoftwareProductComponentsImageListView extends React.Component { - state = { - localFilter: '' - }; + 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()} + 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} = 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(isReadOnlyMode) : null} - plusButtonTitle={i18n('Add Image')} - twoColumns> - {this.filterList().map(image => this.renderImagesListItem(image, isReadOnlyMode))} - </ListEditorView> - ); - }; + ); + } + renderImagesList() { + const { localFilter } = this.state; + let { isReadOnlyMode, onAddImage, isManual } = this.props; - renderImagesListItem(image, isReadOnlyMode) { - let {id, fileName} = image; - let {onEditImageClick, isManual, onDeleteImage} = this.props; - return ( - <ListEditorItemView - key={id} - isReadOnlyMode={isReadOnlyMode} - onSelect={() => onEditImageClick(image, isReadOnlyMode)} - onDelete={isManual ? () => onDeleteImage(image) : null}> + return ( + <ListEditorView + title={i18n('Images')} + filterValue={localFilter} + placeholder={i18n('Filter Images by Name')} + isReadOnlyMode={isReadOnlyMode} + onFilter={value => this.setState({ localFilter: value })} + onAdd={isManual ? () => onAddImage(isReadOnlyMode) : null} + plusButtonTitle={i18n('Add Image')} + twoColumns> + {this.filterList().map(image => + this.renderImagesListItem(image, isReadOnlyMode) + )} + </ListEditorView> + ); + } - <ListEditorItemViewField> - <div className='image-filename-cell'><span className='image-filename'>{fileName}</span></div> - </ListEditorItemViewField> - </ListEditorItemView> - ); - } + renderImagesListItem(image, isReadOnlyMode) { + let { id, fileName } = image; + let { onEditImageClick, isManual, onDeleteImage } = this.props; + return ( + <ListEditorItemView + key={id} + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditImageClick(image, isReadOnlyMode)} + onDelete={isManual ? () => onDeleteImage(image) : 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; - } - } + 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); - } + save() { + let { onSubmit, qdata } = this.props; + return onSubmit(qdata); + } } export default SoftwareProductComponentsImageListView; 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 index 64367c00f2..ec173cd988 100644 --- 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 @@ -18,32 +18,64 @@ 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 { 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 hasLastColSset> - <GridItem colSpan={fileNameCols} lastColInRow={!editingMode}> - <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 && <div className='note-text'>{i18n('After image creation you must go to Edit Image and add File Version')}</div>} - {editingMode && <Version isManual={isManual} dataMap={dataMap} qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged}/>} - {editingMode && <Format isManual={isManual} qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged}/>} - </GridSection> - ); +const FileDetails = ({ + editingMode, + fileName, + onDataChanged, + isManual, + dataMap, + onQDataChanged, + genericFieldInfo, + qgenericFieldInfo +}) => { + let fileNameCols = editingMode ? 3 : 4; + return ( + <GridSection hasLastColSset> + <GridItem colSpan={fileNameCols} lastColInRow={!editingMode}> + <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 && ( + <div className="note-text"> + {i18n( + 'After image creation you must go to Edit Image and add File Version' + )} + </div> + )} + {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 index 1f71c6b277..0ee8fb76d0 100644 --- 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 @@ -18,30 +18,34 @@ 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> - ); +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 index 24e54bbbcb..ccf94bc860 100644 --- 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 @@ -19,21 +19,22 @@ 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> - ); +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 index bd55c5ba91..60454c52e7 100644 --- 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 @@ -17,25 +17,29 @@ 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'; -import {imageCustomValidations} from '../ImageValidations.js'; +import { imageCustomValidations } from '../ImageValidations.js'; - -const Version = ({isManual, dataMap, qgenericFieldInfo, onQDataChanged}) => { - return( - <GridItem colSpan={1} lastColInRow> - <Input - disabled={!isManual} - data-test-id='image-version' - type='text' - className='image-version' - label={i18n('Version')} - isRequired={true} - onChange={(version) => onQDataChanged({'version' : version}, {'version' : imageCustomValidations['version']})} - isValid={qgenericFieldInfo['version'].isValid} - errorText={qgenericFieldInfo['version'].errorText} - value={dataMap['version']}/> - </GridItem> - ); +const Version = ({ isManual, dataMap, qgenericFieldInfo, onQDataChanged }) => { + return ( + <GridItem colSpan={1} lastColInRow> + <Input + disabled={!isManual} + data-test-id="image-version" + type="text" + className="image-version" + label={i18n('Version')} + isRequired={true} + onChange={version => + onQDataChanged( + { version: version }, + { version: imageCustomValidations['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/SoftwareProductComponentLoadBalancing.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancing.js index 350e80c0f8..da8b73fbe0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancing.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/loadBalancing/SoftwareProductComponentLoadBalancing.js @@ -13,29 +13,50 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductComponentLoadBalancingView from './SoftwareProductComponentLoadBalancingRefView.jsx'; import SoftwareProductComponentsActionHelper from '../SoftwareProductComponentsActionHelper.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import { COMPONENTS_QUESTIONNAIRE } from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; -export const mapStateToProps = ({softwareProduct: {softwareProductComponents}}) => { - - let {componentEditor: {qdata, qgenericFieldInfo: genericFieldInfo, dataMap}} = softwareProductComponents; - - return { - qdata, - genericFieldInfo, - dataMap - }; +export const mapStateToProps = ({ + softwareProduct: { softwareProductComponents } +}) => { + let { + componentEditor: { qdata, qgenericFieldInfo: genericFieldInfo, dataMap } + } = softwareProductComponents; + return { + qdata, + genericFieldInfo, + dataMap + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => { - return { - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_QUESTIONNAIRE}), - onSubmit: ({qdata}) =>{ return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId: componentId, qdata});} - }; +const mapActionsToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: COMPONENTS_QUESTIONNAIRE + }), + onSubmit: ({ qdata }) => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + qdata + } + ); + } + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentLoadBalancingView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductComponentLoadBalancingView); 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 1cbb9afc5d..4c90fc0be2 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 @@ -19,7 +19,7 @@ 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'; -import Input from'nfvo-components/input/validation/Input.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'; @@ -27,145 +27,244 @@ import GridItem from 'nfvo-components/grid/GridItem.jsx'; const prefix = 'highAvailabilityAndLoadBalancing/'; const pointers = [ - { - key: 'failureLoadDistribution', - description: 'How is load distributed across live vms in the event of a vm/host failure? please describe' - }, - { - key: 'nkModelImplementation', - description: 'Does each VM implement the N+K model for redundancy and failure protection? Please describe.' - }, - { - key: 'architectureChoice', - description: 'What architecture is being implemented: ACTIVE-ACTIVE and/or ACTIVE-PASSIVE. ', - added: 'Will the arrangement be 1-1 or N-M? Please describe.' - }, - {key: 'slaRequirements', description: 'Specify application SLA requirements on Cloud platform.'}, - { - key: 'horizontalScaling', - description: 'Is horizontal scaling the preferred solution for HA and resiliency? Please describe.' - }, - { - key: 'loadDistributionMechanism', - description: 'Can load be distributed across VMs? If so, are special mechanisms needed to re-balance data across VMs?', - added: 'Please describe.' - } + { + key: 'failureLoadDistribution', + description: + 'How is load distributed across live vms in the event of a vm/host failure? please describe' + }, + { + key: 'nkModelImplementation', + description: + 'Does each VM implement the N+K model for redundancy and failure protection? Please describe.' + }, + { + key: 'architectureChoice', + description: + 'What architecture is being implemented: ACTIVE-ACTIVE and/or ACTIVE-PASSIVE. ', + added: 'Will the arrangement be 1-1 or N-M? Please describe.' + }, + { + key: 'slaRequirements', + description: 'Specify application SLA requirements on Cloud platform.' + }, + { + key: 'horizontalScaling', + description: + 'Is horizontal scaling the preferred solution for HA and resiliency? Please describe.' + }, + { + key: 'loadDistributionMechanism', + description: + 'Can load be distributed across VMs? If so, are special mechanisms needed to re-balance data across VMs?', + added: 'Please describe.' + } ]; //TODO check for buttons -const TextAreaItem = ({item, toggle, expanded, genericFieldInfo, dataMap, onQDataChanged}) => ( - <GridItem colSpan={3} key={item.key} > - <div className={expanded ? 'title' : 'title add-padding'} - data-test-id={`btn-${item.key}`} - onClick={() => toggle(item.key)}> - <SVGIcon name={expanded ? 'chevronUp' : 'chevronDown'}/> - <span className='title-text'>{i18n(item.description)}</span> - {item.added && <div className='new-line'>{i18n(item.added)}</div>} - </div> - <div className={expanded ? 'collapse in' : 'collapse'}> - <div> - <div> - <Input - data-test-id={`input-${item.key}`} - type='textarea' - isValid={genericFieldInfo[`${prefix}${item.key}`].isValid} - errorText={genericFieldInfo[`${prefix}${item.key}`].errorText} - value={dataMap[`${prefix}${item.key}`]} - onChange={(val) => onQDataChanged({[`${prefix}${item.key}`] : val})} /> - </div> - </div> - </div> - </GridItem> +const TextAreaItem = ({ + item, + toggle, + expanded, + genericFieldInfo, + dataMap, + onQDataChanged +}) => ( + <GridItem colSpan={3} key={item.key}> + <div + className={expanded ? 'title' : 'title add-padding'} + data-test-id={`btn-${item.key}`} + onClick={() => toggle(item.key)}> + <SVGIcon name={expanded ? 'chevronUp' : 'chevronDown'} /> + <span className="title-text">{i18n(item.description)}</span> + {item.added && <div className="new-line">{i18n(item.added)}</div>} + </div> + <div className={expanded ? 'collapse in' : 'collapse'}> + <div> + <div> + <Input + data-test-id={`input-${item.key}`} + type="textarea" + isValid={ + genericFieldInfo[`${prefix}${item.key}`].isValid + } + errorText={ + genericFieldInfo[`${prefix}${item.key}`].errorText + } + value={dataMap[`${prefix}${item.key}`]} + onChange={val => + onQDataChanged({ [`${prefix}${item.key}`]: val }) + } + /> + </div> + </div> + </div> + </GridItem> ); class SoftwareProductComponentLoadBalancingView extends React.Component { - static propTypes = { - componentId: PropTypes.string.isRequired, - softwareProductId: PropTypes.string.isRequired, - qdata: PropTypes.object, - qschema: PropTypes.object, - currentSoftwareProduct: PropTypes.object - }; + static propTypes = { + componentId: PropTypes.string.isRequired, + softwareProductId: PropTypes.string.isRequired, + qdata: PropTypes.object, + qschema: PropTypes.object, + currentSoftwareProduct: PropTypes.object + }; - state = { - expanded: {} - }; + state = { + expanded: {} + }; - render() { - let {dataMap, genericFieldInfo, onQDataChanged, isReadOnlyMode} = this.props; - return ( - <div className='vsp-components-load-balancing'> - <div className='halb-data'> - { genericFieldInfo && <Form - formReady={null} - isValid={true} - onSubmit={() => this.save()} - isReadOnlyMode={isReadOnlyMode} - hasButtons={false}> - <GridSection title={i18n('High Availability & Load Balancing')}> - <GridItem colSpan={1}> - <Input - data-test-id='input-is-component-mandatory' - label={i18n('Is Component Mandatory')} - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - isValid={genericFieldInfo[`${prefix}isComponentMandatory`].isValid} - errorText={genericFieldInfo[`${prefix}isComponentMandatory`].errorText} - value={dataMap[`${prefix}isComponentMandatory`]} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({[`${prefix}isComponentMandatory`] : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - { genericFieldInfo[`${prefix}isComponentMandatory`].enum.map(isMan => <option value={isMan.enum} key={isMan.enum}>{isMan.title}</option>) } - </Input> - </GridItem> - <GridItem colSpan={3}/> - <GridItem colSpan={1}> - <Input - data-test-id='input-high-availability-mode' - label={i18n('High Availability Mode')} - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - isValid={genericFieldInfo[`${prefix}highAvailabilityMode`].isValid} - errorText={genericFieldInfo[`${prefix}highAvailabilityMode`].errorText} - value={dataMap[`${prefix}highAvailabilityMode`]} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({[`${prefix}highAvailabilityMode`] : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {genericFieldInfo[`${prefix}highAvailabilityMode`].enum.map(hmode => <option value={hmode.enum} key={hmode.enum}>{hmode.title}</option>)} - </Input> - </GridItem> - <GridItem colSpan={3}/> - </GridSection> - <GridSection> - {pointers.map(pointer => <TextAreaItem onQDataChanged={onQDataChanged} - genericFieldInfo={genericFieldInfo} dataMap={dataMap} item={pointer} key={pointer.key + 'pKey'} - expanded={this.state.expanded[pointer.key]} toggle={(name)=>{this.toggle(name);}} />)} - </GridSection> - </Form> } - </div> - </div> - ); - } + render() { + let { + dataMap, + genericFieldInfo, + onQDataChanged, + isReadOnlyMode + } = this.props; + return ( + <div className="vsp-components-load-balancing"> + <div className="halb-data"> + {genericFieldInfo && ( + <Form + formReady={null} + isValid={true} + onSubmit={() => this.save()} + isReadOnlyMode={isReadOnlyMode} + hasButtons={false}> + <GridSection + title={i18n( + 'High Availability & Load Balancing' + )}> + <GridItem colSpan={1}> + <Input + data-test-id="input-is-component-mandatory" + label={i18n('Is Component Mandatory')} + type="select" + className="input-options-select" + groupClassName="bootstrap-input-options" + isValid={ + genericFieldInfo[ + `${prefix}isComponentMandatory` + ].isValid + } + errorText={ + genericFieldInfo[ + `${prefix}isComponentMandatory` + ].errorText + } + value={ + dataMap[ + `${prefix}isComponentMandatory` + ] + } + onChange={e => { + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[selectedIndex] + .value; + onQDataChanged({ + [`${prefix}isComponentMandatory`]: val + }); + }}> + <option key="placeholder" value=""> + {i18n('Select...')} + </option> + {genericFieldInfo[ + `${prefix}isComponentMandatory` + ].enum.map(isMan => ( + <option + value={isMan.enum} + key={isMan.enum}> + {isMan.title} + </option> + ))} + </Input> + </GridItem> + <GridItem colSpan={3} /> + <GridItem colSpan={1}> + <Input + data-test-id="input-high-availability-mode" + label={i18n('High Availability Mode')} + type="select" + className="input-options-select" + groupClassName="bootstrap-input-options" + isValid={ + genericFieldInfo[ + `${prefix}highAvailabilityMode` + ].isValid + } + errorText={ + genericFieldInfo[ + `${prefix}highAvailabilityMode` + ].errorText + } + value={ + dataMap[ + `${prefix}highAvailabilityMode` + ] + } + onChange={e => { + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[selectedIndex] + .value; + onQDataChanged({ + [`${prefix}highAvailabilityMode`]: val + }); + }}> + <option key="placeholder" value=""> + {i18n('Select...')} + </option> + {genericFieldInfo[ + `${prefix}highAvailabilityMode` + ].enum.map(hmode => ( + <option + value={hmode.enum} + key={hmode.enum}> + {hmode.title} + </option> + ))} + </Input> + </GridItem> + <GridItem colSpan={3} /> + </GridSection> + <GridSection> + {pointers.map(pointer => ( + <TextAreaItem + onQDataChanged={onQDataChanged} + genericFieldInfo={genericFieldInfo} + dataMap={dataMap} + item={pointer} + key={pointer.key + 'pKey'} + expanded={ + this.state.expanded[pointer.key] + } + toggle={name => { + this.toggle(name); + }} + /> + ))} + </GridSection> + </Form> + )} + </div> + </div> + ); + } - toggle(name) { - let st = this.state.expanded[name] ? true : false; - let newState = {...this.state}; - newState.expanded[name] = !st; - this.setState(newState); - } + toggle(name) { + let st = this.state.expanded[name] ? true : false; + let newState = { ...this.state }; + newState.expanded[name] = !st; + this.setState(newState); + } - save() { - let {onSubmit, qdata} = this.props; - return onSubmit({qdata}); - } + save() { + let { onSubmit, qdata } = this.props; + return onSubmit({ qdata }); + } } export default SoftwareProductComponentLoadBalancingView; 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 8871aabbb5..0b0b9ae2d9 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 @@ -13,51 +13,54 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductComponentsMonitoringView from './SoftwareProductComponentsMonitoringView.jsx'; import SoftwareProductComponentsMonitoringAction from './SoftwareProductComponentsMonitoringActionHelper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; - - -export const mapStateToProps = ({softwareProduct}) => { - - let {softwareProductComponents: {monitoring}} = softwareProduct; - return { - filenames: monitoring - }; - +export const mapStateToProps = ({ softwareProduct }) => { + let { softwareProductComponents: { monitoring } } = softwareProduct; + return { + filenames: monitoring + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => { - - return { - onDropMibFileToUpload: (formData, type) => - SoftwareProductComponentsMonitoringAction.uploadFile(dispatch, { - softwareProductId, - version, - componentId, - formData, - type - }), - - onDeleteFile: type => SoftwareProductComponentsMonitoringAction.deleteFile(dispatch, { - softwareProductId, - version, - componentId, - type - }), +const mapActionsToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onDropMibFileToUpload: (formData, type) => + SoftwareProductComponentsMonitoringAction.uploadFile(dispatch, { + softwareProductId, + version, + componentId, + formData, + type + }), - onFileUploadError: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Upload Failed'), - msg: i18n('Expected "zip" file. Please check the provided file type.') - } - }) - }; + onDeleteFile: type => + SoftwareProductComponentsMonitoringAction.deleteFile(dispatch, { + softwareProductId, + version, + componentId, + type + }), + onFileUploadError: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Upload Failed'), + msg: i18n( + 'Expected "zip" file. Please check the provided file type.' + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsMonitoringView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductComponentsMonitoringView); 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 3db708bc92..c60bc5f1be 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,61 +16,90 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './SoftwareProductComponentsMonitoringConstants.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './SoftwareProductComponentsMonitoringConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; 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}/uploads`; + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/components/${componentId}/uploads`; } -let onInvalidFileSizeUpload = (dispatch) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Upload Failed'), - msg: i18n('no zip file was uploaded or zip file doesn\'t exist') - } -}); +let onInvalidFileSizeUpload = dispatch => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Upload Failed'), + msg: i18n("no zip file was uploaded or zip file doesn't exist") + } + }); -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 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 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 deleteFile = ( + dispatch, + { softwareProductId, version, componentId, type } +) => { + return RestAPIUtil.destroy( + `${baseUrl(softwareProductId, version, componentId)}/types/${type}` + ).then(() => + dispatch({ + type: actionTypes.MONITOR_DELETED, + data: { type: type } + }) + ); }; - const SoftwareProductComponentsMonitoringAction = { + fetchExistingFiles(dispatch, { softwareProductId, version, componentId }) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version, componentId)}` + ).then(response => + dispatch({ + type: actionTypes.MONITOR_FILES_DATA_CHANGE, + data: response + }) + ); + }, - fetchExistingFiles(dispatch, {softwareProductId, version, componentId}){ - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`).then(response => - dispatch({ - type: actionTypes.MONITOR_FILES_DATA_CHANGE, - data: response - }) - ); - }, - - uploadFile(dispatch, {softwareProductId, version, componentId, formData, type}){ - if (formData.get('upload').size) { - return uploadFile(dispatch, {softwareProductId, version, componentId, formData, type}); - } - else { - onInvalidFileSizeUpload(dispatch); - } - }, - - deleteFile(dispatch, {softwareProductId, version, componentId, type}){ - return deleteFile(dispatch, {softwareProductId, version, componentId, type}); - } + uploadFile( + dispatch, + { softwareProductId, version, componentId, formData, type } + ) { + if (formData.get('upload').size) { + return uploadFile(dispatch, { + softwareProductId, + version, + componentId, + formData, + type + }); + } else { + onInvalidFileSizeUpload(dispatch); + } + }, + deleteFile(dispatch, { softwareProductId, version, componentId, type }) { + return deleteFile(dispatch, { + softwareProductId, + version, + componentId, + type + }); + } }; export default SoftwareProductComponentsMonitoringAction; 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 bf2cbd2a3f..10049d6b57 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 @@ -16,29 +16,26 @@ 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 + MONITOR_FILES_DATA_CHANGE: null, + MONITOR_UPLOADED: null, + MONITOR_DELETED: null }); export const fileTypes = { - SNMP_TRAP: 'SNMP_TRAP', - SNMP_POLL: 'SNMP_POLL', - VES_EVENT: 'VES_EVENTS' + SNMP_TRAP: 'SNMP_TRAP', + SNMP_POLL: 'SNMP_POLL', + VES_EVENT: 'VES_EVENTS' }; export const type2Name = { - SNMP_TRAP: 'snmpTrap', - SNMP_POLL: 'snmpPoll', - VES_EVENTS: 'vesEvent' + SNMP_TRAP: 'snmpTrap', + SNMP_POLL: 'snmpPoll', + VES_EVENTS: 'vesEvent' }; - export const type2Title = { - SNMP_TRAP : i18n('SNMP Trap'), - SNMP_POLL : i18n('SNMP Poll'), - VES_EVENTS: i18n('VES') + 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 f5cfe6f06d..61ad4ec2d9 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,23 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, type2Name} from './SoftwareProductComponentsMonitoringConstants.js'; +import { + actionTypes, + type2Name +} from './SoftwareProductComponentsMonitoringConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.MONITOR_FILES_DATA_CHANGE: - return action.data; - case actionTypes.MONITOR_UPLOADED: - return { - ...state, - [type2Name[action.data.type]]: action.data.filename - }; - case actionTypes.MONITOR_DELETED: - return { - ...state, - [type2Name[action.data.type]]: undefined - }; - default: - return state; - } + switch (action.type) { + case actionTypes.MONITOR_FILES_DATA_CHANGE: + return action.data; + case actionTypes.MONITOR_UPLOADED: + return { + ...state, + [type2Name[action.data.type]]: action.data.filename + }; + case actionTypes.MONITOR_DELETED: + return { + ...state, + [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 95d1e4e283..771bca161a 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 @@ -13,123 +13,133 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import Dropzone from 'react-dropzone'; import Button from 'sdc-ui/lib/react/Button.js'; import DraggableUploadFileBox from 'nfvo-components/fileupload/DraggableUploadFileBox.jsx'; -import {fileTypes, type2Title, type2Name} from './SoftwareProductComponentsMonitoringConstants.js'; - - +import { + fileTypes, + type2Title, + type2Name +} from './SoftwareProductComponentsMonitoringConstants.js'; class SoftwareProductComponentsMonitoringView extends Component { - - static propTypes = { - isReadOnlyMode: PropTypes.bool, - filenames: PropTypes.object, - softwareProductId: PropTypes.string, - - onDropMibFileToUpload: PropTypes.func, - onDeleteSnmpFile: PropTypes.func - }; - - state = { - dragging: false - }; - - - - - render() { - return ( - <div className='vsp-component-monitoring'> - {this.renderDropzoneWithType(fileTypes.VES_EVENT)} - {this.renderDropzoneWithType(fileTypes.SNMP_TRAP)} - {this.renderDropzoneWithType(fileTypes.SNMP_POLL)} - </div> - ); - } - - renderDropzoneWithType(type) { - let {isReadOnlyMode, filenames} = this.props; - let fileByType = type2Name[type]; - let fileName = (filenames) ? filenames[fileByType] : undefined; - let refAndName = `fileInput${type.toString()}`; - let typeDisplayName = type2Title[type]; - return ( - <Dropzone - className={`dropzone ${this.state.dragging ? 'active-dragging' : ''}`} - onDrop={(acceptedFiles, rejectedFiles) => this.handleImport(acceptedFiles, rejectedFiles, {isReadOnlyMode, type, refAndName})} - onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)} - onDragLeave={() => this.setState({dragging:false})} - multiple={false} - disableClick={true} - ref={refAndName} - name={refAndName} - accept='.zip'> - <div className='draggable-wrapper'> - <div className='section-title'>{typeDisplayName}</div> - {fileName ? this.renderUploadedFileName(fileName, type, isReadOnlyMode) : this.renderUploadButton(refAndName)} - </div> - </Dropzone> - ); - } - - renderUploadButton(refAndName) { - let {isReadOnlyMode} = this.props; - return ( - <DraggableUploadFileBox - dataTestId={`monitoring-upload-${refAndName}`} - className='software-product-landing-view-top-block-col-upl' - isReadOnlyMode={isReadOnlyMode} - onClick={() => this.refs[refAndName].open()}/> - ); - } - - renderUploadedFileName(filename, type, isReadOnlyMode) { - return ( - <div className='monitoring-file'> - <Button - color='white' - disabled={true} - className='filename'> - {filename} - </Button> - - <Button - color='gray' - data-test-id={`monitoring-delete-${type}`} - disabled={isReadOnlyMode} - onClick={()=>this.props.onDeleteFile(type)} - iconName='close' - className='delete'/> - </div> - ); - } - - - handleOnDragEnter(isReadOnlyMode) { - if (!isReadOnlyMode) { - this.setState({dragging: true}); - } - } - - handleImport(files, rejectedFiles, {isReadOnlyMode, type, refAndName}) { - if (isReadOnlyMode) { - return; - } - if (files.length > 0) { - this.setState({dragging: false}); - let file = files[0]; - let formData = new FormData(); - formData.append('upload', file); - this.refs[refAndName].value = ''; - this.props.onDropMibFileToUpload(formData, type); - } else if (rejectedFiles.length > 0) { - this.setState({dragging: false}); - this.props.onFileUploadError(); - } - } + static propTypes = { + isReadOnlyMode: PropTypes.bool, + filenames: PropTypes.object, + softwareProductId: PropTypes.string, + + onDropMibFileToUpload: PropTypes.func, + onDeleteSnmpFile: PropTypes.func + }; + + state = { + dragging: false + }; + + render() { + return ( + <div className="vsp-component-monitoring"> + {this.renderDropzoneWithType(fileTypes.VES_EVENT)} + {this.renderDropzoneWithType(fileTypes.SNMP_TRAP)} + {this.renderDropzoneWithType(fileTypes.SNMP_POLL)} + </div> + ); + } + + renderDropzoneWithType(type) { + let { isReadOnlyMode, filenames } = this.props; + let fileByType = type2Name[type]; + let fileName = filenames ? filenames[fileByType] : undefined; + let refAndName = `fileInput${type.toString()}`; + let typeDisplayName = type2Title[type]; + return ( + <Dropzone + className={`dropzone ${ + this.state.dragging ? 'active-dragging' : '' + }`} + onDrop={(acceptedFiles, rejectedFiles) => + this.handleImport(acceptedFiles, rejectedFiles, { + isReadOnlyMode, + type, + refAndName + }) + } + onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode)} + onDragLeave={() => this.setState({ dragging: false })} + multiple={false} + disableClick={true} + ref={refAndName} + name={refAndName} + accept=".zip"> + <div className="draggable-wrapper"> + <div className="section-title">{typeDisplayName}</div> + {fileName + ? this.renderUploadedFileName( + fileName, + type, + isReadOnlyMode + ) + : this.renderUploadButton(refAndName)} + </div> + </Dropzone> + ); + } + + renderUploadButton(refAndName) { + let { isReadOnlyMode } = this.props; + return ( + <DraggableUploadFileBox + dataTestId={`monitoring-upload-${refAndName}`} + className="software-product-landing-view-top-block-col-upl" + isReadOnlyMode={isReadOnlyMode} + onClick={() => this.refs[refAndName].open()} + /> + ); + } + + renderUploadedFileName(filename, type, isReadOnlyMode) { + return ( + <div className="monitoring-file"> + <Button color="white" disabled={true} className="filename"> + {filename} + </Button> + + <Button + color="gray" + data-test-id={`monitoring-delete-${type}`} + disabled={isReadOnlyMode} + onClick={() => this.props.onDeleteFile(type)} + iconName="close" + className="delete" + /> + </div> + ); + } + + handleOnDragEnter(isReadOnlyMode) { + if (!isReadOnlyMode) { + this.setState({ dragging: true }); + } + } + + handleImport(files, rejectedFiles, { isReadOnlyMode, type, refAndName }) { + if (isReadOnlyMode) { + return; + } + if (files.length > 0) { + this.setState({ dragging: false }); + let file = files[0]; + let formData = new FormData(); + formData.append('upload', file); + this.refs[refAndName].value = ''; + this.props.onDropMibFileToUpload(formData, type); + } else if (rejectedFiles.length > 0) { + this.setState({ dragging: false }); + this.props.onFileUploadError(); + } + } } 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 index d4aaf7cc7e..e705618a65 100644 --- 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 @@ -13,39 +13,55 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +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 { + 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); +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 - }; + return { + currentSoftwareProduct, + data, + genericFieldInfo, + isFormValid, + formReady + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onDataChanged: deltaData => ValidationHelper.dataChanged(dispatch, {deltaData, formName: NIC_CREATION_FORM_NAME}), - onCancel: () => NICCreationActionHelper.close(dispatch), - onSubmit: ({nic, componentId}) => { - SoftwareProductComponentsNetworkActionHelper.createNIC(dispatch, {nic, softwareProductId, componentId, version}); - NICCreationActionHelper.close(dispatch); - }, - onValidateForm: () => ValidationHelper.validateForm(dispatch, NIC_CREATION_FORM_NAME) - }; +const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: NIC_CREATION_FORM_NAME + }), + onCancel: () => NICCreationActionHelper.close(dispatch), + onSubmit: ({ nic, componentId }) => { + SoftwareProductComponentsNetworkActionHelper.createNIC(dispatch, { + nic, + softwareProductId, + componentId, + version + }); + NICCreationActionHelper.close(dispatch); + }, + 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 index a40b32d51a..4f200ce33f 100644 --- 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 @@ -13,35 +13,37 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from '../SoftwareProductComponentsNetworkConstants'; +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'; +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, version } + ) { + dispatch({ + type: actionTypes.NICCreation.OPEN + }); - open(dispatch, {softwareProductId, componentId, modalClassName, version}) { - 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, version } + } + }); + }, - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.NIC_CREATION, - title: i18n('Create NEW NIC'), - modalClassName, - modalComponentProps: {softwareProductId, componentId, version} - } - }); - }, - - close(dispatch){ - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - dispatch({ - type: actionTypes.NICCreation.CLEAR_DATA - }); - } + 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 index c7e2495b3d..8309c40451 100644 --- 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 @@ -13,37 +13,40 @@ * 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'; +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; - } + 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 index 258876844a..88525c051d 100644 --- 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 @@ -22,103 +22,136 @@ import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; const NICPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - networkId: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + networkId: PropTypes.string }); class NICCreationView extends React.Component { + static propTypes = { + data: NICPropType, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - static propTypes = { - data: NICPropType, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: 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 hasLastColSet> + <GridItem colSpan={4} lastColInRow> + <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')} hasLastColSet> + <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} lastColInRow> + <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> + ); + } - 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 hasLastColSet> - <GridItem colSpan={4} lastColInRow> - <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')} hasLastColSet> - <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} lastColInRow> - <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, componentId} = this.props; - this.props.onSubmit({nic, componentId}); - } + submit() { + const { data: nic, componentId } = this.props; + this.props.onSubmit({ nic, componentId }); + } } 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 93bd0bd67e..d7205b46ed 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 @@ -13,56 +13,93 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductComponentsNetworkActionHelper from './SoftwareProductComponentsNetworkActionHelper.js'; import SoftwareProductComponentsNICEditorView from './SoftwareProductComponentsNICEditorView.jsx'; 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'; +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, currentScreen}) => { - - let {softwareProductEditor: {data:currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; - let {network: {nicEditor = {}}} = softwareProductComponents; - let {data, qdata, genericFieldInfo, qgenericFieldInfo, dataMap, formReady} = nicEditor; - let {props: {isReadOnlyMode}} = currentScreen; - let {onboardingMethod} = currentSoftwareProduct; - let protocols = []; - if(qdata && qdata.protocols && qdata.protocols.protocols && qdata.protocols.protocols.length){ - protocols = qdata.protocols.protocols; - } - let {version} = currentSoftwareProduct; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo) && ValidationHelper.checkFormValid(qgenericFieldInfo); - - return { - currentSoftwareProduct, - isValidityData, - version, - data, - qdata, - dataMap, - isFormValid, - formReady, - genericFieldInfo, - qgenericFieldInfo, - isReadOnlyMode, - protocols, - isManual: onboardingMethod === onboardingMethodTypes.MANUAL - }; +export const mapStateToProps = ({ softwareProduct, currentScreen }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {}, + isValidityData = true + }, + softwareProductComponents + } = softwareProduct; + let { network: { nicEditor = {} } } = softwareProductComponents; + let { + data, + qdata, + genericFieldInfo, + qgenericFieldInfo, + dataMap, + formReady + } = nicEditor; + let { props: { isReadOnlyMode } } = currentScreen; + let { onboardingMethod } = currentSoftwareProduct; + let protocols = []; + if ( + qdata && + qdata.protocols && + qdata.protocols.protocols && + qdata.protocols.protocols.length + ) { + protocols = qdata.protocols.protocols; + } + let { version } = currentSoftwareProduct; + let isFormValid = + ValidationHelper.checkFormValid(genericFieldInfo) && + ValidationHelper.checkFormValid(qgenericFieldInfo); + return { + currentSoftwareProduct, + isValidityData, + version, + data, + qdata, + dataMap, + isFormValid, + formReady, + genericFieldInfo, + qgenericFieldInfo, + isReadOnlyMode, + protocols, + isManual: onboardingMethod === onboardingMethodTypes.MANUAL + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, - formName: forms.NIC_EDIT_FORM}), - onSubmit: ({data, qdata}) => SoftwareProductComponentsNetworkActionHelper.saveNICDataAndQuestionnaire(dispatch, {softwareProductId, version, componentId, data, qdata}), - onCancel: () => SoftwareProductComponentsNetworkActionHelper.closeNICEditor(dispatch), - onValidateForm: () => ValidationHelper.validateForm(dispatch, forms.NIC_EDIT_FORM), - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, - qName: NIC_QUESTIONNAIRE}), - }; +const mapActionsToProps = ( + dispatch, + { softwareProductId, componentId, version } +) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: forms.NIC_EDIT_FORM + }), + onSubmit: ({ data, qdata }) => + SoftwareProductComponentsNetworkActionHelper.saveNICDataAndQuestionnaire( + dispatch, + { softwareProductId, version, componentId, data, qdata } + ), + onCancel: () => + SoftwareProductComponentsNetworkActionHelper.closeNICEditor( + dispatch + ), + onValidateForm: () => + ValidationHelper.validateForm(dispatch, forms.NIC_EDIT_FORM), + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: NIC_QUESTIONNAIRE + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentsNICEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + SoftwareProductComponentsNICEditorView +); 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 dd37135d77..2da9b4b76b 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 @@ -13,37 +13,37 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentsNetworkConstants.js'; -import {forms} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; +import { actionTypes } from './SoftwareProductComponentsNetworkConstants.js'; +import { forms } from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.NICEditor.FILL_DATA: - return { - ...state, - data: action.nic, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [] - }, - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data : true}] - }, - 'networkDescription' : { - isValid: true, - errorText: '', - validations: [] - } - }, - formName: forms.NIC_EDIT_FORM - }; - case actionTypes.NICEditor.CLEAR_DATA: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.NICEditor.FILL_DATA: + return { + ...state, + data: action.nic, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [] + }, + name: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + networkDescription: { + isValid: true, + errorText: '', + validations: [] + } + }, + formName: forms.NIC_EDIT_FORM + }; + 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 fbb3d53033..df2efbe39e 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 @@ -26,48 +26,113 @@ import Protocols from './nicEditorComponents/Protocols.jsx'; import NameAndPurpose from './nicEditorComponents/NameAndPurpose.jsx'; class SoftwareProductComponentsNetworkEditorView extends React.Component { + render() { + 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 + } + ]; + return ( + <div> + {qgenericFieldInfo && ( + <Form + ref={form => { + this.form = form; + }} + hasButtons={true} + onSubmit={() => this.submit()} + onReset={() => onCancel()} + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + isValid={isFormValid} + formReady={formReady} + onValidateForm={() => onValidateForm()} + className="vsp-components-network-editor"> + <div className="editor-data"> + <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 + 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} + /> + <FlowLength + qgenericFieldInfo={qgenericFieldInfo} + dataMap={dataMap} + onQDataChanged={onQDataChanged} + /> + <Acceptable + qgenericFieldInfo={qgenericFieldInfo} + dataMap={dataMap} + onQDataChanged={onQDataChanged} + /> + </div> + </Form> + )} + </div> + ); + } - render() { - 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 - }]; - return ( - <div> - {qgenericFieldInfo && <Form - ref={(form) => { this.form = form; }} - hasButtons={true} - onSubmit={ () => this.submit() } - onReset={ () => onCancel() } - labledButtons={true} - isReadOnlyMode={isReadOnlyMode} - isValid={isFormValid} - formReady={formReady} - onValidateForm={() => onValidateForm() } - className='vsp-components-network-editor'> - <div className='editor-data'> - <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 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} /> - <FlowLength qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> - <Acceptable qgenericFieldInfo={qgenericFieldInfo} dataMap={dataMap} onQDataChanged={onQDataChanged} /> - </div> - </Form> } - </div> - ); - } - - submit() { - let {data, qdata, onSubmit} = this.props; - onSubmit({data, qdata}); - } + submit() { + let { data, qdata, onSubmit } = this.props; + onSubmit({ data, qdata }); + } } export default SoftwareProductComponentsNetworkEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICListReducer.js index 5cfc88bdc9..a2e65142a2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNICListReducer.js @@ -13,16 +13,22 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentsNetworkConstants.js'; +import { actionTypes } from './SoftwareProductComponentsNetworkConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.NIC_LIST_UPDATE: - return [...action.response]; - case actionTypes.NIC_LIST_EDIT: - const indexForEdit = state.findIndex(nic => nic.id === action.nic.id); - return [...state.slice(0, indexForEdit), action.nic, ...state.slice(indexForEdit + 1)]; - default: - return state; - } + switch (action.type) { + case actionTypes.NIC_LIST_UPDATE: + return [...action.response]; + case actionTypes.NIC_LIST_EDIT: + const indexForEdit = state.findIndex( + nic => nic.id === action.nic.id + ); + return [ + ...state.slice(0, indexForEdit), + action.nic, + ...state.slice(indexForEdit + 1) + ]; + default: + return state; + } }; 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 1ffbc5919f..58c816134b 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 @@ -17,127 +17,223 @@ 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 { 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'; +import { NIC_QUESTIONNAIRE } from 'sdc-app/onboarding/softwareProduct/components/network/SoftwareProductComponentsNetworkConstants.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}/nics`; + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + 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 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`); +function fetchNICQuestionnaire({ + softwareProductId, + version, + componentId, + nicId +}) { + return RestAPIUtil.fetch( + `${baseUrl( + softwareProductId, + version, + componentId + )}/${nicId}/questionnaire` + ); } -function fetchNIC({softwareProductId, version, componentId, nicId}) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}/${nicId}`); +function fetchNIC({ softwareProductId, version, componentId, nicId }) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version, componentId)}/${nicId}` + ); } -function fetchNICsList({softwareProductId, version, componentId}) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`); +function fetchNICsList({ softwareProductId, version, componentId }) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version, componentId)}` + ); } -function deleteNIC({softwareProductId, componentId, nicId, version}) { - return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${nicId}`); +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, - networkDescription, - networkType - }); +function saveNIC({ + softwareProductId, + version, + componentId, + nic: { id, name, description, networkId, networkType, networkDescription } +}) { + return RestAPIUtil.put( + `${baseUrl(softwareProductId, version, componentId)}/${id}`, + { + name, + description, + networkId, + networkDescription, + networkType + } + ); } -function saveNICQuestionnaire({softwareProductId, version, componentId, nicId, qdata}) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${nicId}/questionnaire`, qdata); +function saveNICQuestionnaire({ + softwareProductId, + version, + componentId, + nicId, + qdata +}) { + return RestAPIUtil.put( + `${baseUrl( + softwareProductId, + version, + componentId + )}/${nicId}/questionnaire`, + qdata + ); } const SoftwareProductComponentNetworkActionHelper = { - - fetchNICsList(dispatch, {softwareProductId, version, componentId}) { - return fetchNICsList({softwareProductId, version, componentId}).then((response) => { - dispatch({ - type: actionTypes.NIC_LIST_UPDATE, - response: response.results - }); - }); - }, - - openNICEditor(dispatch, {nic = {}, data = {}, softwareProductId, componentId, isReadOnlyMode, modalClassName, version}) { - dispatch({ - type: actionTypes.NICEditor.FILL_DATA, - nic: {...data, id: nic.id} - }); - dispatch({ - type: GlobalModalActions.GLOBAL_MODAL_SHOW, - data: { - modalClassName, - modalComponentProps: {softwareProductId, componentId, isReadOnlyMode, version}, - modalComponentName: modalPagesMapper.NIC_EDITOR, - title: i18n('Edit NIC') - } - }); - }, - - closeNICEditor(dispatch) { - dispatch({ - 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: { - qdata: response.data ? JSON.parse(response.data) : {}, - qschema: JSON.parse(response.schema) - }}); - }); - }, - - saveNICDataAndQuestionnaire(dispatch, {softwareProductId, version, componentId, data, qdata}) { - SoftwareProductComponentNetworkActionHelper.closeNICEditor(dispatch); - return Promise.all([ - saveNICQuestionnaire({softwareProductId, version, componentId, nicId: data.id, qdata}), - saveNIC({softwareProductId, version, componentId, nic: data}).then(() => { - dispatch({ - type: actionTypes.NIC_LIST_EDIT, - nic: data - }); - }) - ]); - } + fetchNICsList(dispatch, { softwareProductId, version, componentId }) { + return fetchNICsList({ softwareProductId, version, componentId }).then( + response => { + dispatch({ + type: actionTypes.NIC_LIST_UPDATE, + response: response.results + }); + } + ); + }, + + openNICEditor( + dispatch, + { + nic = {}, + data = {}, + softwareProductId, + componentId, + isReadOnlyMode, + modalClassName, + version + } + ) { + dispatch({ + type: actionTypes.NICEditor.FILL_DATA, + nic: { ...data, id: nic.id } + }); + dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_SHOW, + data: { + modalClassName, + modalComponentProps: { + softwareProductId, + componentId, + isReadOnlyMode, + version + }, + modalComponentName: modalPagesMapper.NIC_EDITOR, + title: i18n('Edit NIC') + } + }); + }, + + closeNICEditor(dispatch) { + dispatch({ + 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: { + qdata: response.data ? JSON.parse(response.data) : {}, + qschema: JSON.parse(response.schema) + } + }); + }); + }, + + saveNICDataAndQuestionnaire( + dispatch, + { softwareProductId, version, componentId, data, qdata } + ) { + SoftwareProductComponentNetworkActionHelper.closeNICEditor(dispatch); + return Promise.all([ + saveNICQuestionnaire({ + softwareProductId, + version, + componentId, + nicId: data.id, + qdata + }), + saveNIC({ + softwareProductId, + version, + componentId, + nic: data + }).then(() => { + dispatch({ + type: actionTypes.NIC_LIST_EDIT, + nic: data + }); + }) + ]); + } }; export default SoftwareProductComponentNetworkActionHelper; 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 8ef8fe8c18..4e361bb1a9 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 @@ -16,23 +16,23 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - NIC_LIST_EDIT: null, - NIC_LIST_UPDATE: null, + NIC_LIST_EDIT: null, + NIC_LIST_UPDATE: null, - NICEditor: { - FILL_DATA: null, - CLEAR_DATA: null, - }, - NICCreation: { - OPEN: null, - CLEAR_DATA: null, - DATA_CHANGED: null - }, + NICEditor: { + FILL_DATA: null, + CLEAR_DATA: null + }, + NICCreation: { + OPEN: null, + CLEAR_DATA: null, + DATA_CHANGED: null + } }); export const networkTypes = { - EXTERNAL: 'External', - INTERNAL: 'Internal' + 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 bb256d5d41..ac708524cf 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 @@ -13,79 +13,132 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; import SoftwareProductComponentsNetworkListView from './SoftwareProductComponentsNetworkListView.jsx'; import SoftwareProductComponentsNetworkActionHelper from './SoftwareProductComponentsNetworkActionHelper.js'; -import {COMPONENTS_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsConstants.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 { actionTypes as GlobalModalActions } from 'nfvo-components/modal/GlobalModalConstants.js'; import NICCreationActionHelper from './NICCreation/NICCreationActionHelper.js'; -import {onboardingMethod as onboardingMethodTypes} from '../../SoftwareProductConstants.js'; +import { onboardingMethod as onboardingMethodTypes } from '../../SoftwareProductConstants.js'; +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {}, + isValidityData = true + }, + softwareProductComponents + } = softwareProduct; + let { + network: { nicList = [] }, + componentEditor: { + data: componentData, + qdata, + dataMap, + qgenericFieldInfo + } + } = softwareProductComponents; + let { version, onboardingMethod } = currentSoftwareProduct; + let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; -export const mapStateToProps = ({softwareProduct}) => { - - let {softwareProductEditor: {data: currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents} = softwareProduct; - let {network: {nicList = []}, componentEditor: {data: componentData, qdata, dataMap, qgenericFieldInfo}} = softwareProductComponents; - let {version, onboardingMethod} = currentSoftwareProduct; - let isManual = onboardingMethod === onboardingMethodTypes.MANUAL; - - return { - version, - componentData, - qdata, - dataMap, - qgenericFieldInfo, - isValidityData, - nicList, - isManual - }; - + return { + version, + componentData, + qdata, + dataMap, + qgenericFieldInfo, + isValidityData, + nicList, + isManual + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, componentId, version}) => { - return { - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, - qName: COMPONENTS_QUESTIONNAIRE}), - onAddNic: () => NICCreationActionHelper.open(dispatch, {softwareProductId, componentId, modalClassName: 'network-nic-modal-create', version}), - onDeleteNic: (nic) => dispatch({ - type: GlobalModalActions.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: nic.name}), - onConfirmed: () => SoftwareProductComponentsNetworkActionHelper.deleteNIC(dispatch, {softwareProductId, - componentId, nicId: nic.id, version}) - } - }), - onEditNicClick: (nic, isReadOnlyMode) => { - Promise.all([ - SoftwareProductComponentsNetworkActionHelper.loadNICData({ - softwareProductId, - version, - componentId, - nicId: nic.id - }), - SoftwareProductComponentsNetworkActionHelper.loadNICQuestionnaire(dispatch, { - softwareProductId, - version, - componentId, - nicId: nic.id - }) - ]).then( - ([{data}]) => SoftwareProductComponentsNetworkActionHelper.openNICEditor(dispatch, {nic, data, - isReadOnlyMode, softwareProductId, componentId, modalClassName: 'network-nic-modal-edit', version}) - ); - }, - onSubmit: ({qdata}) => { return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, - {softwareProductId, version, - vspComponentId: componentId, - qdata}); - } - - - }; +const mapActionsToProps = ( + dispatch, + { softwareProductId, componentId, version } +) => { + return { + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: COMPONENTS_QUESTIONNAIRE + }), + onAddNic: () => + NICCreationActionHelper.open(dispatch, { + softwareProductId, + componentId, + modalClassName: 'network-nic-modal-create', + version + }), + onDeleteNic: nic => + dispatch({ + type: GlobalModalActions.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete "{name}"?', { + name: nic.name + }), + onConfirmed: () => + SoftwareProductComponentsNetworkActionHelper.deleteNIC( + dispatch, + { + softwareProductId, + componentId, + nicId: nic.id, + version + } + ) + } + }), + onEditNicClick: (nic, isReadOnlyMode) => { + Promise.all([ + SoftwareProductComponentsNetworkActionHelper.loadNICData({ + softwareProductId, + version, + componentId, + nicId: nic.id + }), + SoftwareProductComponentsNetworkActionHelper.loadNICQuestionnaire( + dispatch, + { + softwareProductId, + version, + componentId, + nicId: nic.id + } + ) + ]).then(([{ data }]) => + SoftwareProductComponentsNetworkActionHelper.openNICEditor( + dispatch, + { + nic, + data, + isReadOnlyMode, + softwareProductId, + componentId, + modalClassName: 'network-nic-modal-edit', + version + } + ) + ); + }, + onSubmit: ({ qdata }) => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + qdata + } + ); + } + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsNetworkListView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductComponentsNetworkListView); 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 4d460c722d..c631fb24c3 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 @@ -20,138 +20,203 @@ 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'; - +import Input from 'nfvo-components/input/validation/Input.jsx'; class SoftwareProductComponentsNetworkView extends React.Component { + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; - - render() { - let {dataMap, qgenericFieldInfo, onQDataChanged, isReadOnlyMode} = this.props; - - return( - <div className='vsp-components-network'> - <div className='network-data'> - <div> -{ qgenericFieldInfo && <Form - formReady={null} - isValid={true} - onSubmit={() => this.save()} - isReadOnlyMode={isReadOnlyMode} - hasButtons={false}> - <h3 className='section-title'>{i18n('Network Capacity')}</h3> - <div className='rows-section'> - <div className='row-flex-components'> - <div className='single-col'> - <Input - data-test-id='protocolWithHighestTrafficProfileAcrossAllNICs' - label={i18n('Protocol with Highest Traffic Profile across all NICs')} - type='select' - groupClassName='bootstrap-input-options' - className='input-options-select' - isValid={qgenericFieldInfo['network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs'].isValid} - errorText={qgenericFieldInfo['network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs'].errorText} - value={dataMap['network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - { qgenericFieldInfo['network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs'].enum.map(proto => - <option value={proto.enum} key={proto.enum}>{proto.title}</option>) } - </Input> - </div> - <div className='single-col add-line-break'> - <Input - data-test-id='networkTransactionsPerSecond' - label={i18n('Network Transactions per Second')} - type='number' - onChange={(ntps) => onQDataChanged({'network/networkCapacity/networkTransactionsPerSecond' : ntps})} - isValid={qgenericFieldInfo['network/networkCapacity/networkTransactionsPerSecond'].isValid} - errorText={qgenericFieldInfo['network/networkCapacity/networkTransactionsPerSecond'].errorText} - value={dataMap['network/networkCapacity/networkTransactionsPerSecond']} /> - </div> - <div className='empty-two-col' /> - </div> - </div> - - </Form> } - </div> - {this.renderNicList()} - </div> - - </div> - ); - } - - renderNicList() { - const {localFilter} = this.state; - let {isReadOnlyMode, onAddNic, isManual} = this.props; - return ( - <ListEditorView - title={i18n('Interfaces')} - filterValue={localFilter} - 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> - ); - } + render() { + let { + dataMap, + qgenericFieldInfo, + onQDataChanged, + isReadOnlyMode + } = this.props; - renderNicListItem(nic, isReadOnlyMode) { - let {id, name, description, networkName = ''} = nic; - let {onEditNicClick, version, isManual, onDeleteNic} = this.props; - return ( - <ListEditorItemView - key={id} - isReadOnlyMode={isReadOnlyMode} - onSelect={() => onEditNicClick(nic, version, isReadOnlyMode)} - onDelete={isManual ? () => onDeleteNic(nic, version) : null}> + return ( + <div className="vsp-components-network"> + <div className="network-data"> + <div> + {qgenericFieldInfo && ( + <Form + formReady={null} + isValid={true} + onSubmit={() => this.save()} + isReadOnlyMode={isReadOnlyMode} + hasButtons={false}> + <h3 className="section-title"> + {i18n('Network Capacity')} + </h3> + <div className="rows-section"> + <div className="row-flex-components"> + <div className="single-col"> + <Input + data-test-id="protocolWithHighestTrafficProfileAcrossAllNICs" + label={i18n( + 'Protocol with Highest Traffic Profile across all NICs' + )} + type="select" + groupClassName="bootstrap-input-options" + className="input-options-select" + isValid={ + qgenericFieldInfo[ + 'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs' + ].errorText + } + value={ + dataMap[ + 'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs' + ] + } + onChange={e => { + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[ + selectedIndex + ].value; + onQDataChanged({ + 'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs': val + }); + }}> + <option + key="placeholder" + value=""> + {i18n('Select...')} + </option> + {qgenericFieldInfo[ + 'network/networkCapacity/protocolWithHighestTrafficProfileAcrossAllNICs' + ].enum.map(proto => ( + <option + value={proto.enum} + key={proto.enum}> + {proto.title} + </option> + ))} + </Input> + </div> + <div className="single-col add-line-break"> + <Input + data-test-id="networkTransactionsPerSecond" + label={i18n( + 'Network Transactions per Second' + )} + type="number" + onChange={ntps => + onQDataChanged({ + 'network/networkCapacity/networkTransactionsPerSecond': ntps + }) + } + isValid={ + qgenericFieldInfo[ + 'network/networkCapacity/networkTransactionsPerSecond' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'network/networkCapacity/networkTransactionsPerSecond' + ].errorText + } + value={ + dataMap[ + 'network/networkCapacity/networkTransactionsPerSecond' + ] + } + /> + </div> + <div className="empty-two-col" /> + </div> + </div> + </Form> + )} + </div> + {this.renderNicList()} + </div> + </div> + ); + } - <ListEditorItemViewField> - <div className='name'>{name}</div> - </ListEditorItemViewField> - <ListEditorItemViewField> - <div className={isManual ? 'details-col' : 'details'}> - <div className={isManual ? 'manual-title' : 'title'}>{i18n('Purpose of NIC')}</div> - {description && <div className={isManual ? 'description' : ''}>{description}</div>} - </div> - {!isManual && <div className='details'> - <div className='title'>{i18n('Network')}</div> - <div className='artifact-name'>{networkName}</div> - </div>} - </ListEditorItemViewField> + renderNicList() { + const { localFilter } = this.state; + let { isReadOnlyMode, onAddNic, isManual } = this.props; + return ( + <ListEditorView + title={i18n('Interfaces')} + filterValue={localFilter} + 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> + ); + } - </ListEditorItemView> - ); - } + renderNicListItem(nic, isReadOnlyMode) { + let { id, name, description, networkName = '' } = nic; + let { onEditNicClick, version, isManual, onDeleteNic } = this.props; + return ( + <ListEditorItemView + key={id} + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditNicClick(nic, version, isReadOnlyMode)} + onDelete={isManual ? () => onDeleteNic(nic, version) : null}> + <ListEditorItemViewField> + <div className="name">{name}</div> + </ListEditorItemViewField> + <ListEditorItemViewField> + <div className={isManual ? 'details-col' : 'details'}> + <div className={isManual ? 'manual-title' : 'title'}> + {i18n('Purpose of NIC')} + </div> + {description && ( + <div className={isManual ? 'description' : ''}> + {description} + </div> + )} + </div> + {!isManual && ( + <div className="details"> + <div className="title">{i18n('Network')}</div> + <div className="artifact-name">{networkName}</div> + </div> + )} + </ListEditorItemViewField> + </ListEditorItemView> + ); + } - filterList() { - let {nicList} = this.props; - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return nicList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return nicList; - } - } + filterList() { + let { nicList } = this.props; + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return nicList.filter(({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + }); + } else { + return nicList; + } + } - save() { - let {onSubmit, qdata, version} = this.props; - return onSubmit({qdata, version}); - } + save() { + let { onSubmit, qdata, version } = this.props; + return onSubmit({ qdata, version }); + } } export default SoftwareProductComponentsNetworkView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Acceptable.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Acceptable.jsx index 0fc7404c56..0b2783ebe7 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Acceptable.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Acceptable.jsx @@ -19,57 +19,97 @@ 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 Acceptable = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { - return( - <GridSection hasLastColSet> - <GridItem colSpan={3}> - <div className='part-title-small packets'>{i18n('Acceptable Jitter')}</div> - </GridItem> - <GridItem lastColInRow> - <div className='part-title-small bytes'>{i18n('Allow Packet Loss')}</div> - </GridItem> - <GridItem> - <Input - label={i18n('Mean')} - type='number' - data-test-id='acceptableJitter-mean' - isValid={qgenericFieldInfo['sizing/acceptableJitter/mean'].isValid} - errorText={qgenericFieldInfo['sizing/acceptableJitter/mean'].errorText} - value={dataMap['sizing/acceptableJitter/mean']} - onChange={val => onQDataChanged({'sizing/acceptableJitter/mean' : val})} /> - </GridItem> - <GridItem> - <Input - label={i18n('Max')} - type='number' - data-test-id='acceptableJitter-max' - isValid={qgenericFieldInfo['sizing/acceptableJitter/max'].isValid} - errorText={qgenericFieldInfo['sizing/acceptableJitter/max'].errorText} - value={dataMap['sizing/acceptableJitter/max']} - onChange={val => onQDataChanged({'sizing/acceptableJitter/max' : val})} /> - </GridItem> - <GridItem> - <Input - label={i18n('Var')} - type='number' - data-test-id='acceptableJitter-variable' - isValid={qgenericFieldInfo['sizing/acceptableJitter/variable'].isValid} - errorText={qgenericFieldInfo['sizing/acceptableJitter/variable'].errorText} - value={dataMap['sizing/acceptableJitter/variable']} - onChange={val => onQDataChanged({'sizing/acceptableJitter/variable' : val})} /> - </GridItem> - <GridItem lastColInRow> - <Input - label={i18n('In Percent')} - type='number' - data-test-id='acceptableJitter-acceptablePacketLoss' - isValid={qgenericFieldInfo['sizing/acceptablePacketLoss'].isValid} - errorText={qgenericFieldInfo['sizing/acceptablePacketLoss'].errorText} - value={dataMap['sizing/acceptablePacketLoss']} - onChange={val => onQDataChanged({'sizing/acceptablePacketLoss' : val})} /> - </GridItem> - </GridSection> - ); +const Acceptable = ({ qgenericFieldInfo, dataMap, onQDataChanged }) => { + return ( + <GridSection hasLastColSet> + <GridItem colSpan={3}> + <div className="part-title-small packets"> + {i18n('Acceptable Jitter')} + </div> + </GridItem> + <GridItem lastColInRow> + <div className="part-title-small bytes"> + {i18n('Allow Packet Loss')} + </div> + </GridItem> + <GridItem> + <Input + label={i18n('Mean')} + type="number" + data-test-id="acceptableJitter-mean" + isValid={ + qgenericFieldInfo['sizing/acceptableJitter/mean'] + .isValid + } + errorText={ + qgenericFieldInfo['sizing/acceptableJitter/mean'] + .errorText + } + value={dataMap['sizing/acceptableJitter/mean']} + onChange={val => + onQDataChanged({ 'sizing/acceptableJitter/mean': val }) + } + /> + </GridItem> + <GridItem> + <Input + label={i18n('Max')} + type="number" + data-test-id="acceptableJitter-max" + isValid={ + qgenericFieldInfo['sizing/acceptableJitter/max'].isValid + } + errorText={ + qgenericFieldInfo['sizing/acceptableJitter/max'] + .errorText + } + value={dataMap['sizing/acceptableJitter/max']} + onChange={val => + onQDataChanged({ 'sizing/acceptableJitter/max': val }) + } + /> + </GridItem> + <GridItem> + <Input + label={i18n('Var')} + type="number" + data-test-id="acceptableJitter-variable" + isValid={ + qgenericFieldInfo['sizing/acceptableJitter/variable'] + .isValid + } + errorText={ + qgenericFieldInfo['sizing/acceptableJitter/variable'] + .errorText + } + value={dataMap['sizing/acceptableJitter/variable']} + onChange={val => + onQDataChanged({ + 'sizing/acceptableJitter/variable': val + }) + } + /> + </GridItem> + <GridItem lastColInRow> + <Input + label={i18n('In Percent')} + type="number" + data-test-id="acceptableJitter-acceptablePacketLoss" + isValid={ + qgenericFieldInfo['sizing/acceptablePacketLoss'].isValid + } + errorText={ + qgenericFieldInfo['sizing/acceptablePacketLoss'] + .errorText + } + value={dataMap['sizing/acceptablePacketLoss']} + onChange={val => + onQDataChanged({ 'sizing/acceptablePacketLoss': val }) + } + /> + </GridItem> + </GridSection> + ); }; export default Acceptable; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/FlowLength.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/FlowLength.jsx index 3745fc7c2e..32a5516eb4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/FlowLength.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/FlowLength.jsx @@ -18,18 +18,20 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import PacketsBytes from './PacketsBytes.jsx'; const pointers = [ - {label: 'Peak', value: 'sizing/flowLength/packets/peak'}, - {label: 'Avg', value: 'sizing/flowLength/packets/avg'}, - {label: 'Peak', value: 'sizing/flowLength/bytes/peak'}, - {label: 'Avg', value: 'sizing/flowLength/bytes/avg'}, + { label: 'Peak', value: 'sizing/flowLength/packets/peak' }, + { label: 'Avg', value: 'sizing/flowLength/packets/avg' }, + { label: 'Peak', value: 'sizing/flowLength/bytes/peak' }, + { label: 'Avg', value: 'sizing/flowLength/bytes/avg' } ]; -const FlowLength = (props) => { - return( - <PacketsBytes {...props} title={i18n('Flow Length')} pointers={pointers}/> - ); +const FlowLength = props => { + return ( + <PacketsBytes + {...props} + title={i18n('Flow Length')} + pointers={pointers} + /> + ); }; export default FlowLength; - - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/InFlowTraffic.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/InFlowTraffic.jsx index 5476ed90e6..150e58af52 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/InFlowTraffic.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/InFlowTraffic.jsx @@ -18,18 +18,20 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import PacketsBytes from './PacketsBytes.jsx'; const pointers = [ - {label: 'Peak', value: 'sizing/inflowTrafficPerSecond/packets/peak'}, - {label: 'Avg', value: 'sizing/inflowTrafficPerSecond/packets/avg'}, - {label: 'Peak', value: 'sizing/inflowTrafficPerSecond/bytes/peak'}, - {label: 'Avg', value: 'sizing/inflowTrafficPerSecond/bytes/avg'}, + { label: 'Peak', value: 'sizing/inflowTrafficPerSecond/packets/peak' }, + { label: 'Avg', value: 'sizing/inflowTrafficPerSecond/packets/avg' }, + { label: 'Peak', value: 'sizing/inflowTrafficPerSecond/bytes/peak' }, + { label: 'Avg', value: 'sizing/inflowTrafficPerSecond/bytes/avg' } ]; -const InFlowTraffic = (props) => { - return( - <PacketsBytes {...props} title={i18n('Inflow Traffic per second')} pointers={pointers}/> - ); +const InFlowTraffic = props => { + return ( + <PacketsBytes + {...props} + title={i18n('Inflow Traffic per second')} + pointers={pointers} + /> + ); }; export default InFlowTraffic; - - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/IpConfig.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/IpConfig.jsx index b3a5d21625..695835606b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/IpConfig.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/IpConfig.jsx @@ -19,27 +19,37 @@ 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 IpConfig = ({dataMap, onQDataChanged}) => { - return ( - <GridSection title={i18n('IP Configuration')}> - <GridItem> - <Input - label={i18n('IPv4 Required')} - type='checkbox' - onChange={value => onQDataChanged({'ipConfiguration/ipv4Required' : value})} - data-test-id='ipConfiguration-ipv4Required' - value={dataMap['ipConfiguration/ipv4Required']} /> - </GridItem> - <GridItem> - <Input - label={i18n('IPv6 Required')} - type='checkbox' - data-test-id='ipConfiguration-ipv6Required' - onChange={value => onQDataChanged({'ipConfiguration/ipv6Required' : value})} - value={dataMap['ipConfiguration/ipv6Required']} /> - </GridItem> - </GridSection> - ); +const IpConfig = ({ dataMap, onQDataChanged }) => { + return ( + <GridSection title={i18n('IP Configuration')}> + <GridItem> + <Input + label={i18n('IPv4 Required')} + type="checkbox" + onChange={value => + onQDataChanged({ + 'ipConfiguration/ipv4Required': value + }) + } + data-test-id="ipConfiguration-ipv4Required" + value={dataMap['ipConfiguration/ipv4Required']} + /> + </GridItem> + <GridItem> + <Input + label={i18n('IPv6 Required')} + type="checkbox" + data-test-id="ipConfiguration-ipv6Required" + onChange={value => + onQDataChanged({ + 'ipConfiguration/ipv6Required': value + }) + } + value={dataMap['ipConfiguration/ipv6Required']} + /> + </GridItem> + </GridSection> + ); }; export default IpConfig; 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 06a2bb445c..5a89239dc6 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 @@ -20,40 +20,48 @@ 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, genericFieldInfo, isReadOnlyMode, name, description, isManual}) => { - - return ( - <GridSection hastLastColSet> - <GridItem colSpan={2}> - <Input - label={i18n('Name')} - value={name} - data-test-id='nic-name' - disabled={!isManual} - isRequired={true} - onChange={name => onDataChanged({name})} - isValid={genericFieldInfo['name'].isValid} - errorText={genericFieldInfo['name'].errorText} - type='text' /> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - label={i18n('Purpose of NIC')} - value={description} - data-test-id='nic-description' - onChange={description => onDataChanged({description})} - disabled={isReadOnlyMode} - type='textarea' /> - </GridItem> - </GridSection> - ); +const NameAndPurpose = ({ + onDataChanged, + genericFieldInfo, + isReadOnlyMode, + name, + description, + isManual +}) => { + return ( + <GridSection hastLastColSet> + <GridItem colSpan={2}> + <Input + label={i18n('Name')} + value={name} + data-test-id="nic-name" + disabled={!isManual} + isRequired={true} + onChange={name => onDataChanged({ name })} + isValid={genericFieldInfo['name'].isValid} + errorText={genericFieldInfo['name'].errorText} + type="text" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + label={i18n('Purpose of NIC')} + value={description} + data-test-id="nic-description" + onChange={description => onDataChanged({ description })} + disabled={isReadOnlyMode} + type="textarea" + /> + </GridItem> + </GridSection> + ); }; NameAndPurpose.PropTypes = { - name: PropTypes.string, - description: PropTypes.array, - onDataChanged: PropTypes.func, - isReadOnlyMode: PropTypes.bool, + name: PropTypes.string, + description: PropTypes.array, + onDataChanged: PropTypes.func, + isReadOnlyMode: PropTypes.bool }; export default NameAndPurpose; 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 7e6712cb5e..c440d2fbd3 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 @@ -21,56 +21,70 @@ import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; import { networkTypes } from '../SoftwareProductComponentsNetworkConstants.js'; -const Network = ({networkValues, networkType, networkDescription, onDataChanged, isReadOnlyMode}) => { - const isExternal = networkType === networkTypes.EXTERNAL; - return ( - <GridSection title={i18n('Network')} hasLastColSet> - <GridItem> - <Input - label={i18n('Internal')} - disabled - checked={!isExternal} - data-test-id='nic-internal' - className='network-radio disabled' - type='radio' /> - </GridItem> - <GridItem> - <Input - label={i18n('External')} - disabled - checked={isExternal} - data-test-id='nic-external' - className='network-radio disabled' - type='radio' /> - </GridItem> - <GridItem colSpan={2} lastColInRow> - { - 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' - type='select' - className='input-options-select' - groupClassName='bootstrap-input-options' - disabled={true}> - {networkValues.map(val => <option key={val.enum} value={val.enum}>{val.title}</option>)} - </Input> - } - </GridItem> - </GridSection> - ); +const Network = ({ + networkValues, + networkType, + networkDescription, + onDataChanged, + isReadOnlyMode +}) => { + const isExternal = networkType === networkTypes.EXTERNAL; + return ( + <GridSection title={i18n('Network')} hasLastColSet> + <GridItem> + <Input + label={i18n('Internal')} + disabled + checked={!isExternal} + data-test-id="nic-internal" + className="network-radio disabled" + type="radio" + /> + </GridItem> + <GridItem> + <Input + label={i18n('External')} + disabled + checked={isExternal} + data-test-id="nic-external" + className="network-radio disabled" + type="radio" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + {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" + type="select" + className="input-options-select" + groupClassName="bootstrap-input-options" + disabled={true}> + {networkValues.map(val => ( + <option key={val.enum} value={val.enum}> + {val.title} + </option> + ))} + </Input> + )} + </GridItem> + </GridSection> + ); }; Network.PropTypes = { - networkValues: PropTypes.array + networkValues: PropTypes.array }; -export default Network; +export default Network; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/OutFlowTraffic.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/OutFlowTraffic.jsx index 80a3d1579b..7173294536 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/OutFlowTraffic.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/OutFlowTraffic.jsx @@ -18,18 +18,20 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import PacketsBytes from './PacketsBytes.jsx'; const pointers = [ - {label: 'Peak', value: 'sizing/outflowTrafficPerSecond/packets/peak'}, - {label: 'Avg', value: 'sizing/outflowTrafficPerSecond/packets/avg'}, - {label: 'Peak', value: 'sizing/outflowTrafficPerSecond/bytes/peak'}, - {label: 'Avg', value: 'sizing/outflowTrafficPerSecond/bytes/avg'}, + { label: 'Peak', value: 'sizing/outflowTrafficPerSecond/packets/peak' }, + { label: 'Avg', value: 'sizing/outflowTrafficPerSecond/packets/avg' }, + { label: 'Peak', value: 'sizing/outflowTrafficPerSecond/bytes/peak' }, + { label: 'Avg', value: 'sizing/outflowTrafficPerSecond/bytes/avg' } ]; -const OutFlowTraffic = (props) => { - return( - <PacketsBytes {...props} title={i18n('Outflow Traffic per second')} pointers={pointers}/> - ); +const OutFlowTraffic = props => { + return ( + <PacketsBytes + {...props} + title={i18n('Outflow Traffic per second')} + pointers={pointers} + /> + ); }; export default OutFlowTraffic; - - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/PacketsBytes.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/PacketsBytes.jsx index f5f28aea59..070ac816ad 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/PacketsBytes.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/PacketsBytes.jsx @@ -20,47 +20,74 @@ 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 PointerInput = ({label, value, onQDataChanged, qgenericFieldInfo, dataMap, lastColInRow}) => { - return ( - <GridItem lastColInRow={lastColInRow}> - <Input - label={i18n(label)} - type='number' - data-test-id={`${value}`} - isValid={qgenericFieldInfo[value].isValid} - errorText={qgenericFieldInfo[value].errorText} - value={dataMap[value]} - onChange={val => onQDataChanged({[value]: val})} /> - </GridItem> - ); +const PointerInput = ({ + label, + value, + onQDataChanged, + qgenericFieldInfo, + dataMap, + lastColInRow +}) => { + return ( + <GridItem lastColInRow={lastColInRow}> + <Input + label={i18n(label)} + type="number" + data-test-id={`${value}`} + isValid={qgenericFieldInfo[value].isValid} + errorText={qgenericFieldInfo[value].errorText} + value={dataMap[value]} + onChange={val => onQDataChanged({ [value]: val })} + /> + </GridItem> + ); }; PointerInput.PropTypes = { - label: PropTypes.string, - value: PropTypes.string + label: PropTypes.string, + value: PropTypes.string }; -const PacketsBytes = ({title, pointers = [], qgenericFieldInfo, dataMap, onQDataChanged}) => { - return( - <GridSection title={title} hasLastColSet> - <GridItem colSpan={2}> - <div className='part-title-small packets'>{i18n('Packets')}</div> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <div className='part-title-small bytes'>{i18n('Bytes')}</div> - </GridItem> - {pointers.map((pointer, i) => {return (<PointerInput key={i} label={pointer.label} value={pointer.value} - qgenericFieldInfo={qgenericFieldInfo} onQDataChanged={onQDataChanged} dataMap={dataMap} lastColInRow={i === 3} />);})} - </GridSection> - ); +const PacketsBytes = ({ + title, + pointers = [], + qgenericFieldInfo, + dataMap, + onQDataChanged +}) => { + return ( + <GridSection title={title} hasLastColSet> + <GridItem colSpan={2}> + <div className="part-title-small packets"> + {i18n('Packets')} + </div> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <div className="part-title-small bytes">{i18n('Bytes')}</div> + </GridItem> + {pointers.map((pointer, i) => { + return ( + <PointerInput + key={i} + label={pointer.label} + value={pointer.value} + qgenericFieldInfo={qgenericFieldInfo} + onQDataChanged={onQDataChanged} + dataMap={dataMap} + lastColInRow={i === 3} + /> + ); + })} + </GridSection> + ); }; PacketsBytes.PropTypes = { - title: PropTypes.string, - pointers: PropTypes.array, - onQDataChanged: PropTypes.function, - dataMap: PropTypes.object, - qgenericFieldInfo: PropTypes.object + title: PropTypes.string, + pointers: PropTypes.array, + onQDataChanged: PropTypes.function, + dataMap: PropTypes.object, + qgenericFieldInfo: PropTypes.object }; export default PacketsBytes; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Protocols.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Protocols.jsx index be4093da59..eb762b11b2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Protocols.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Protocols.jsx @@ -21,55 +21,83 @@ import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; -const Protocols = ({protocols, qgenericFieldInfo, dataMap, onQDataChanged}) => { - return ( - <GridSection title={i18n('Protocols')} hasLastColSet> - <GridItem colSpan={2}> - <InputOptions - data-test-id='nic-protocols' - label={i18n('Protocols')} - type='select' - isMultiSelect={true} - isValid={qgenericFieldInfo['protocols/protocols'].isValid} - errorText={qgenericFieldInfo['protocols/protocols'].errorText} - onInputChange={()=>{}} - onEnumChange={protocols => { - onQDataChanged({'protocols/protocols' : protocols});} - } - multiSelectedEnum={dataMap['protocols/protocols']} - clearable={false} - values={qgenericFieldInfo['protocols/protocols'].enum}/> - </GridItem> - <GridItem colSpan={2} lastColInRow> - <Input - data-test-id='nic-protocolWithHighestTrafficProfile' - label={i18n('Protocol with Highest Traffic Profile')} - type='select' - groupClassName='bootstrap-input-options' - className='input-options-select' - isValid={qgenericFieldInfo['protocols/protocolWithHighestTrafficProfile'].isValid} - errorText={qgenericFieldInfo['protocols/protocolWithHighestTrafficProfile'].errorText} - value={dataMap['protocols/protocolWithHighestTrafficProfile']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'protocols/protocolWithHighestTrafficProfile' : val});} - }> - {(protocols.length === 0) && - <option key={'You must select protocols first...'} value=''>{i18n('You must select protocols first...')}</option> - } - {protocols.map(protocol => <option key={protocol} value={protocol}>{protocol}</option>)} - </Input> - </GridItem> - </GridSection> - ); +const Protocols = ({ + protocols, + qgenericFieldInfo, + dataMap, + onQDataChanged +}) => { + return ( + <GridSection title={i18n('Protocols')} hasLastColSet> + <GridItem colSpan={2}> + <InputOptions + data-test-id="nic-protocols" + label={i18n('Protocols')} + type="select" + isMultiSelect={true} + isValid={qgenericFieldInfo['protocols/protocols'].isValid} + errorText={ + qgenericFieldInfo['protocols/protocols'].errorText + } + onInputChange={() => {}} + onEnumChange={protocols => { + onQDataChanged({ 'protocols/protocols': protocols }); + }} + multiSelectedEnum={dataMap['protocols/protocols']} + clearable={false} + values={qgenericFieldInfo['protocols/protocols'].enum} + /> + </GridItem> + <GridItem colSpan={2} lastColInRow> + <Input + data-test-id="nic-protocolWithHighestTrafficProfile" + label={i18n('Protocol with Highest Traffic Profile')} + type="select" + groupClassName="bootstrap-input-options" + className="input-options-select" + isValid={ + qgenericFieldInfo[ + 'protocols/protocolWithHighestTrafficProfile' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'protocols/protocolWithHighestTrafficProfile' + ].errorText + } + value={ + dataMap['protocols/protocolWithHighestTrafficProfile'] + } + onChange={e => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({ + 'protocols/protocolWithHighestTrafficProfile': val + }); + }}> + {protocols.length === 0 && ( + <option + key={'You must select protocols first...'} + value=""> + {i18n('You must select protocols first...')} + </option> + )} + {protocols.map(protocol => ( + <option key={protocol} value={protocol}> + {protocol} + </option> + ))} + </Input> + </GridItem> + </GridSection> + ); }; Protocols.PropTypes = { - protocols: PropTypes.array, - onQDataChanged: PropTypes.function, - dataMap: PropTypes.object, - qgenericFieldInfo: PropTypes.object + protocols: PropTypes.array, + onQDataChanged: PropTypes.function, + dataMap: PropTypes.object, + qgenericFieldInfo: PropTypes.object }; export default Protocols; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Sizing.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Sizing.jsx index 202d458f25..f9ec7261ac 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Sizing.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/network/nicEditorComponents/Sizing.jsx @@ -19,21 +19,32 @@ 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 Sizing = ({qgenericFieldInfo, dataMap, onQDataChanged}) => { - return( - <GridSection title={i18n('Sizing')} hasLastColSet> - <GridItem colSpan={4} lastColInRow> - <Input - label={i18n('Describe Quality of Service')} - type='textarea' - data-test-id='sizing-describeQualityOfService' - isValid={qgenericFieldInfo['sizing/describeQualityOfService'].isValid} - errorText={qgenericFieldInfo['sizing/describeQualityOfService'].errorText} - value={dataMap['sizing/describeQualityOfService']} - onChange={val => onQDataChanged({'sizing/describeQualityOfService' : val}) }/> - </GridItem> - </GridSection> - ); +const Sizing = ({ qgenericFieldInfo, dataMap, onQDataChanged }) => { + return ( + <GridSection title={i18n('Sizing')} hasLastColSet> + <GridItem colSpan={4} lastColInRow> + <Input + label={i18n('Describe Quality of Service')} + type="textarea" + data-test-id="sizing-describeQualityOfService" + isValid={ + qgenericFieldInfo['sizing/describeQualityOfService'] + .isValid + } + errorText={ + qgenericFieldInfo['sizing/describeQualityOfService'] + .errorText + } + value={dataMap['sizing/describeQualityOfService']} + onChange={val => + onQDataChanged({ + 'sizing/describeQualityOfService': val + }) + } + /> + </GridItem> + </GridSection> + ); }; export default Sizing; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js index b2133ad5d8..52c5cdde3d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesActionHelper.js @@ -15,121 +15,184 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './SoftwareProductComponentProcessesConstants.js'; +import { actionTypes } from './SoftwareProductComponentProcessesConstants.js'; function baseUrl(softwareProductId, version, componentId) { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${version.id}/components/${componentId}/processes`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${ + version.id + }/components/${componentId}/processes`; } -function fetchProcessesList({softwareProductId, version, componentId}) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version, componentId)}`); +function fetchProcessesList({ softwareProductId, version, componentId }) { + return RestAPIUtil.fetch( + `${baseUrl(softwareProductId, version, componentId)}` + ); } -function deleteProcess({softwareProductId, version, componentId, processId}) { - return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version, componentId)}/${processId}`); +function deleteProcess({ softwareProductId, version, componentId, processId }) { + return RestAPIUtil.destroy( + `${baseUrl(softwareProductId, version, componentId)}/${processId}` + ); } -function putProcess({softwareProductId, version, componentId, process}) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version, componentId)}/${process.id}`, { - name: process.name, - description: process.description, - type: process.type === '' ? null : process.type - }); +function putProcess({ softwareProductId, version, componentId, process }) { + return RestAPIUtil.put( + `${baseUrl(softwareProductId, version, componentId)}/${process.id}`, + { + name: process.name, + description: process.description, + type: process.type === '' ? null : process.type + } + ); } -function postProcess({softwareProductId, version, componentId, process}) { - return RestAPIUtil.post(`${baseUrl(softwareProductId, version, componentId)}`, { - name: process.name, - description: process.description, - type: process.type === '' ? null : process.type - }); +function postProcess({ softwareProductId, version, componentId, process }) { + return RestAPIUtil.post( + `${baseUrl(softwareProductId, version, componentId)}`, + { + name: process.name, + description: process.description, + type: process.type === '' ? null : process.type + } + ); } -function uploadFileToProcess({softwareProductId, version, processId, componentId, formData}) { - return RestAPIUtil.post(`${baseUrl(softwareProductId, version, componentId)}/${processId}/upload`, formData); +function uploadFileToProcess({ + softwareProductId, + version, + processId, + componentId, + formData +}) { + return RestAPIUtil.post( + `${baseUrl( + softwareProductId, + version, + componentId + )}/${processId}/upload`, + formData + ); } - - const SoftwareProductComponentProcessesActionHelper = { - fetchProcessesList(dispatch, {softwareProductId, version, componentId}) { - dispatch({ - type: actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES, - processesList: [] - }); - - return fetchProcessesList({softwareProductId, version, componentId}).then(response => { - dispatch({ - type: actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES, - processesList: response.results - }); - }); - }, - - deleteProcess(dispatch, {process, softwareProductId, version, componentId}) { - return deleteProcess({softwareProductId, version, processId:process.id, componentId}).then(() => { - dispatch({ - type: actionTypes.DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, - processId: process.id - }); - }); - - }, - - saveProcess(dispatch, {softwareProductId, version, componentId, previousProcess, process}) { - if (previousProcess) { - return putProcess({softwareProductId, version, componentId, process}).then(() => { - if (process.formData && process.formData.name !== previousProcess.artifactName){ - uploadFileToProcess({softwareProductId, version, processId: process.id, formData: process.formData, componentId}); - } - dispatch({ - type: actionTypes.EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, - process - }); - }); - } - else { - return postProcess({softwareProductId, version, componentId, process}).then(response => { - if (process.formData) { - uploadFileToProcess({softwareProductId, version, processId: response.value, formData: process.formData, componentId}); - } - dispatch({ - type: actionTypes.ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, - process: { - ...process, - id: response.value - } - }); - }); - } - }, - - hideDeleteConfirm(dispatch) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM, - processToDelete: false - }); - }, - - openDeleteProcessesConfirm(dispatch, {process} ) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM, - processToDelete: process - }); - }, - - openEditor(dispatch, process = {}) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN, - process - }); - }, - closeEditor(dispatch) { - dispatch({ - type:actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE - }); - } + fetchProcessesList(dispatch, { softwareProductId, version, componentId }) { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES, + processesList: [] + }); + + return fetchProcessesList({ + softwareProductId, + version, + componentId + }).then(response => { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES, + processesList: response.results + }); + }); + }, + + deleteProcess( + dispatch, + { process, softwareProductId, version, componentId } + ) { + return deleteProcess({ + softwareProductId, + version, + processId: process.id, + componentId + }).then(() => { + dispatch({ + type: actionTypes.DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, + processId: process.id + }); + }); + }, + + saveProcess( + dispatch, + { softwareProductId, version, componentId, previousProcess, process } + ) { + if (previousProcess) { + return putProcess({ + softwareProductId, + version, + componentId, + process + }).then(() => { + if ( + process.formData && + process.formData.name !== previousProcess.artifactName + ) { + uploadFileToProcess({ + softwareProductId, + version, + processId: process.id, + formData: process.formData, + componentId + }); + } + dispatch({ + type: actionTypes.EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, + process + }); + }); + } else { + return postProcess({ + softwareProductId, + version, + componentId, + process + }).then(response => { + if (process.formData) { + uploadFileToProcess({ + softwareProductId, + version, + processId: response.value, + formData: process.formData, + componentId + }); + } + dispatch({ + type: actionTypes.ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS, + process: { + ...process, + id: response.value + } + }); + }); + } + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: + actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM, + processToDelete: false + }); + }, + + openDeleteProcessesConfirm(dispatch, { process }) { + dispatch({ + type: + actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM, + processToDelete: process + }); + }, + + openEditor(dispatch, process = {}) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN, + process + }); + }, + closeEditor(dispatch) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE + }); + } }; export default SoftwareProductComponentProcessesActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js index d15432b3fb..e3ce4f8007 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesConstants.js @@ -16,21 +16,22 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, - EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, - DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, - SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN: null, - SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE: null, - FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES: null, - SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM: null + ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, + EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, + DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: null, + SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN: null, + SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE: null, + FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES: null, + SOFTWARE_PRODUCT_PROCESS_DELETE_COMPONENTS_CONFIRM: null }); export const optionsInputValues = { - PROCESS_TYPE: [ - {title: 'Select...', enum: ''}, - {title: 'Lifecycle Operations', enum: 'Lifecycle_Operations'}, - {title: 'Other', enum: 'Other'} - ] + PROCESS_TYPE: [ + { title: 'Select...', enum: '' }, + { title: 'Lifecycle Operations', enum: 'Lifecycle_Operations' }, + { title: 'Other', enum: 'Other' } + ] }; -export const SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM = 'SOFTWAREPRODUCTPROCESSCOMPONENTSEDITORFORM'; +export const SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM = + 'SOFTWAREPRODUCTPROCESSCOMPONENTSEDITORFORM'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditor.js index 9502e24b1a..9d2bf34b78 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditor.js @@ -13,44 +13,68 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import SoftwareProductComponentProcessesActionHelper from './SoftwareProductComponentProcessesActionHelper'; import SoftwareProductComponentProcessesEditorView from './SoftwareProductComponentProcessesEditorView.jsx'; -import {SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM} from './SoftwareProductComponentProcessesConstants.js'; +import { SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM } from './SoftwareProductComponentProcessesConstants.js'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductComponents: {componentProcesses = {}}} = softwareProduct; - let {processesList = [], processesEditor = {}} = componentProcesses; - let {data, genericFieldInfo, formReady} = processesEditor; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductComponents: { componentProcesses = {} } + } = softwareProduct; + let { processesList = [], processesEditor = {} } = componentProcesses; + let { data, genericFieldInfo, formReady } = processesEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let previousData; - const processId = data ? data.id : null; - if(processId) { - previousData = processesList.find(process => process.id === processId); - } + let previousData; + const processId = data ? data.id : null; + if (processId) { + previousData = processesList.find(process => process.id === processId); + } - return { - data, - genericFieldInfo, - previousData, - isFormValid, - formReady - }; + return { + data, + genericFieldInfo, + previousData, + isFormValid, + formReady + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version, componentId}) => { - - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM}), - onCancel: () => SoftwareProductComponentProcessesActionHelper.closeEditor(dispatch), - onSubmit: ({previousProcess, process}) => { - SoftwareProductComponentProcessesActionHelper.closeEditor(dispatch); - SoftwareProductComponentProcessesActionHelper.saveProcess(dispatch, {softwareProductId, version, previousProcess, componentId, process}); - }, - onValidateForm: () => ValidationHelper.validateForm(dispatch, SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM) - }; +const mapActionsToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM + }), + onCancel: () => + SoftwareProductComponentProcessesActionHelper.closeEditor(dispatch), + onSubmit: ({ previousProcess, process }) => { + SoftwareProductComponentProcessesActionHelper.closeEditor(dispatch); + SoftwareProductComponentProcessesActionHelper.saveProcess( + dispatch, + { + softwareProductId, + version, + previousProcess, + componentId, + process + } + ); + }, + onValidateForm: () => + ValidationHelper.validateForm( + dispatch, + SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM + ) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductComponentProcessesEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + SoftwareProductComponentProcessesEditorView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorReducer.js index 9afaa6d5fd..fd211734df 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorReducer.js @@ -13,42 +13,48 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM} from './SoftwareProductComponentProcessesConstants.js'; +import { + actionTypes, + SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM +} from './SoftwareProductComponentProcessesConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN: - return { - ...state, - formReady: null, - formName: SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM, - genericFieldInfo: { - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}] - }, - 'artifactName' : { - isValid: true, - errorText: '', - validations: [] - }, - 'type' : { - isValid: true, - errorText: '', - validations: [] - } - }, - data: action.process - }; - case actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_OPEN: + return { + ...state, + formReady: null, + formName: SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_FORM, + genericFieldInfo: { + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }] + }, + artifactName: { + isValid: true, + errorText: '', + validations: [] + }, + type: { + isValid: true, + errorText: '', + validations: [] + } + }, + data: action.process + }; + case actionTypes.SOFTWARE_PRODUCT_PROCESS_COMPONENTS_EDITOR_CLOSE: + return {}; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorView.jsx index 9841ecbae7..132ebe86fb 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesEditorView.jsx @@ -14,17 +14,18 @@ * permissions and limitations under the License. */ import React from 'react'; -import {optionsInputValues as ComponentProcessesOptionsInputValues} from './SoftwareProductComponentProcessesConstants.js'; +import { optionsInputValues as ComponentProcessesOptionsInputValues } from './SoftwareProductComponentProcessesConstants.js'; import SoftwareProductProcessesEditorForm from 'sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorForm.jsx'; - class SoftwareProductProcessesEditorView extends React.Component { - - render() { - return ( - <SoftwareProductProcessesEditorForm optionsInputValues={ComponentProcessesOptionsInputValues} {...this.props}/> - ); - } + render() { + return ( + <SoftwareProductProcessesEditorForm + optionsInputValues={ComponentProcessesOptionsInputValues} + {...this.props} + /> + ); + } } export default SoftwareProductProcessesEditorView; 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 2a7152ef8b..cb6d25a6ac 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 @@ -13,45 +13,64 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import SoftwareProductComponentProcessesActionHelper from './SoftwareProductComponentProcessesActionHelper.js'; import SoftwareProductComponentsProcessesListView from './SoftwareProductComponentsProcessesListView.jsx'; -export const mapStateToProps = ({softwareProduct}) => { - - let {softwareProductEditor: {data:currentSoftwareProduct = {}, isValidityData = true}, softwareProductComponents: {componentProcesses = {}}} = softwareProduct; - let{processesList = [], processesEditor = {}} = componentProcesses; - let {data} = processesEditor; - - return { - currentSoftwareProduct, - isValidityData, - processesList, - isDisplayModal: Boolean(data), - isModalInEditMode: Boolean(data && data.id) - }; +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct = {}, + isValidityData = true + }, + softwareProductComponents: { componentProcesses = {} } + } = softwareProduct; + let { processesList = [], processesEditor = {} } = componentProcesses; + let { data } = processesEditor; + return { + currentSoftwareProduct, + isValidityData, + processesList, + isDisplayModal: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; }; -const mapActionsToProps = (dispatch, {componentId, softwareProductId, version}) => { - - return { - onAddProcess: () => SoftwareProductComponentProcessesActionHelper.openEditor(dispatch), - onEditProcess: (process) => SoftwareProductComponentProcessesActionHelper.openEditor(dispatch, process), - onDeleteProcess: (process) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=> SoftwareProductComponentProcessesActionHelper.deleteProcess(dispatch, - {process, softwareProductId, version, componentId}) - } - }) - }; +const mapActionsToProps = ( + dispatch, + { componentId, softwareProductId, version } +) => { + return { + onAddProcess: () => + SoftwareProductComponentProcessesActionHelper.openEditor(dispatch), + onEditProcess: process => + SoftwareProductComponentProcessesActionHelper.openEditor( + dispatch, + process + ), + onDeleteProcess: process => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete "{name}"?', { + name: process.name + }), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + SoftwareProductComponentProcessesActionHelper.deleteProcess( + dispatch, + { process, softwareProductId, version, componentId } + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductComponentsProcessesListView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductComponentsProcessesListView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesListReducer.js index 98e24a9c21..d406f02c19 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/processes/SoftwareProductComponentProcessesListReducer.js @@ -13,20 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductComponentProcessesConstants.js'; +import { actionTypes } from './SoftwareProductComponentProcessesConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES: - return [...action.processesList]; - case actionTypes.EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: - const indexForEdit = state.findIndex(process => process.id === action.process.id); - return [...state.slice(0, indexForEdit), action.process, ...state.slice(indexForEdit + 1)]; - case actionTypes.ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: - return [...state, action.process]; - case actionTypes.DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: - return state.filter(process => process.id !== action.processId); - default: - return state; - } + switch (action.type) { + case actionTypes.FETCH_SOFTWARE_PRODUCT_COMPONENTS_PROCESSES: + return [...action.processesList]; + case actionTypes.EDIT_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: + const indexForEdit = state.findIndex( + process => process.id === action.process.id + ); + return [ + ...state.slice(0, indexForEdit), + action.process, + ...state.slice(indexForEdit + 1) + ]; + case actionTypes.ADD_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: + return [...state, action.process]; + case actionTypes.DELETE_SOFTWARE_PRODUCT_COMPONENTS_PROCESS: + return state.filter(process => process.id !== action.processId); + default: + return state; + } }; 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 27c4b9f429..8fa2bffb27 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 @@ -21,55 +21,73 @@ import SoftwareProductProcessesEditor from './SoftwareProductComponentProcessesE import SoftwareProductProcessListView from 'sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessListView.jsx'; class SoftwareProductProcessesView extends React.Component { + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; + static propTypes = { + onAddProcess: PropTypes.func, + onEditProcess: PropTypes.func, + onDeleteProcess: PropTypes.func, + isDisplayModal: PropTypes.bool, + isModalInEditMode: PropTypes.bool, + onStorageSelect: PropTypes.func, + componentId: PropTypes.string, + softwareProductId: PropTypes.string, + currentSoftwareProduct: PropTypes.object + }; - static propTypes = { - onAddProcess: PropTypes.func, - onEditProcess: PropTypes.func, - onDeleteProcess: PropTypes.func, - isDisplayModal: PropTypes.bool, - isModalInEditMode: PropTypes.bool, - onStorageSelect: PropTypes.func, - componentId: PropTypes.string, - softwareProductId: PropTypes.string, - currentSoftwareProduct: PropTypes.object - }; - - render() { - return ( - <div className='vsp-processes-page'> - <div className='software-product-view'> - <div className='software-product-landing-view-right-side vsp-components-processes-page flex-column'> - {this.renderEditor()} - <SoftwareProductProcessListView addButtonTitle={i18n('Add Component Process Details')} {...this.props}/> - </div> - </div> - </div> - ); - } - - renderEditor() { - let {softwareProductId, version, componentId, isReadOnlyMode, isDisplayModal, isModalInEditMode} = this.props; - return ( - <Modal show={isDisplayModal} bsSize='large' animation={true} className='onborading-modal'> - <Modal.Header> - <Modal.Title>{isModalInEditMode ? i18n('Edit Process Details') : i18n('Create New Process Details')}</Modal.Title> - </Modal.Header> - <Modal.Body className='edit-process-modal'> - <SoftwareProductProcessesEditor - componentId={componentId} - softwareProductId={softwareProductId} - version={version} - isReadOnlyMode={isReadOnlyMode}/> - </Modal.Body> - </Modal> - - ); - } + render() { + return ( + <div className="vsp-processes-page"> + <div className="software-product-view"> + <div className="software-product-landing-view-right-side vsp-components-processes-page flex-column"> + {this.renderEditor()} + <SoftwareProductProcessListView + addButtonTitle={i18n( + 'Add Component Process Details' + )} + {...this.props} + /> + </div> + </div> + </div> + ); + } + renderEditor() { + let { + softwareProductId, + version, + componentId, + isReadOnlyMode, + isDisplayModal, + isModalInEditMode + } = this.props; + return ( + <Modal + show={isDisplayModal} + bsSize="large" + animation={true} + className="onborading-modal"> + <Modal.Header> + <Modal.Title> + {isModalInEditMode + ? i18n('Edit Process Details') + : i18n('Create New Process Details')} + </Modal.Title> + </Modal.Header> + <Modal.Body className="edit-process-modal"> + <SoftwareProductProcessesEditor + componentId={componentId} + softwareProductId={softwareProductId} + version={version} + isReadOnlyMode={isReadOnlyMode} + /> + </Modal.Body> + </Modal> + ); + } } export default SoftwareProductProcessesView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorage.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorage.js index ca27a76a18..8da9b99a33 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorage.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorage.js @@ -13,32 +13,57 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import SoftwareProductComponentsActionHelper from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponentsActionHelper.js'; import SoftwareProductComponentStorageView from './SoftwareProductComponentStorageView.jsx'; -import {COMPONENTS_QUESTIONNAIRE} from '../SoftwareProductComponentsConstants.js'; +import { COMPONENTS_QUESTIONNAIRE } from '../SoftwareProductComponentsConstants.js'; -const mapStateToProps = ({softwareProduct: {softwareProductComponents}}) => { - let {componentEditor: {qdata, qgenericFieldInfo : qGenericFieldInfo, dataMap}} = softwareProductComponents; +const mapStateToProps = ({ + softwareProduct: { softwareProductComponents } +}) => { + let { + componentEditor: { + qdata, + qgenericFieldInfo: qGenericFieldInfo, + dataMap + } + } = softwareProductComponents; - return { - qdata, - qGenericFieldInfo, - dataMap - }; + return { + qdata, + qGenericFieldInfo, + dataMap + }; }; -const mapActionToProps = (dispatch, {softwareProductId, version, componentId}) => { - return { - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: COMPONENTS_QUESTIONNAIRE}), - onSubmit: ({qdata}) => { - return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire(dispatch, {softwareProductId, version, vspComponentId: componentId, qdata}); - } - }; +const mapActionToProps = ( + dispatch, + { softwareProductId, version, componentId } +) => { + return { + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: COMPONENTS_QUESTIONNAIRE + }), + onSubmit: ({ qdata }) => { + return SoftwareProductComponentsActionHelper.updateSoftwareProductComponentQuestionnaire( + dispatch, + { + softwareProductId, + version, + vspComponentId: componentId, + qdata + } + ); + } + }; }; -export default connect(mapStateToProps, mapActionToProps, null, {withRef: true}) (SoftwareProductComponentStorageView); +export default connect(mapStateToProps, mapActionToProps, null, { + withRef: true +})(SoftwareProductComponentStorageView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorageView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorageView.jsx index 8538dab6bc..ac7e4a8053 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorageView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/components/storage/SoftwareProductComponentStorageView.jsx @@ -22,171 +22,311 @@ import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; import classnames from 'classnames'; -const BackupSection = ({isReadOnlyMode,dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Backup')}> - <GridItem> - <div className='vertical-flex'> - <label key='label' className={classnames('control-label',{'disabled': isReadOnlyMode})}>{i18n('Backup Type')}</label> - <div className='radio-options-content-row'> - {qgenericFieldInfo['storage/backup/backupType'].enum.map(onSite => ( - <Input - data-test-id='backupType' - type='radio' - key={onSite.enum} - name={'compute/guestOS/bitSize'} - className='radio-field' - value={onSite.enum} - label={onSite.title} - onChange={(site) => onQDataChanged({'storage/backup/backupType' : site})} - isValid={qgenericFieldInfo['storage/backup/backupType'].isValid} - errorText={qgenericFieldInfo['storage/backup/backupType'].errorText} - checked={dataMap['storage/backup/backupType'] === onSite.enum} /> )) } - </div> - </div> - </GridItem> - <GridItem> - <Input - className='section-field' - data-test-id='backupSolution' - onChange={(backupSolution) => onQDataChanged({'storage/backup/backupSolution' : backupSolution})} - label={i18n('Backup Solution')} - type='text' - isValid={qgenericFieldInfo['storage/backup/backupSolution'].isValid} - errorText={qgenericFieldInfo['storage/backup/backupSolution'].errorText} - value={dataMap['storage/backup/backupSolution']}/> - </GridItem> - <GridItem> - <Input - className='section-field' - data-test-id='backupStorageSize' - onChange={(backupStorageSize) => onQDataChanged({'storage/backup/backupStorageSize' : backupStorageSize})} - label={i18n('Backup Storage Size (GB)')} - type='number' - isValid={qgenericFieldInfo['storage/backup/backupStorageSize'].isValid} - errorText={qgenericFieldInfo['storage/backup/backupStorageSize'].errorText} - value={dataMap['storage/backup/backupStorageSize']}/> - </GridItem> - <GridItem> - <Input - data-test-id='backupNIC' - label={i18n('Backup NIC')} - type='select' - className='input-options-select section-field' - groupClassName='bootstrap-input-options' - isValid={qgenericFieldInfo['storage/backup/backupNIC'].isValid} - errorText={qgenericFieldInfo['storage/backup/backupNIC'].errorText} - value={dataMap['storage/backup/backupNIC']} - onChange={(e) => { - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onQDataChanged({'storage/backup/backupNIC' : val});} - }> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {qgenericFieldInfo['storage/backup/backupNIC'].enum.map(hv => <option value={hv.enum} key={hv.enum}>{hv.title}</option>)} - </Input> - </GridItem> - </GridSection> +const BackupSection = ({ + isReadOnlyMode, + dataMap, + onQDataChanged, + qgenericFieldInfo +}) => ( + <GridSection title={i18n('Backup')}> + <GridItem> + <div className="vertical-flex"> + <label + key="label" + className={classnames('control-label', { + disabled: isReadOnlyMode + })}> + {i18n('Backup Type')} + </label> + <div className="radio-options-content-row"> + {qgenericFieldInfo['storage/backup/backupType'].enum.map( + onSite => ( + <Input + data-test-id="backupType" + type="radio" + key={onSite.enum} + name={'compute/guestOS/bitSize'} + className="radio-field" + value={onSite.enum} + label={onSite.title} + onChange={site => + onQDataChanged({ + 'storage/backup/backupType': site + }) + } + isValid={ + qgenericFieldInfo[ + 'storage/backup/backupType' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'storage/backup/backupType' + ].errorText + } + checked={ + dataMap['storage/backup/backupType'] === + onSite.enum + } + /> + ) + )} + </div> + </div> + </GridItem> + <GridItem> + <Input + className="section-field" + data-test-id="backupSolution" + onChange={backupSolution => + onQDataChanged({ + 'storage/backup/backupSolution': backupSolution + }) + } + label={i18n('Backup Solution')} + type="text" + isValid={ + qgenericFieldInfo['storage/backup/backupSolution'].isValid + } + errorText={ + qgenericFieldInfo['storage/backup/backupSolution'].errorText + } + value={dataMap['storage/backup/backupSolution']} + /> + </GridItem> + <GridItem> + <Input + className="section-field" + data-test-id="backupStorageSize" + onChange={backupStorageSize => + onQDataChanged({ + 'storage/backup/backupStorageSize': backupStorageSize + }) + } + label={i18n('Backup Storage Size (GB)')} + type="number" + isValid={ + qgenericFieldInfo['storage/backup/backupStorageSize'] + .isValid + } + errorText={ + qgenericFieldInfo['storage/backup/backupStorageSize'] + .errorText + } + value={dataMap['storage/backup/backupStorageSize']} + /> + </GridItem> + <GridItem> + <Input + data-test-id="backupNIC" + label={i18n('Backup NIC')} + type="select" + className="input-options-select section-field" + groupClassName="bootstrap-input-options" + isValid={qgenericFieldInfo['storage/backup/backupNIC'].isValid} + errorText={ + qgenericFieldInfo['storage/backup/backupNIC'].errorText + } + value={dataMap['storage/backup/backupNIC']} + onChange={e => { + const selectedIndex = e.target.selectedIndex; + const val = e.target.options[selectedIndex].value; + onQDataChanged({ 'storage/backup/backupNIC': val }); + }}> + <option key="placeholder" value=""> + {i18n('Select...')} + </option> + {qgenericFieldInfo['storage/backup/backupNIC'].enum.map(hv => ( + <option value={hv.enum} key={hv.enum}> + {hv.title} + </option> + ))} + </Input> + </GridItem> + </GridSection> ); -const SnapshotBackupSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Snapshot Backup')}> - <GridItem> - <Input - className='section-field' - data-test-id='snapshotFrequency' - onChange={(snapshotFrequency) => onQDataChanged({'storage/snapshotBackup/snapshotFrequency' : snapshotFrequency})} - label={i18n('Backup Storage Size (GB)')} - type='number' - isValid={qgenericFieldInfo['storage/snapshotBackup/snapshotFrequency'].isValid} - errorText={qgenericFieldInfo['storage/snapshotBackup/snapshotFrequency'].errorText} - value={dataMap['storage/snapshotBackup/snapshotFrequency']}/> - </GridItem> - </GridSection> +const SnapshotBackupSection = ({ + dataMap, + onQDataChanged, + qgenericFieldInfo +}) => ( + <GridSection title={i18n('Snapshot Backup')}> + <GridItem> + <Input + className="section-field" + data-test-id="snapshotFrequency" + onChange={snapshotFrequency => + onQDataChanged({ + 'storage/snapshotBackup/snapshotFrequency': snapshotFrequency + }) + } + label={i18n('Backup Storage Size (GB)')} + type="number" + isValid={ + qgenericFieldInfo[ + 'storage/snapshotBackup/snapshotFrequency' + ].isValid + } + errorText={ + qgenericFieldInfo[ + 'storage/snapshotBackup/snapshotFrequency' + ].errorText + } + value={dataMap['storage/snapshotBackup/snapshotFrequency']} + /> + </GridItem> + </GridSection> ); -const LogBackupSection = ({dataMap, onQDataChanged, qgenericFieldInfo}) => ( - <GridSection title={i18n('Log Backup')}> - <GridItem> - <Input - className='section-field' - data-test-id='sizeOfLogFiles' - onChange={(sizeOfLogFiles) => onQDataChanged({'storage/logBackup/sizeOfLogFiles' : sizeOfLogFiles})} - label={i18n('Backup Storage Size (GB)')} - type='number' - isValid={qgenericFieldInfo['storage/logBackup/sizeOfLogFiles'].isValid} - errorText={qgenericFieldInfo['storage/logBackup/sizeOfLogFiles'].errorText} - value={dataMap['storage/logBackup/sizeOfLogFiles']}/> - </GridItem> - <GridItem> - <Input - className='section-field' - label={i18n('Log Retention Period (days)')} - data-test-id='logRetentionPeriod' - onChange={(logRetentionPeriod) => onQDataChanged({'storage/logBackup/logRetentionPeriod' : logRetentionPeriod})} - type='number' - isValid={qgenericFieldInfo['storage/logBackup/logRetentionPeriod'].isValid} - errorText={qgenericFieldInfo['storage/logBackup/logRetentionPeriod'].errorText} - value={dataMap['storage/logBackup/logRetentionPeriod']}/> - </GridItem> - <GridItem> - <Input - className='section-field' - label={i18n('Log Backup Frequency (days)')} - data-test-id='logBackupFrequency' - onChange={(logBackupFrequency) => onQDataChanged({'storage/logBackup/logBackupFrequency' : logBackupFrequency})} - type='number' - isValid={qgenericFieldInfo['storage/logBackup/logBackupFrequency'].isValid} - errorText={qgenericFieldInfo['storage/logBackup/logBackupFrequency'].errorText} - value={dataMap['storage/logBackup/logBackupFrequency']}/> - </GridItem> - <GridItem> - <Input - className='section-field' - label={i18n('Log File Location')} - data-test-id='logFileLocation' - onChange={(logFileLocation) => onQDataChanged({'storage/logBackup/logFileLocation' : logFileLocation})} - type='text' - isValid={qgenericFieldInfo['storage/logBackup/logFileLocation'].isValid} - errorText={qgenericFieldInfo['storage/logBackup/logFileLocation'].errorText} - value={dataMap['storage/logBackup/logFileLocation']}/> - </GridItem> - </GridSection> +const LogBackupSection = ({ dataMap, onQDataChanged, qgenericFieldInfo }) => ( + <GridSection title={i18n('Log Backup')}> + <GridItem> + <Input + className="section-field" + data-test-id="sizeOfLogFiles" + onChange={sizeOfLogFiles => + onQDataChanged({ + 'storage/logBackup/sizeOfLogFiles': sizeOfLogFiles + }) + } + label={i18n('Backup Storage Size (GB)')} + type="number" + isValid={ + qgenericFieldInfo['storage/logBackup/sizeOfLogFiles'] + .isValid + } + errorText={ + qgenericFieldInfo['storage/logBackup/sizeOfLogFiles'] + .errorText + } + value={dataMap['storage/logBackup/sizeOfLogFiles']} + /> + </GridItem> + <GridItem> + <Input + className="section-field" + label={i18n('Log Retention Period (days)')} + data-test-id="logRetentionPeriod" + onChange={logRetentionPeriod => + onQDataChanged({ + 'storage/logBackup/logRetentionPeriod': logRetentionPeriod + }) + } + type="number" + isValid={ + qgenericFieldInfo['storage/logBackup/logRetentionPeriod'] + .isValid + } + errorText={ + qgenericFieldInfo['storage/logBackup/logRetentionPeriod'] + .errorText + } + value={dataMap['storage/logBackup/logRetentionPeriod']} + /> + </GridItem> + <GridItem> + <Input + className="section-field" + label={i18n('Log Backup Frequency (days)')} + data-test-id="logBackupFrequency" + onChange={logBackupFrequency => + onQDataChanged({ + 'storage/logBackup/logBackupFrequency': logBackupFrequency + }) + } + type="number" + isValid={ + qgenericFieldInfo['storage/logBackup/logBackupFrequency'] + .isValid + } + errorText={ + qgenericFieldInfo['storage/logBackup/logBackupFrequency'] + .errorText + } + value={dataMap['storage/logBackup/logBackupFrequency']} + /> + </GridItem> + <GridItem> + <Input + className="section-field" + label={i18n('Log File Location')} + data-test-id="logFileLocation" + onChange={logFileLocation => + onQDataChanged({ + 'storage/logBackup/logFileLocation': logFileLocation + }) + } + type="text" + isValid={ + qgenericFieldInfo['storage/logBackup/logFileLocation'] + .isValid + } + errorText={ + qgenericFieldInfo['storage/logBackup/logFileLocation'] + .errorText + } + value={dataMap['storage/logBackup/logFileLocation']} + /> + </GridItem> + </GridSection> ); class SoftwareProductComponentStorageView extends React.Component { + static propTypes = { + componentId: PropTypes.string, + onQDataChanged: PropTypes.func, + onSubmit: PropTypes.func, + isReadOnlyMode: PropTypes.bool + }; - static propTypes = { - componentId: PropTypes.string, - onQDataChanged: PropTypes.func, - onSubmit: PropTypes.func, - isReadOnlyMode: PropTypes.bool - }; + render() { + let { + onQDataChanged, + dataMap, + qGenericFieldInfo, + isReadOnlyMode, + onSubmit, + qdata + } = this.props; - render() { - let {onQDataChanged, dataMap, qGenericFieldInfo, isReadOnlyMode, onSubmit, qdata} = this.props; + return ( + <div className="vsp-component-questionnaire-view"> + {qGenericFieldInfo && ( + <Form + ref={form => (this.form = form)} + isValid={true} + formReady={null} + onSubmit={() => onSubmit({ qdata })} + className="component-questionnaire-validation-form" + isReadOnlyMode={isReadOnlyMode} + hasButtons={false}> + <BackupSection + isReadOnlyMode={isReadOnlyMode} + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <SnapshotBackupSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + <LogBackupSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + qgenericFieldInfo={qGenericFieldInfo} + /> + </Form> + )} + </div> + ); + } - return( - <div className='vsp-component-questionnaire-view'> - {qGenericFieldInfo && <Form - ref={form => this.form = form } - isValid={true} - formReady={null} - onSubmit={() => onSubmit({qdata})} - className='component-questionnaire-validation-form' - isReadOnlyMode={isReadOnlyMode} - hasButtons={false}> - <BackupSection isReadOnlyMode={isReadOnlyMode} onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <SnapshotBackupSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - <LogBackupSection onQDataChanged={onQDataChanged} dataMap={dataMap} qgenericFieldInfo={qGenericFieldInfo}/> - </Form> } - </div> - ); - } - - save(){ - const {qdata, onSubmit} = this.props; - return onSubmit({qdata}); - } + save() { + const { qdata, onSubmit } = this.props; + return onSubmit({ qdata }); + } } export default SoftwareProductComponentStorageView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js index 569b33f999..41584d94e2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreation.js @@ -13,64 +13,96 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductCreationActionHelper from './SoftwareProductCreationActionHelper.js'; import SoftwareProductCreationView from './SoftwareProductCreationView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import SoftwareProductActionHelper from '../SoftwareProductActionHelper.js'; +import SoftwareProductActionHelper from '../SoftwareProductActionHelper.js'; import VersionsPageActionHelper from 'sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js'; -import {itemTypes as versionItemTypes} from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; +import { itemTypes as versionItemTypes } from 'sdc-app/onboarding/versionsPage/VersionsPageConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; import PermissionsActionHelper from 'sdc-app/onboarding/permissions/PermissionsActionHelper.js'; -export const mapStateToProps = ({finalizedLicenseModelList, users: {usersList}, archivedSoftwareProductList, - softwareProductList, finalizedSoftwareProductList, softwareProduct: {softwareProductCreation, softwareProductCategories} }) => { - let {genericFieldInfo} = softwareProductCreation; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); +export const mapStateToProps = ({ + finalizedLicenseModelList, + users: { usersList }, + archivedSoftwareProductList, + softwareProductList, + finalizedSoftwareProductList, + softwareProduct: { softwareProductCreation, softwareProductCategories } +}) => { + let { genericFieldInfo } = softwareProductCreation; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let VSPNames = {}; - const allVspList = [...softwareProductList, ...finalizedSoftwareProductList, ...archivedSoftwareProductList]; - allVspList.map(item => { - VSPNames[item.name.toLowerCase()] = item.id; - }); - + let VSPNames = {}; + const allVspList = [ + ...softwareProductList, + ...finalizedSoftwareProductList, + ...archivedSoftwareProductList + ]; + allVspList.map(item => { + VSPNames[item.name.toLowerCase()] = item.id; + }); - return { - data: softwareProductCreation.data, - selectedVendorId: softwareProductCreation.selectedVendorId, - disableVendor: softwareProductCreation.disableVendor, - softwareProductCategories, - finalizedLicenseModelList, - isFormValid, - formReady: softwareProductCreation.formReady, - genericFieldInfo, - VSPNames, - usersList - }; + return { + data: softwareProductCreation.data, + selectedVendorId: softwareProductCreation.selectedVendorId, + disableVendor: softwareProductCreation.disableVendor, + softwareProductCategories, + finalizedLicenseModelList, + isFormValid, + formReady: softwareProductCreation.formReady, + genericFieldInfo, + VSPNames, + usersList + }; }; -export const mapActionsToProps = (dispatch) => { - return { - onDataChanged: (deltaData, formName, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName, customValidations}), - onCancel: () => SoftwareProductCreationActionHelper.resetData(dispatch), - onSubmit: (softwareProduct, usersList) => { - SoftwareProductCreationActionHelper.resetData(dispatch); - SoftwareProductCreationActionHelper.createSoftwareProduct(dispatch, {softwareProduct}).then(response => { - let {itemId, version} = response; - SoftwareProductActionHelper.fetchSoftwareProductList(dispatch).then(() => - PermissionsActionHelper.fetchItemUsers(dispatch, {itemId, allUsers: usersList}).then(() => - VersionsPageActionHelper.fetchVersions(dispatch, {itemType: versionItemTypes.SOFTWARE_PRODUCT, itemId}).then(() => - ScreensHelper.loadScreen(dispatch, {screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId: itemId, version}}) - ) - ) - ); - }); - }, - onValidateForm: (formName) => ValidationHelper.validateForm(dispatch, formName) - }; +export const mapActionsToProps = dispatch => { + return { + onDataChanged: (deltaData, formName, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName, + customValidations + }), + onCancel: () => SoftwareProductCreationActionHelper.resetData(dispatch), + onSubmit: (softwareProduct, usersList) => { + SoftwareProductCreationActionHelper.resetData(dispatch); + SoftwareProductCreationActionHelper.createSoftwareProduct( + dispatch, + { softwareProduct } + ).then(response => { + let { itemId, version } = response; + SoftwareProductActionHelper.fetchSoftwareProductList( + dispatch + ).then(() => + PermissionsActionHelper.fetchItemUsers(dispatch, { + itemId, + allUsers: usersList + }).then(() => + VersionsPageActionHelper.fetchVersions(dispatch, { + itemType: versionItemTypes.SOFTWARE_PRODUCT, + itemId + }).then(() => + ScreensHelper.loadScreen(dispatch, { + screen: + enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId: itemId, version } + }) + ) + ) + ); + }); + }, + onValidateForm: formName => + ValidationHelper.validateForm(dispatch, formName) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductCreationView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductCreationView); 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 b19e460497..1b1fd71fef 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationActionHelper.js @@ -17,68 +17,68 @@ 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, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes} from './SoftwareProductCreationConstants.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'; function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/`; } function createSoftwareProduct(softwareProduct) { - return RestAPIUtil.post(baseUrl(), { - ...softwareProduct, - icon: 'icon', - licensingData: {} - }); + return RestAPIUtil.post(baseUrl(), { + ...softwareProduct, + icon: 'icon', + licensingData: {} + }); } const SoftwareProductCreationActionHelper = { + open(dispatch, vendorId) { + SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch); + dispatch({ + type: actionTypes.OPEN, + selectedVendorId: vendorId + }); - open(dispatch, vendorId) { - SoftwareProductActionHelper.loadSoftwareProductAssociatedData(dispatch); - dispatch({ - type: actionTypes.OPEN, - selectedVendorId: vendorId - }); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: + modalContentMapper.SOFTWARE_PRODUCT_CREATION, + title: i18n('New Software Product'), + modalComponentProps: { + vendorId, + size: modalSizes.LARGE + } + } + }); + }, - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.SOFTWARE_PRODUCT_CREATION, - title: i18n('New Software Product'), - modalComponentProps: { - vendorId, - size: modalSizes.LARGE - } - } - }); + resetData(dispatch) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); - }, - - resetData(dispatch) { - - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - - dispatch({ - type: actionTypes.RESET_DATA - }); - }, - - createSoftwareProduct(dispatch, {softwareProduct}) { - return createSoftwareProduct(softwareProduct).then(result => { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_CREATED, - result - }); - return result; - }); - } + dispatch({ + type: actionTypes.RESET_DATA + }); + }, + createSoftwareProduct(dispatch, { softwareProduct }) { + return createSoftwareProduct(softwareProduct).then(result => { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_CREATED, + result + }); + return result; + }); + } }; export default SoftwareProductCreationActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js index b941c849cb..ad1034602a 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationConstants.js @@ -16,9 +16,9 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - OPEN: null, - RESET_DATA: null, - SOFTWARE_PRODUCT_CREATED: null + OPEN: null, + RESET_DATA: null, + SOFTWARE_PRODUCT_CREATED: null }); export const SP_CREATION_FORM_NAME = 'SPCREATIONFORM'; 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 a7db2b2357..5f70f18f75 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationReducer.js @@ -13,56 +13,70 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, SP_CREATION_FORM_NAME} from './SoftwareProductCreationConstants.js'; - +import { + actionTypes, + SP_CREATION_FORM_NAME +} from './SoftwareProductCreationConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.OPEN: - return { - ...state, - formName: SP_CREATION_FORM_NAME, - disableVendor: action.selectedVendorId ? true : false, - data: { - vendorId: action.selectedVendorId ? action.selectedVendorId : undefined - }, - genericFieldInfo: { - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'freeEnglishText', data: true}, {type: 'maxLength', data: 1000}, {type: 'required', data: true}] - }, - 'vendorId' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - 'subCategory' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - 'category' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - }, - 'name' : { - 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 - }; - case actionTypes.RESET_DATA: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.OPEN: + return { + ...state, + formName: SP_CREATION_FORM_NAME, + disableVendor: action.selectedVendorId ? true : false, + data: { + vendorId: action.selectedVendorId + ? action.selectedVendorId + : undefined + }, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [ + { type: 'freeEnglishText', data: true }, + { type: 'maxLength', data: 1000 }, + { type: 'required', data: true } + ] + }, + vendorId: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + subCategory: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + category: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + }, + name: { + 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 + }; + case actionTypes.RESET_DATA: + return {}; + default: + return state; + } }; 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 e491491f4d..e94087cc80 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/creation/SoftwareProductCreationView.jsx @@ -22,194 +22,308 @@ 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 { 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'; +import { onboardingMethod as onboardingMethodConst } from '../SoftwareProductConstants.js'; const SoftwareProductPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - category: PropTypes.string, - subCategory: PropTypes.string, - vendorId: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + category: PropTypes.string, + subCategory: PropTypes.string, + vendorId: PropTypes.string }); class SoftwareProductCreationView extends React.Component { + static propTypes = { + data: SoftwareProductPropType, + finalizedLicenseModelList: PropTypes.array, + softwareProductCategories: PropTypes.array, + VSPNames: PropTypes.object, + usersList: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; - static propTypes = { - data: SoftwareProductPropType, - finalizedLicenseModelList: PropTypes.array, - softwareProductCategories: PropTypes.array, - VSPNames: PropTypes.object, - usersList: PropTypes.array, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; - - render() { - let {softwareProductCategories, data = {}, onDataChanged, onCancel, genericFieldInfo, disableVendor} = this.props; - let {name, description, vendorId, subCategory, onboardingMethod} = data; - - const vendorList = this.getVendorList(); - return ( - <div className='software-product-creation-page'> - { genericFieldInfo && <Form - ref={(validationForm) => this.validationForm = validationForm} - hasButtons={true} - onSubmit={() => this.submit() } - onReset={() => onCancel() } - labledButtons={true} - isValid={this.props.isFormValid} - submitButtonText={i18n('Create')} - formReady={this.props.formReady} - onValidateForm={() => this.validate() }> - <GridSection hasLastColSet> - <GridItem colSpan='2'> - <Input - value={name} - label={i18n('Name')} - isRequired={true} - onChange={name => onDataChanged({name},SP_CREATION_FORM_NAME, {name: name => this.validateName(name)})} - isValid={genericFieldInfo.name.isValid} - errorText={genericFieldInfo.name.errorText} - type='text' - className='field-section' - data-test-id='new-vsp-name' /> - <Input - label={i18n('Vendor')} - type='select' - value={vendorId} - overlayPos='bottom' - isRequired={true} - disabled={disableVendor} - onChange={e => this.onSelectVendor(e)} - isValid={genericFieldInfo.vendorId.isValid} - errorText={genericFieldInfo.vendorId.errorText} - className='input-options-select' - groupClassName='bootstrap-input-options' - data-test-id='new-vsp-vendor' > - {vendorList.map(vendor => - <option key={vendor.title} value={vendor.enum}>{vendor.title}</option>)} - </Input> - <Input - label={i18n('Category')} - type='select' - value={subCategory} - isRequired={true} - onChange={e => this.onSelectSubCategory(e)} - isValid={genericFieldInfo.subCategory.isValid} - errorText={genericFieldInfo.subCategory.errorText} - className='input-options-select' - groupClassName='bootstrap-input-options' - data-test-id='new-vsp-category' > - <option key='' value=''>{i18n('please select…')}</option> - {softwareProductCategories.map(category => - category.subcategories && - <optgroup - key={category.name} - label={category.name}>{category.subcategories.map(sub => - <option key={sub.uniqueId} value={sub.uniqueId}>{`${sub.name} (${category.name})`}</option>)} - </optgroup>) - } - </Input> - </GridItem> - <GridItem colSpan='2' stretch lastColInRow> - <Input - value={description} - label={i18n('Description')} - isRequired={true} - overlayPos='bottom' - onChange={description => onDataChanged({description},SP_CREATION_FORM_NAME)} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - type='textarea' - className='field-section' - data-test-id='new-vsp-description'/> - </GridItem> - </GridSection> - <OnboardingProcedure genericFieldInfo={genericFieldInfo} onboardingMethod={onboardingMethod} onDataChanged={onDataChanged} /> - </Form>} - </div> - ); - } - - getVendorList() { - let {finalizedLicenseModelList} = this.props; - - return [{enum: '', title: i18n('please select...')}].concat( - sortByStringProperty(finalizedLicenseModelList, 'name').map(vendor => { - return { - enum: vendor.id, - title: vendor.name - }; - }) - ); - } - - onSelectVendor(e) { - const selectedIndex = e.target.selectedIndex; - const vendorId = e.target.options[selectedIndex].value; - this.props.onDataChanged({vendorId},SP_CREATION_FORM_NAME); - } - - onSelectSubCategory(e) { - const selectedIndex = e.target.selectedIndex; - const subCategory = e.target.options[selectedIndex].value; - let {softwareProductCategories, onDataChanged} = this.props; - let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory(subCategory, softwareProductCategories); - onDataChanged({category, subCategory},SP_CREATION_FORM_NAME); - } - - submit() { - let {data:softwareProduct, finalizedLicenseModelList, usersList} = this.props; - softwareProduct.vendorName = finalizedLicenseModelList.find(vendor => vendor.id === softwareProduct.vendorId).name; - this.props.onSubmit(softwareProduct, usersList); - } - - validateName(value) { - const {data: {id}, VSPNames} = this.props; - const isExists = Validator.isItemNameAlreadyExistsInList({itemId: id, itemName: value, list: VSPNames}); - - return !isExists ? {isValid: true, errorText: ''} : - {isValid: false, errorText: i18n('Software product by the name \'' + value + '\' already exists. Software product name must be unique')}; - } - - validate() { - this.props.onValidateForm(SP_CREATION_FORM_NAME); - } + render() { + let { + softwareProductCategories, + data = {}, + onDataChanged, + onCancel, + genericFieldInfo, + disableVendor + } = this.props; + let { + name, + description, + vendorId, + subCategory, + onboardingMethod + } = data; + + const vendorList = this.getVendorList(); + return ( + <div className="software-product-creation-page"> + {genericFieldInfo && ( + <Form + ref={validationForm => + (this.validationForm = validationForm) + } + hasButtons={true} + onSubmit={() => this.submit()} + onReset={() => onCancel()} + labledButtons={true} + isValid={this.props.isFormValid} + submitButtonText={i18n('Create')} + formReady={this.props.formReady} + onValidateForm={() => this.validate()}> + <GridSection hasLastColSet> + <GridItem colSpan="2"> + <Input + value={name} + label={i18n('Name')} + isRequired={true} + onChange={name => + onDataChanged( + { name }, + SP_CREATION_FORM_NAME, + { + name: name => + this.validateName(name) + } + ) + } + isValid={genericFieldInfo.name.isValid} + errorText={genericFieldInfo.name.errorText} + type="text" + className="field-section" + data-test-id="new-vsp-name" + /> + <Input + label={i18n('Vendor')} + type="select" + value={vendorId} + overlayPos="bottom" + isRequired={true} + disabled={disableVendor} + onChange={e => this.onSelectVendor(e)} + isValid={genericFieldInfo.vendorId.isValid} + errorText={ + genericFieldInfo.vendorId.errorText + } + className="input-options-select" + groupClassName="bootstrap-input-options" + data-test-id="new-vsp-vendor"> + {vendorList.map(vendor => ( + <option + key={vendor.title} + value={vendor.enum}> + {vendor.title} + </option> + ))} + </Input> + <Input + label={i18n('Category')} + type="select" + value={subCategory} + isRequired={true} + onChange={e => this.onSelectSubCategory(e)} + isValid={ + genericFieldInfo.subCategory.isValid + } + errorText={ + genericFieldInfo.subCategory.errorText + } + className="input-options-select" + groupClassName="bootstrap-input-options" + data-test-id="new-vsp-category"> + <option key="" value=""> + {i18n('please select…')} + </option> + {softwareProductCategories.map( + category => + category.subcategories && ( + <optgroup + key={category.name} + label={category.name}> + {category.subcategories.map( + sub => ( + <option + key={ + sub.uniqueId + } + value={ + sub.uniqueId + }>{`${ + sub.name + } (${ + category.name + })`}</option> + ) + )} + </optgroup> + ) + )} + </Input> + </GridItem> + <GridItem colSpan="2" stretch lastColInRow> + <Input + value={description} + label={i18n('Description')} + isRequired={true} + overlayPos="bottom" + onChange={description => + onDataChanged( + { description }, + SP_CREATION_FORM_NAME + ) + } + isValid={ + genericFieldInfo.description.isValid + } + errorText={ + genericFieldInfo.description.errorText + } + type="textarea" + className="field-section" + data-test-id="new-vsp-description" + /> + </GridItem> + </GridSection> + <OnboardingProcedure + genericFieldInfo={genericFieldInfo} + onboardingMethod={onboardingMethod} + onDataChanged={onDataChanged} + /> + </Form> + )} + </div> + ); + } + + getVendorList() { + let { finalizedLicenseModelList } = this.props; + + return [{ enum: '', title: i18n('please select...') }].concat( + sortByStringProperty(finalizedLicenseModelList, 'name').map( + vendor => { + return { + enum: vendor.id, + title: vendor.name + }; + } + ) + ); + } + + onSelectVendor(e) { + const selectedIndex = e.target.selectedIndex; + const vendorId = e.target.options[selectedIndex].value; + this.props.onDataChanged({ vendorId }, SP_CREATION_FORM_NAME); + } + + onSelectSubCategory(e) { + const selectedIndex = e.target.selectedIndex; + const subCategory = e.target.options[selectedIndex].value; + let { softwareProductCategories, onDataChanged } = this.props; + let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory( + subCategory, + softwareProductCategories + ); + onDataChanged({ category, subCategory }, SP_CREATION_FORM_NAME); + } + + submit() { + let { + data: softwareProduct, + finalizedLicenseModelList, + usersList + } = this.props; + softwareProduct.vendorName = finalizedLicenseModelList.find( + vendor => vendor.id === softwareProduct.vendorId + ).name; + this.props.onSubmit(softwareProduct, usersList); + } + + validateName(value) { + const { data: { id }, VSPNames } = this.props; + const isExists = Validator.isItemNameAlreadyExistsInList({ + itemId: id, + itemName: value, + list: VSPNames + }); + + return !isExists + ? { isValid: true, errorText: '' } + : { + isValid: false, + errorText: i18n( + "Software product by the name '" + + value + + "' already exists. Software product name must be unique" + ) + }; + } + + validate() { + this.props.onValidateForm(SP_CREATION_FORM_NAME); + } } -const OnboardingProcedure = ({onboardingMethod, onDataChanged, genericFieldInfo}) => { - return( - <GridSection title={i18n('Onboarding procedure')}> - <GridItem colSpan={4}> - <Input - label={i18n('Network Package')} - overlayPos='top' - isValid={genericFieldInfo.onboardingMethod.isValid} - checked={onboardingMethod === onboardingMethodConst.NETWORK_PACKAGE} - errorText={genericFieldInfo.onboardingMethod.errorText} - onChange={() => onDataChanged({onboardingMethod: onboardingMethodConst.NETWORK_PACKAGE},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: onboardingMethodConst.MANUAL},SP_CREATION_FORM_NAME)} - type='radio' - data-test-id='new-vsp-creation-procedure-manual' /> - </GridItem> - </GridSection> - ); +const OnboardingProcedure = ({ + onboardingMethod, + onDataChanged, + genericFieldInfo +}) => { + return ( + <GridSection title={i18n('Onboarding procedure')}> + <GridItem colSpan={4}> + <Input + label={i18n('Network Package')} + overlayPos="top" + isValid={genericFieldInfo.onboardingMethod.isValid} + checked={ + onboardingMethod === + onboardingMethodConst.NETWORK_PACKAGE + } + errorText={genericFieldInfo.onboardingMethod.errorText} + onChange={() => + onDataChanged( + { + onboardingMethod: + onboardingMethodConst.NETWORK_PACKAGE + }, + 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: onboardingMethodConst.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/SoftwareProductDependencies.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js index 9888087800..1a0c66d70e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependencies.js @@ -13,25 +13,48 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductDependenciesView from './SoftwareProductDependenciesView.jsx'; import SoftwareProductDependenciesActionHelper from './SoftwareProductDependenciesActionHelper.js'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductDependencies, softwareProductComponents: {componentsList}} = softwareProduct; - return { - softwareProductDependencies: softwareProductDependencies, - componentsOptions: componentsList.map(component => ({value: component.id, label: component.displayName})) - }; +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductDependencies, + softwareProductComponents: { componentsList } + } = softwareProduct; + return { + softwareProductDependencies: softwareProductDependencies, + componentsOptions: componentsList.map(component => ({ + value: component.id, + label: component.displayName + })) + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onDataChanged: (item) => SoftwareProductDependenciesActionHelper.updateDependency(dispatch, {softwareProductId, version, item}), - onDeleteDependency: (item) => SoftwareProductDependenciesActionHelper.removeDependency(dispatch, {softwareProductId, version, item}), - onAddDependency: (item) => SoftwareProductDependenciesActionHelper.createDependency(dispatch, {softwareProductId, version, item}) - }; +const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onDataChanged: item => + SoftwareProductDependenciesActionHelper.updateDependency(dispatch, { + softwareProductId, + version, + item + }), + onDeleteDependency: item => + SoftwareProductDependenciesActionHelper.removeDependency(dispatch, { + softwareProductId, + version, + item + }), + onAddDependency: item => + SoftwareProductDependenciesActionHelper.createDependency(dispatch, { + softwareProductId, + version, + item + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductDependenciesView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductDependenciesView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js index f04f8faf56..4bbcaa13d5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesActionHelper.js @@ -15,83 +15,99 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes, NEW_RULE_TEMP_ID} from './SoftwareProductDependenciesConstants.js'; +import { + actionTypes, + NEW_RULE_TEMP_ID +} from './SoftwareProductDependenciesConstants.js'; function baseUrl(softwareProductId, version) { - const versionId = version.id; - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/component-dependencies`; + const versionId = version.id; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${softwareProductId}/versions/${versionId}/component-dependencies`; } function fetchDependencies(softwareProductId, version) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); } function addDepencency(softwareProductId, version, item) { - return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { - sourceId: item.sourceId, - targetId: item.targetId, - relationType: item.relationType - }); + return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { + sourceId: item.sourceId, + targetId: item.targetId, + relationType: item.relationType + }); } - function updateDepencency(softwareProductId, version, item) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${item.id}`, - { - sourceId: item.sourceId, - targetId: item.targetId, - relationType: item.relationType - }); + return RestAPIUtil.put( + `${baseUrl(softwareProductId, version)}/${item.id}`, + { + sourceId: item.sourceId, + targetId: item.targetId, + relationType: item.relationType + } + ); } function removeDependency(softwareProductId, version, item) { - return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${item.id}`); + return RestAPIUtil.destroy( + `${baseUrl(softwareProductId, version)}/${item.id}` + ); } - const SoftwareProductDependenciesActionHelper = { - updateDependency(dispatch, {softwareProductId, version, item}) { - // if change was made on existing item - we will update the server and refresh the list - // if change was made on the 'new' row - we will only fire the event - if (item.id !== NEW_RULE_TEMP_ID) { - return updateDepencency(softwareProductId, version, item).then(() => { - return this.fetchDependencies(dispatch, {softwareProductId, version}); - }); - } else { - dispatch({ - type: actionTypes.UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY, - item: item - }); - } - }, + updateDependency(dispatch, { softwareProductId, version, item }) { + // if change was made on existing item - we will update the server and refresh the list + // if change was made on the 'new' row - we will only fire the event + if (item.id !== NEW_RULE_TEMP_ID) { + return updateDepencency(softwareProductId, version, item).then( + () => { + return this.fetchDependencies(dispatch, { + softwareProductId, + version + }); + } + ); + } else { + dispatch({ + type: actionTypes.UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY, + item: item + }); + } + }, - createDependency(dispatch, {softwareProductId, version, item}) { - // removing the temp id - delete item.id; - // creating the new dependency - return addDepencency(softwareProductId, version, item).then(() => { - dispatch({ - type: actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY - }); - return this.fetchDependencies(dispatch, {softwareProductId, version}); - }); - }, + createDependency(dispatch, { softwareProductId, version, item }) { + // removing the temp id + delete item.id; + // creating the new dependency + return addDepencency(softwareProductId, version, item).then(() => { + dispatch({ + type: actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY + }); + return this.fetchDependencies(dispatch, { + softwareProductId, + version + }); + }); + }, - removeDependency(dispatch, {softwareProductId, version, item}) { - return removeDependency(softwareProductId, version, item).then( () => { - return this.fetchDependencies(dispatch, {softwareProductId, version}); - }); - }, + removeDependency(dispatch, { softwareProductId, version, item }) { + return removeDependency(softwareProductId, version, item).then(() => { + return this.fetchDependencies(dispatch, { + softwareProductId, + version + }); + }); + }, - fetchDependencies(dispatch, {softwareProductId, version}) { - return fetchDependencies(softwareProductId, version).then( response => { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE, - dependenciesList : response.results - }); - }); - } + fetchDependencies(dispatch, { softwareProductId, version }) { + return fetchDependencies(softwareProductId, version).then(response => { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE, + dependenciesList: response.results + }); + }); + } }; export default SoftwareProductDependenciesActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js index c25561da17..32c7387ca2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesConstants.js @@ -16,17 +16,17 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: null, - ADD_SOFTWARE_PRODUCT_DEPENDENCY: null, - UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY: null + SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: null, + ADD_SOFTWARE_PRODUCT_DEPENDENCY: null, + UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY: null }); export const relationTypes = { - DEPENDS_ON: 'dependsOn' + DEPENDS_ON: 'dependsOn' }; export const relationTypesOptions = [ - {value: relationTypes.DEPENDS_ON, label: 'Depends On'} + { value: relationTypes.DEPENDS_ON, label: 'Depends On' } ]; -export const NEW_RULE_TEMP_ID = 'newRuleTempId';
\ No newline at end of file +export const NEW_RULE_TEMP_ID = 'newRuleTempId'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js index 3edd3b899a..6e028b1ff2 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesReducer.js @@ -1,4 +1,3 @@ - /*! * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. * @@ -15,32 +14,47 @@ * permissions and limitations under the License. */ -import {actionTypes, relationTypes, NEW_RULE_TEMP_ID} from './SoftwareProductDependenciesConstants.js'; -import {checkCyclesAndMarkDependencies} from './SoftwareProductDependenciesUtils.js'; +import { + actionTypes, + relationTypes, + NEW_RULE_TEMP_ID +} from './SoftwareProductDependenciesConstants.js'; +import { checkCyclesAndMarkDependencies } from './SoftwareProductDependenciesUtils.js'; -let newRowObject = {id: NEW_RULE_TEMP_ID, targetId: null, sourceId: null, relationType: relationTypes.DEPENDS_ON}; +let newRowObject = { + id: NEW_RULE_TEMP_ID, + targetId: null, + sourceId: null, + relationType: relationTypes.DEPENDS_ON +}; -export default (state = [Object.assign({}, newRowObject) ], action) => { - switch (action.type) { - case actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: - // copying the entity with the data for the row that is in the 'add' mode - let newDependency = state.find(dependency => dependency.id === NEW_RULE_TEMP_ID); - action.dependenciesList.push(newDependency); - // returning list from the server with our 'new entity' row - return checkCyclesAndMarkDependencies(action.dependenciesList); - case actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY : - // resetting the entity with the data for the 'add' mode for a new entity - let newArray = state.filter(dependency => dependency.id !== NEW_RULE_TEMP_ID); - newArray.push(Object.assign({}, newRowObject)); - return newArray; - case actionTypes.UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY : - // we really only need this for the 'new' row since we need to change the state to get - // everything updated - let updateArrayIndex = state.findIndex(dependency => dependency.id === NEW_RULE_TEMP_ID); - let updateArray = state.slice(); - updateArray.splice(updateArrayIndex, 1, action.item); - return checkCyclesAndMarkDependencies(updateArray); - default: - return state; - } +export default (state = [Object.assign({}, newRowObject)], action) => { + switch (action.type) { + case actionTypes.SOFTWARE_PRODUCT_DEPENDENCIES_LIST_UPDATE: + // copying the entity with the data for the row that is in the 'add' mode + let newDependency = state.find( + dependency => dependency.id === NEW_RULE_TEMP_ID + ); + action.dependenciesList.push(newDependency); + // returning list from the server with our 'new entity' row + return checkCyclesAndMarkDependencies(action.dependenciesList); + case actionTypes.ADD_SOFTWARE_PRODUCT_DEPENDENCY: + // resetting the entity with the data for the 'add' mode for a new entity + let newArray = state.filter( + dependency => dependency.id !== NEW_RULE_TEMP_ID + ); + newArray.push(Object.assign({}, newRowObject)); + return newArray; + case actionTypes.UPDATE_NEW_SOFTWARE_PRODUCT_DEPENDENCY: + // we really only need this for the 'new' row since we need to change the state to get + // everything updated + let updateArrayIndex = state.findIndex( + dependency => dependency.id === NEW_RULE_TEMP_ID + ); + let updateArray = state.slice(); + updateArray.splice(updateArrayIndex, 1, action.item); + return checkCyclesAndMarkDependencies(updateArray); + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js index 94d21bd49d..8d5aaf864e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesUtils.js @@ -16,49 +16,77 @@ import DirectedGraph from 'nfvo-utils/DirectedGraph.js'; -function findCycles(graph, node, id, visited = {}, visitedConnections = {}, recursionStack = {}, connectionsWithCycle = {}) { - visited[node] = true; - recursionStack[node] = true; - if (id) { - visitedConnections[id] = true; - } - for (let edge of graph.getEdges(node)) { - if (!visited[edge.target]) { - findCycles(graph, edge.target, edge.id, visited, visitedConnections, recursionStack, connectionsWithCycle); - } else if (recursionStack[edge.target]) { - visitedConnections[edge.id] = true; - for (let connection in visitedConnections) { - connectionsWithCycle[connection] = true; - } - } - } - recursionStack[node] = false; - return {visitedNodes: visited, connectionsWithCycle: connectionsWithCycle}; +function findCycles( + graph, + node, + id, + visited = {}, + visitedConnections = {}, + recursionStack = {}, + connectionsWithCycle = {} +) { + visited[node] = true; + recursionStack[node] = true; + if (id) { + visitedConnections[id] = true; + } + for (let edge of graph.getEdges(node)) { + if (!visited[edge.target]) { + findCycles( + graph, + edge.target, + edge.id, + visited, + visitedConnections, + recursionStack, + connectionsWithCycle + ); + } else if (recursionStack[edge.target]) { + visitedConnections[edge.id] = true; + for (let connection in visitedConnections) { + connectionsWithCycle[connection] = true; + } + } + } + recursionStack[node] = false; + return { + visitedNodes: visited, + connectionsWithCycle: connectionsWithCycle + }; } export function checkCyclesAndMarkDependencies(dependenciesList) { - let overallVisitedNodes = {}; - let overallConnectionsWithCycles = {}; + let overallVisitedNodes = {}; + let overallConnectionsWithCycles = {}; - let g = new DirectedGraph(); - for (let dependency of dependenciesList) { - if (dependency.sourceId !== null && dependency.targetId !== null) { - g.addEdge(dependency.sourceId, dependency.targetId, {id: dependency.id}); - } - } + let g = new DirectedGraph(); + for (let dependency of dependenciesList) { + if (dependency.sourceId !== null && dependency.targetId !== null) { + g.addEdge(dependency.sourceId, dependency.targetId, { + id: dependency.id + }); + } + } - for (let node in g.nodes) { - if (!overallVisitedNodes.node) { - let {visitedNodes, connectionsWithCycle} = findCycles(g, node, undefined); - overallVisitedNodes = {...overallVisitedNodes, ...visitedNodes}; - overallConnectionsWithCycles = {...overallConnectionsWithCycles, ...connectionsWithCycle}; - } - } - return dependenciesList.map(dependency => ( - { - ...dependency, - hasCycle: dependency.sourceId && dependency.targetId ? - overallConnectionsWithCycles.hasOwnProperty(dependency.id) - : undefined - })); + for (let node in g.nodes) { + if (!overallVisitedNodes.node) { + let { visitedNodes, connectionsWithCycle } = findCycles( + g, + node, + undefined + ); + overallVisitedNodes = { ...overallVisitedNodes, ...visitedNodes }; + overallConnectionsWithCycles = { + ...overallConnectionsWithCycles, + ...connectionsWithCycle + }; + } + } + return dependenciesList.map(dependency => ({ + ...dependency, + hasCycle: + dependency.sourceId && dependency.targetId + ? overallConnectionsWithCycles.hasOwnProperty(dependency.id) + : undefined + })); } 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 ed92de7bb1..3ea1f2d5cc 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/dependencies/SoftwareProductDependenciesView.jsx @@ -20,111 +20,201 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; 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 {relationTypesOptions, NEW_RULE_TEMP_ID} from './SoftwareProductDependenciesConstants.js'; +import { + relationTypesOptions, + NEW_RULE_TEMP_ID +} from './SoftwareProductDependenciesConstants.js'; - -const TableActionRow = ({onAction, actionIcon, showAction, dependency, sourceOptions, targetOptions, onDataChanged}) => { - return ( - <SelectActionTableRow - key={dependency.id} - onAction={onAction} - overlayMsg={i18n('There is a loop between selections')} - hasError={dependency.hasCycle} - hasErrorIndication - showAction={showAction} - actionIcon={actionIcon}> - <SelectActionTableCell - options={sourceOptions} - selected={dependency.sourceId} - placeholder={i18n('Select VFC...')} - clearable={false} - onChange={newVal => { - dependency.sourceId = newVal; - onDataChanged(dependency); - }} /> - <SelectActionTableCell options={relationTypesOptions} selected={dependency.relationType} clearable={false}/> - <SelectActionTableCell - placeholder={i18n('Select VFC...')} - options={targetOptions} - selected={dependency.targetId} - clearable={false} - onChange={newVal => { - dependency.targetId = newVal; - onDataChanged(dependency); - }} /> - </SelectActionTableRow> - ); +const TableActionRow = ({ + onAction, + actionIcon, + showAction, + dependency, + sourceOptions, + targetOptions, + onDataChanged +}) => { + return ( + <SelectActionTableRow + key={dependency.id} + onAction={onAction} + overlayMsg={i18n('There is a loop between selections')} + hasError={dependency.hasCycle} + hasErrorIndication + showAction={showAction} + actionIcon={actionIcon}> + <SelectActionTableCell + options={sourceOptions} + selected={dependency.sourceId} + placeholder={i18n('Select VFC...')} + clearable={false} + onChange={newVal => { + dependency.sourceId = newVal; + onDataChanged(dependency); + }} + /> + <SelectActionTableCell + options={relationTypesOptions} + selected={dependency.relationType} + clearable={false} + /> + <SelectActionTableCell + placeholder={i18n('Select VFC...')} + options={targetOptions} + selected={dependency.targetId} + clearable={false} + onChange={newVal => { + dependency.targetId = newVal; + onDataChanged(dependency); + }} + /> + </SelectActionTableRow> + ); }; - export default class SoftwareProductDependenciesView extends React.Component { - filterTargets({componentsOptions, sourceToTargetMapping, selectedSourceId, selectedTargetId}) { - let isInMap = sourceToTargetMapping.hasOwnProperty(selectedSourceId); - return componentsOptions.filter(component => { - if (component.value === selectedTargetId) { - return true; - } else { - return component.value !== selectedSourceId && (isInMap ? sourceToTargetMapping[selectedSourceId].indexOf(component.value) < 0 : true); - } - }); - } - - filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId, selectedTargetId}) { - return componentsOptions.filter(component => { - if (component.value === selectedSourceId) { - return true; - } else { - let isInMap = sourceToTargetMapping.hasOwnProperty(component.value); - return component.value !== selectedTargetId && (isInMap ? sourceToTargetMapping[component.value].indexOf(selectedTargetId) < 0 : true); - } - }); - } + filterTargets({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId, + selectedTargetId + }) { + let isInMap = sourceToTargetMapping.hasOwnProperty(selectedSourceId); + return componentsOptions.filter(component => { + if (component.value === selectedTargetId) { + return true; + } else { + return ( + component.value !== selectedSourceId && + (isInMap + ? sourceToTargetMapping[selectedSourceId].indexOf( + component.value + ) < 0 + : true) + ); + } + }); + } - render() { - let {componentsOptions, softwareProductDependencies, onDataChanged, onAddDependency, onDeleteDependency, isReadOnlyMode} = this.props; - let sourceToTargetMapping = {}; - softwareProductDependencies.map(dependency => { - let isInMap = sourceToTargetMapping.hasOwnProperty(dependency.sourceId); - if (dependency.targetId) { - sourceToTargetMapping[dependency.sourceId] = isInMap ? [...sourceToTargetMapping[dependency.sourceId], dependency.targetId] : [dependency.targetId]; - } - }); - let depList = softwareProductDependencies.filter(dependency => dependency.id !== NEW_RULE_TEMP_ID); - let newDependency = softwareProductDependencies.find(dependency => dependency.id === NEW_RULE_TEMP_ID); - return ( - <div className='software-product-dependencies'> - <div className='page-title'>{i18n('Dependencies')}</div> - <SelectActionTable - columns={[i18n('Source'), i18n('Relation Type'), i18n('Target')]} - numOfIcons={2} - isReadOnlyMode={isReadOnlyMode}> - {!isReadOnlyMode && <TableActionRow - key={newDependency.id} - actionIcon='plusCircle' - onAction={() => onAddDependency(newDependency)} - dependency={newDependency} - componentsOptions={componentsOptions} - sourceToTargetMapping={sourceToTargetMapping} - onDataChanged={onDataChanged} - sourceOptions={this.filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId: newDependency.sourceId, selectedTargetId: newDependency.targetId})} - targetOptions={this.filterTargets({componentsOptions, sourceToTargetMapping, selectedSourceId: newDependency.sourceId, selectedTargetId: newDependency.targetId})} - showAction={newDependency.targetId !== null && newDependency.relationType !== null && newDependency.sourceId !== null}/> } - {depList.map(dependency => ( - <TableActionRow - key={dependency.id} - actionIcon='trashO' - onAction={() => onDeleteDependency(dependency)} - dependency={dependency} - componentsOptions={componentsOptions} - sourceToTargetMapping={sourceToTargetMapping} - sourceOptions={this.filterSources({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})} - targetOptions={this.filterTargets({componentsOptions, sourceToTargetMapping, selectedSourceId: dependency.sourceId, selectedTargetId: dependency.targetId})} - onDataChanged={onDataChanged} - showAction={true}/> - ))} - </SelectActionTable> - </div> - ); - } + filterSources({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId, + selectedTargetId + }) { + return componentsOptions.filter(component => { + if (component.value === selectedSourceId) { + return true; + } else { + let isInMap = sourceToTargetMapping.hasOwnProperty( + component.value + ); + return ( + component.value !== selectedTargetId && + (isInMap + ? sourceToTargetMapping[component.value].indexOf( + selectedTargetId + ) < 0 + : true) + ); + } + }); + } + render() { + let { + componentsOptions, + softwareProductDependencies, + onDataChanged, + onAddDependency, + onDeleteDependency, + isReadOnlyMode + } = this.props; + let sourceToTargetMapping = {}; + softwareProductDependencies.map(dependency => { + let isInMap = sourceToTargetMapping.hasOwnProperty( + dependency.sourceId + ); + if (dependency.targetId) { + sourceToTargetMapping[dependency.sourceId] = isInMap + ? [ + ...sourceToTargetMapping[dependency.sourceId], + dependency.targetId + ] + : [dependency.targetId]; + } + }); + let depList = softwareProductDependencies.filter( + dependency => dependency.id !== NEW_RULE_TEMP_ID + ); + let newDependency = softwareProductDependencies.find( + dependency => dependency.id === NEW_RULE_TEMP_ID + ); + return ( + <div className="software-product-dependencies"> + <div className="page-title">{i18n('Dependencies')}</div> + <SelectActionTable + columns={[ + i18n('Source'), + i18n('Relation Type'), + i18n('Target') + ]} + numOfIcons={2} + isReadOnlyMode={isReadOnlyMode}> + {!isReadOnlyMode && ( + <TableActionRow + key={newDependency.id} + actionIcon="plusCircle" + onAction={() => onAddDependency(newDependency)} + dependency={newDependency} + componentsOptions={componentsOptions} + sourceToTargetMapping={sourceToTargetMapping} + onDataChanged={onDataChanged} + sourceOptions={this.filterSources({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId: newDependency.sourceId, + selectedTargetId: newDependency.targetId + })} + targetOptions={this.filterTargets({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId: newDependency.sourceId, + selectedTargetId: newDependency.targetId + })} + showAction={ + newDependency.targetId !== null && + newDependency.relationType !== null && + newDependency.sourceId !== null + } + /> + )} + {depList.map(dependency => ( + <TableActionRow + key={dependency.id} + actionIcon="trashO" + onAction={() => onDeleteDependency(dependency)} + dependency={dependency} + componentsOptions={componentsOptions} + sourceToTargetMapping={sourceToTargetMapping} + sourceOptions={this.filterSources({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId: dependency.sourceId, + selectedTargetId: dependency.targetId + })} + targetOptions={this.filterTargets({ + componentsOptions, + sourceToTargetMapping, + selectedSourceId: dependency.sourceId, + selectedTargetId: dependency.targetId + })} + onDataChanged={onDataChanged} + showAction={true} + /> + ))} + </SelectActionTable> + </div> + ); + } } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js index a5c70068b0..4e03926ac5 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeployment.js @@ -13,37 +13,70 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +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 { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; -export function mapStateToProps({softwareProduct}) { - let {softwareProductComponents: {componentsList}, softwareProductDeployment: {deploymentFlavors}} = softwareProduct; - return { - deploymentFlavors, - componentsList - }; +export function mapStateToProps({ softwareProduct }) { + let { + softwareProductComponents: { componentsList }, + softwareProductDeployment: { deploymentFlavors } + } = softwareProduct; + return { + 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}"?', {model: 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}), - ) - }; +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}"?', { + model: 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); +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 index bd802b38f4..44b25311e0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentActionHelper.js @@ -1,101 +1,183 @@ -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 { 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`; + 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 fetchDeploymentFlavorsList({ softwareProductId, version }) { + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); } -function fetchDeploymentFlavor({softwareProductId, deploymentFlavorId, version}) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}/${deploymentFlavorId}`); +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 deleteDeploymentFlavor({ + softwareProductId, + deploymentFlavorId, + version +}) { + return RestAPIUtil.destroy( + `${baseUrl(softwareProductId, version)}/${deploymentFlavorId}` + ); } -function createDeploymentFlavor({softwareProductId, data, version}) { - return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, data); +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); +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 - }); - }); - }, + 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}); - }, + 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}); - }); - }, + 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}); - }); - }, + 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}); - }); - }, + 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 - }); - }, + 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' - } - }); - }, + 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; +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 index 51469b461c..6c0d3efe38 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentConstants.js @@ -16,13 +16,13 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS: null, + FETCH_SOFTWARE_PRODUCT_DEPLOYMENT_FLAVORS: null, - deploymentFlavorEditor: { - DATA_CHANGED: null, - SOFTWARE_PRODUCT_DEPLOYMENT_FILL_DATA: null, - SOFTWARE_PRODUCT_DEPLOYMENT_CLEAR_DATA: 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 index 8eb91e8fcb..31bf09e945 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentListReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductDeploymentConstants.js'; +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; - } + 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 index 860d02c343..e1bdd553a6 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/SoftwareProductDeploymentView.jsx @@ -22,74 +22,82 @@ import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.js import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; export default class SoftwareProductDeployment extends React.Component { - state = { - localFilter: '' - }; + state = { + localFilter: '' + }; - static propTypes = { - onAddDeployment: PropTypes.func.isRequired, - onDeleteDeployment: PropTypes.func.isRequired, - onEditDeployment: PropTypes.func.isRequired, - isReadOnlyMode: PropTypes.bool.isRequired - }; + static propTypes = { + onAddDeployment: PropTypes.func.isRequired, + onDeleteDeployment: PropTypes.func.isRequired, + onEditDeployment: PropTypes.func.isRequired, + isReadOnlyMode: PropTypes.bool.isRequired + }; - render() { - return ( - <div> - {this.renderList()} - </div> - ); - } + 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> - ); - } + 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> - ); - } + 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; + 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; - } - } + 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 index c24548b7b9..9392317692 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditor.js @@ -13,77 +13,103 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductDeploymentEditorView from './SoftwareProductDeploymentEditorView.jsx'; import SoftwareProdcutDeploymentActionHelper from '../SoftwareProductDeploymentActionHelper.js'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import {DEPLOYMENT_FLAVORS_FORM_NAME} from '../SoftwareProductDeploymentConstants.js'; +import { DEPLOYMENT_FLAVORS_FORM_NAME } from '../SoftwareProductDeploymentConstants.js'; export function mapStateToProps({ - licenseModel, - softwareProduct, - currentScreen: {props: {isReadOnlyMode}} + licenseModel, + softwareProduct, + currentScreen: { props: { isReadOnlyMode } } }) { - let { - softwareProductEditor: { - data: currentSoftwareProduct = {} - }, - softwareProductComponents: { - componentsList, - computeFlavor: { - computesList - } - }, - softwareProductDeployment: { - deploymentFlavors, - deploymentFlavorEditor: { - data = {}, - genericFieldInfo, - formReady - } - } - } = softwareProduct; + let { + softwareProductEditor: { data: currentSoftwareProduct = {} }, + softwareProductComponents: { + componentsList, + computeFlavor: { computesList } + }, + softwareProductDeployment: { + deploymentFlavors, + deploymentFlavorEditor: { data = {}, genericFieldInfo, formReady } + } + } = softwareProduct; - let { - featureGroup: { - featureGroupsList - } - } = licenseModel; + let { featureGroup: { featureGroupsList } } = licenseModel; - 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 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 = {}; + let DFNames = {}; - deploymentFlavors.map(deployment => { - DFNames[deployment.model.toLowerCase()] = deployment.id; - }); + deploymentFlavors.map(deployment => { + DFNames[deployment.model.toLowerCase()] = deployment.id; + }); - return { - data, - selectedFeatureGroupsList, - genericFieldInfo, - DFNames, - isFormValid, - formReady, - isReadOnlyMode, - componentsList, - computesList, - isEdit: Boolean(data.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) - }; +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); +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 index 70836e8ff9..16e73d2162 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorReducer.js @@ -13,32 +13,37 @@ * 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';; +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; - } + 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 index 7c9ae438d9..e44d2bd966 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/deployment/editor/SoftwareProductDeploymentEditorView.jsx @@ -11,127 +11,240 @@ import SelectActionTableCell from 'nfvo-components/table/SelectActionTableCell.j 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 hasLastColSet> - <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} lastColInRow> - <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')} hasLastColSet> - <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' hasLastColSet> - <GridItem colSpan={4} lastColInRow> - <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> - ); - } + 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 hasLastColSet> + <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} lastColInRow> + <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')} + hasLastColSet> + <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" + hasLastColSet> + <GridItem colSpan={4} lastColInRow> + <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}); + 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')}; - } + 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(); - } + submit() { + let { isEdit, onCreate, onEdit, onClose, data } = this.props; + if (isEdit) { + onEdit(data); + } else { + onCreate(data); + } + onClose(); + } - validate() { - this.props.onValidateForm(); - } + validate() { + this.props.onValidateForm(); + } } diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetails.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetails.js index 0973537d43..8a3279a02c 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetails.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetails.js @@ -13,80 +13,140 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SoftwareProductActionHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductActionHelper.js'; import SoftwareProductDetailsView from './SoftwareProductDetailsView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import {PRODUCT_QUESTIONNAIRE} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -import {actionTypes as modalActionTypes, modalSizes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { PRODUCT_QUESTIONNAIRE } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { + actionTypes as modalActionTypes, + modalSizes +} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { forms } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; export const mapStateToProps = ({ - finalizedLicenseModelList, - archivedLicenseModelList, - softwareProduct, - licenseModel: {licenseAgreement, featureGroup} + finalizedLicenseModelList, + archivedLicenseModelList, + softwareProduct, + licenseModel: { licenseAgreement, featureGroup } }) => { + let { + softwareProductEditor: { + data: currentSoftwareProduct, + licensingVersionsList = [], + genericFieldInfo + }, + softwareProductCategories, + softwareProductQuestionnaire + } = softwareProduct; + let { licensingData = {}, licensingVersion } = currentSoftwareProduct; + let licenseAgreementList = [], + filteredFeatureGroupsList = []; + licenseAgreementList = licensingVersion + ? licenseAgreement.licenseAgreementList + : []; + if (licensingVersion && licensingData && licensingData.licenseAgreement) { + let selectedLicenseAgreement = licenseAgreementList.find( + la => la.id === licensingData.licenseAgreement + ); + if (selectedLicenseAgreement) { + let featureGroupsList = featureGroup.featureGroupsList.filter( + ({ referencingLicenseAgreements }) => + referencingLicenseAgreements.includes( + selectedLicenseAgreement.id + ) + ); + if (featureGroupsList.length) { + filteredFeatureGroupsList = featureGroupsList.map( + featureGroup => ({ + enum: featureGroup.id, + title: featureGroup.name + }) + ); + } + } + } + let { + qdata, + qgenericFieldInfo: qGenericFieldInfo, + dataMap + } = softwareProductQuestionnaire; - let {softwareProductEditor: {data: currentSoftwareProduct, licensingVersionsList = [], genericFieldInfo}, softwareProductCategories, softwareProductQuestionnaire} = softwareProduct; - let {licensingData = {}, licensingVersion} = currentSoftwareProduct; - let licenseAgreementList = [], filteredFeatureGroupsList = []; - licenseAgreementList = licensingVersion ? - licenseAgreement.licenseAgreementList : []; - if(licensingVersion && licensingData && licensingData.licenseAgreement) { - let selectedLicenseAgreement = licenseAgreementList.find(la => la.id === licensingData.licenseAgreement); - if (selectedLicenseAgreement) { - let featureGroupsList = featureGroup.featureGroupsList.filter(({referencingLicenseAgreements}) => referencingLicenseAgreements.includes(selectedLicenseAgreement.id)); - if (featureGroupsList.length) { - filteredFeatureGroupsList = featureGroupsList.map(featureGroup => ({enum: featureGroup.id, title: featureGroup.name})); - } - } - } - let {qdata, qgenericFieldInfo : qGenericFieldInfo, dataMap} = softwareProductQuestionnaire; - - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - const isVendorArchived = archivedLicenseModelList.find(item => item.id === currentSoftwareProduct.vendorId); - return { - currentSoftwareProduct, - softwareProductCategories, - licenseAgreementList, - licensingVersionsList, - featureGroupsList: filteredFeatureGroupsList, - finalizedLicenseModelList, - qdata, - isFormValid, - genericFieldInfo, - qGenericFieldInfo, - dataMap, - isVendorArchived: !!isVendorArchived - }; - + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + const isVendorArchived = archivedLicenseModelList.find( + item => item.id === currentSoftwareProduct.vendorId + ); + return { + currentSoftwareProduct, + softwareProductCategories, + licenseAgreementList, + licensingVersionsList, + featureGroupsList: filteredFeatureGroupsList, + finalizedLicenseModelList, + qdata, + isFormValid, + genericFieldInfo, + qGenericFieldInfo, + dataMap, + isVendorArchived: !!isVendorArchived + }; }; -export const mapActionsToProps = (dispatch, {version}) => { - return { - onDataChanged: (deltaData, formName) => ValidationHelper.dataChanged(dispatch, {deltaData, formName}), - onVendorParamChanged: (deltaData, formName) => SoftwareProductActionHelper.softwareProductEditorVendorChanged(dispatch, {deltaData, formName}), - onQDataChanged: (deltaData) => ValidationHelper.qDataChanged(dispatch, {deltaData, qName: PRODUCT_QUESTIONNAIRE}), - onValidityChanged: isValidityData => SoftwareProductActionHelper.setIsValidityData(dispatch, {isValidityData}), - onSubmit: (softwareProduct, qdata) => SoftwareProductActionHelper.updateSoftwareProduct(dispatch, {softwareProduct, qdata, version}), - onArchivedVendorRemove: ({onVendorParamChanged, finalizedLicenseModelList, vendorName}) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data:{ - title: i18n('Change Archived VLM'), - modalComponentName: modalContentMapper.VENDOR_SELECTOR, - modalComponentProps: { - size: modalSizes.MEDIUM, - finalizedLicenseModelList, - vendorName, - onClose: () => dispatch({type: modalActionTypes.GLOBAL_MODAL_CLOSE}), - onConfirm: (vendorId) => onVendorParamChanged({vendorId}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS) - } - } - }) - }; +export const mapActionsToProps = (dispatch, { version }) => { + return { + onDataChanged: (deltaData, formName) => + ValidationHelper.dataChanged(dispatch, { deltaData, formName }), + onVendorParamChanged: (deltaData, formName) => + SoftwareProductActionHelper.softwareProductEditorVendorChanged( + dispatch, + { deltaData, formName } + ), + onQDataChanged: deltaData => + ValidationHelper.qDataChanged(dispatch, { + deltaData, + qName: PRODUCT_QUESTIONNAIRE + }), + onValidityChanged: isValidityData => + SoftwareProductActionHelper.setIsValidityData(dispatch, { + isValidityData + }), + onSubmit: (softwareProduct, qdata) => + SoftwareProductActionHelper.updateSoftwareProduct(dispatch, { + softwareProduct, + qdata, + version + }), + onArchivedVendorRemove: ({ + onVendorParamChanged, + finalizedLicenseModelList, + vendorName + }) => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + title: i18n('Change Archived VLM'), + modalComponentName: modalContentMapper.VENDOR_SELECTOR, + modalComponentProps: { + size: modalSizes.MEDIUM, + finalizedLicenseModelList, + vendorName, + onClose: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }), + onConfirm: vendorId => + onVendorParamChanged( + { vendorId }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ) + } + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductDetailsView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductDetailsView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsReducer.js index 1a293264c3..1e4a0df787 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsReducer.js @@ -13,49 +13,56 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { + actionTypes, + forms +} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED: - return { - ...state, - isValidityData: action.isValidityData - }; - case actionTypes.SOFTWARE_PRODUCT_LOADED: - return { - ...state, - formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS, - genericFieldInfo: { - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'validateName', data: true}, {type: 'maxLength', data: 25}, {type: 'required', data: true}] - }, - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - } - }, - data: action.response - }; - case actionTypes.TOGGLE_NAVIGATION_ITEM: - return { - ...state, - mapOfExpandedIds: action.mapOfExpandedIds - }; - case actionTypes.LOAD_LICENSING_VERSIONS_LIST: - return { - ...state, - licensingVersionsList: action.licensingVersionsList - }; - case actionTypes.CANDIDATE_IN_PROCESS: - return { - ...state, - data: {...state.data, candidateOnboardingOrigin: true} - }; - default: - return state; - } + switch (action.type) { + case actionTypes.softwareProductEditor.IS_VALIDITY_DATA_CHANGED: + return { + ...state, + isValidityData: action.isValidityData + }; + case actionTypes.SOFTWARE_PRODUCT_LOADED: + return { + ...state, + formName: forms.VENDOR_SOFTWARE_PRODUCT_DETAILS, + genericFieldInfo: { + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'validateName', data: true }, + { type: 'maxLength', data: 25 }, + { type: 'required', data: true } + ] + }, + description: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + } + }, + data: action.response + }; + case actionTypes.TOGGLE_NAVIGATION_ITEM: + return { + ...state, + mapOfExpandedIds: action.mapOfExpandedIds + }; + case actionTypes.LOAD_LICENSING_VERSIONS_LIST: + return { + ...state, + licensingVersionsList: action.licensingVersionsList + }; + case actionTypes.CANDIDATE_IN_PROCESS: + return { + ...state, + data: { ...state.data, candidateOnboardingOrigin: true } + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsVendorSelector.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsVendorSelector.jsx index c2a3e0bd02..9c20723689 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsVendorSelector.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsVendorSelector.jsx @@ -22,57 +22,77 @@ import Input from 'nfvo-components/input/validation/Input.jsx'; import sortByStringProperty from 'nfvo-utils/sortByStringProperty.js'; class VendorSelector extends React.Component { - static propTypes = { - finalizedLicenseModelList: PropTypes.array, - vendorName: PropTypes.string, - onClose: PropTypes.func.isRequired, - onConfirm: PropTypes.func.isRequired - } - constructor(props){ - super(props); - const selectedValue = props.finalizedLicenseModelList.length ? props.finalizedLicenseModelList[0].id : ''; - this.state = { - selectedValue - }; - } - submit() { - const vendor = this.props.finalizedLicenseModelList.find(item => item.id === this.state.selectedValue); - this.props.onConfirm(vendor.id); - this.props.onClose(); - } - render() { - const {finalizedLicenseModelList, vendorName, onClose} = this.props; - const {selectedValue} = this.state; - return ( - <div className='vsp-details-vendor-select'> - <Form - onSubmit={() => this.submit()} - onReset={() => onClose()} - isValid = {!!selectedValue} - submitButtonText={i18n('Save')} - hasButtons={true}> - <div className='vendor-selector-modal-title'>{`${i18n('The VLM')} '${vendorName}' ${i18n('assigned to this VSP is archived')}.`}</div> - <div className='vendor-selector-modal-additional-text'>{i18n('If you select a different VLM you will not be able to reselect the archived VLM.')}</div> - <Input - data-test-id='vsp-vendor-name-select' - label={i18n('Vendor')} - type='select' - onChange={e => {this.setState({ - selectedValue: e.target.options[e.target.selectedIndex].value - });}} - value={selectedValue}> - <option key='emtyVendor' value=''>{i18n('please select...')}</option> - {sortByStringProperty( - finalizedLicenseModelList, - 'name' - ).map(lm => <option key={lm.id} value={lm.id}>{lm.name}</option>) - } - </Input> - </Form> - </div> - ); - } + static propTypes = { + finalizedLicenseModelList: PropTypes.array, + vendorName: PropTypes.string, + onClose: PropTypes.func.isRequired, + onConfirm: PropTypes.func.isRequired + }; + constructor(props) { + super(props); + const selectedValue = props.finalizedLicenseModelList.length + ? props.finalizedLicenseModelList[0].id + : ''; + this.state = { + selectedValue + }; + } + submit() { + const vendor = this.props.finalizedLicenseModelList.find( + item => item.id === this.state.selectedValue + ); + this.props.onConfirm(vendor.id); + this.props.onClose(); + } + render() { + const { finalizedLicenseModelList, vendorName, onClose } = this.props; + const { selectedValue } = this.state; + return ( + <div className="vsp-details-vendor-select"> + <Form + onSubmit={() => this.submit()} + onReset={() => onClose()} + isValid={!!selectedValue} + submitButtonText={i18n('Save')} + hasButtons={true}> + <div className="vendor-selector-modal-title">{`${i18n( + 'The VLM' + )} '${vendorName}' ${i18n( + 'assigned to this VSP is archived' + )}.`}</div> + <div className="vendor-selector-modal-additional-text"> + {i18n( + 'If you select a different VLM you will not be able to reselect the archived VLM.' + )} + </div> + <Input + data-test-id="vsp-vendor-name-select" + label={i18n('Vendor')} + type="select" + onChange={e => { + this.setState({ + selectedValue: + e.target.options[e.target.selectedIndex] + .value + }); + }} + value={selectedValue}> + <option key="emtyVendor" value=""> + {i18n('please select...')} + </option> + {sortByStringProperty( + finalizedLicenseModelList, + 'name' + ).map(lm => ( + <option key={lm.id} value={lm.id}> + {lm.name} + </option> + ))} + </Input> + </Form> + </div> + ); + } } export default VendorSelector; - 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 24aa319c24..12b1eadc86 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/details/SoftwareProductDetailsView.jsx @@ -13,7 +13,7 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import React, {Component} from 'react'; +import React, { Component } from 'react'; import PropTypes from 'prop-types'; import i18n from 'nfvo-utils/i18n/i18n.js'; @@ -24,427 +24,642 @@ import InputOptions from 'nfvo-components/input/validation/InputOptions.jsx'; import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; import SoftwareProductCategoriesHelper from 'sdc-app/onboarding/softwareProduct/SoftwareProductCategoriesHelper.js'; -import {forms} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { forms } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; -const DeprecatedVlmInfo = ({vendorName, onVendorRemove}) => { - return ( - <div className='depricated-vlm-info'> - <Input - data-test-id='vsp-vendor-name' - isRequired={true} - onClick={() => onVendorRemove()} - label={i18n('Vendor')} - type='select' - value={`${vendorName} (Archived)`}> - <option key={vendorName} value={`${vendorName} (Archived)`}>{`${vendorName} (Archived)`}</option> - </Input> - </div> - ); +const DeprecatedVlmInfo = ({ vendorName, onVendorRemove }) => { + return ( + <div className="depricated-vlm-info"> + <Input + data-test-id="vsp-vendor-name" + isRequired={true} + onClick={() => onVendorRemove()} + label={i18n('Vendor')} + type="select" + value={`${vendorName} (Archived)`}> + <option + key={vendorName} + value={`${vendorName} (Archived)`}>{`${vendorName} (Archived)`}</option> + </Input> + </div> + ); }; class GeneralSection extends React.Component { - static propTypes = { - vendorId: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - subCategory: PropTypes.string, - softwareProductCategories: PropTypes.array, - finalizedLicenseModelList: PropTypes.array, - onDataChanged: PropTypes.func.isRequired, - onVendorParamChanged: PropTypes.func.isRequired, - onSelectSubCategory: PropTypes.func.isRequired, - isVendorArchived: PropTypes.bool, - onArchivedVendorRemove: PropTypes.func - }; + static propTypes = { + vendorId: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + subCategory: PropTypes.string, + softwareProductCategories: PropTypes.array, + finalizedLicenseModelList: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onVendorParamChanged: PropTypes.func.isRequired, + onSelectSubCategory: PropTypes.func.isRequired, + isVendorArchived: PropTypes.bool, + onArchivedVendorRemove: PropTypes.func + }; - onVendorParamChanged(e) { - const selectedIndex = e.target.selectedIndex; - const vendorId = e.target.options[selectedIndex].value; - this.props.onVendorParamChanged({vendorId}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); + onVendorParamChanged(e) { + const selectedIndex = e.target.selectedIndex; + const vendorId = e.target.options[selectedIndex].value; + this.props.onVendorParamChanged( + { vendorId }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ); + } - } + onSelectSubCategory(e) { + const selectedIndex = e.target.selectedIndex; + const subCategory = e.target.options[selectedIndex].value; + this.props.onSelectSubCategory(subCategory); + } + onVendorRemove() { + const { + finalizedLicenseModelList, + vendorName, + onVendorParamChanged + } = this.props; + this.props.onArchivedVendorRemove({ + finalizedLicenseModelList, + onVendorParamChanged, + vendorName + }); + } - onSelectSubCategory(e) { - const selectedIndex = e.target.selectedIndex; - const subCategory = e.target.options[selectedIndex].value; - this.props.onSelectSubCategory(subCategory); - } - onVendorRemove() { - const {finalizedLicenseModelList, vendorName, onVendorParamChanged} = this.props; - this.props.onArchivedVendorRemove({finalizedLicenseModelList, onVendorParamChanged, vendorName}); - } - - render (){ - let {genericFieldInfo} = this.props; - return ( - <div> - {genericFieldInfo && <GridSection title={i18n('General')} className='grid-section-general'> - <GridItem> - <Input - data-test-id='vsp-name' - label={i18n('Name')} - type='text' - value={this.props.name} - isRequired={true} - errorText={genericFieldInfo.name.errorText} - isValid={genericFieldInfo.name.isValid} - onChange={name => name.length <= 25 && this.props.onDataChanged({name}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/> - {this.props.isVendorArchived ? - <DeprecatedVlmInfo onVendorRemove={()=>this.onVendorRemove()} vendorName={this.props.vendorName} /> : - <Input - data-test-id='vsp-vendor-name' - label={i18n('Vendor')} - type='select' - value={this.props.vendorId} - onChange={e => this.onVendorParamChanged(e)}> - {sortByStringProperty( - this.props.finalizedLicenseModelList, - 'name' - ).map(lm => <option key={lm.id} value={lm.id}>{lm.name}</option>) - } - </Input> - } - <Input - data-test-id='vsp-category-name' - label={i18n('Category')} - type='select' - value={this.props.subCategory} - onChange={e => this.onSelectSubCategory(e)}> - { - this.props.softwareProductCategories.map(category => - category.subcategories && - <optgroup - key={category.name} - label={category.name}>{category.subcategories.map(sub => - <option - key={sub.uniqueId} - value={sub.uniqueId}>{`${sub.name} (${category.name})`}</option>)} - </optgroup> - ) - } - </Input> - </GridItem> - <GridItem colSpan={2} stretch> - <Input - data-test-id='vsp-description' - label={i18n('Description')} - type='textarea' - isRequired={true} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - value={this.props.description} - onChange={description => this.props.onDataChanged({description}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS)}/> - </GridItem> - </GridSection>} - </div>); - } + render() { + let { genericFieldInfo } = this.props; + return ( + <div> + {genericFieldInfo && ( + <GridSection + title={i18n('General')} + className="grid-section-general"> + <GridItem> + <Input + data-test-id="vsp-name" + label={i18n('Name')} + type="text" + value={this.props.name} + isRequired={true} + errorText={genericFieldInfo.name.errorText} + isValid={genericFieldInfo.name.isValid} + onChange={name => + name.length <= 25 && + this.props.onDataChanged( + { name }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ) + } + /> + {this.props.isVendorArchived ? ( + <DeprecatedVlmInfo + onVendorRemove={() => this.onVendorRemove()} + vendorName={this.props.vendorName} + /> + ) : ( + <Input + data-test-id="vsp-vendor-name" + label={i18n('Vendor')} + type="select" + value={this.props.vendorId} + onChange={e => + this.onVendorParamChanged(e) + }> + {sortByStringProperty( + this.props.finalizedLicenseModelList, + 'name' + ).map(lm => ( + <option key={lm.id} value={lm.id}> + {lm.name} + </option> + ))} + </Input> + )} + <Input + data-test-id="vsp-category-name" + label={i18n('Category')} + type="select" + value={this.props.subCategory} + onChange={e => this.onSelectSubCategory(e)}> + {this.props.softwareProductCategories.map( + category => + category.subcategories && ( + <optgroup + key={category.name} + label={category.name}> + {category.subcategories.map( + sub => ( + <option + key={sub.uniqueId} + value={ + sub.uniqueId + }>{`${sub.name} (${ + category.name + })`}</option> + ) + )} + </optgroup> + ) + )} + </Input> + </GridItem> + <GridItem colSpan={2} stretch> + <Input + data-test-id="vsp-description" + label={i18n('Description')} + type="textarea" + isRequired={true} + isValid={genericFieldInfo.description.isValid} + errorText={ + genericFieldInfo.description.errorText + } + value={this.props.description} + onChange={description => + this.props.onDataChanged( + { description }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ) + } + /> + </GridItem> + </GridSection> + )} + </div> + ); + } } class LicensesSection extends React.Component { - static propTypes = { - onVendorParamChanged: PropTypes.func.isRequired, - vendorId: PropTypes.string, - licensingVersion: PropTypes.string, - licensingVersionsList: PropTypes.array, - licensingData: PropTypes.shape({ - licenceAgreement: PropTypes.string, - featureGroups: PropTypes.array - }), - onFeatureGroupsChanged: PropTypes.func.isRequired, - onLicensingDataChanged: PropTypes.func.isRequired, - featureGroupsList: PropTypes.array, - licenseAgreementList: PropTypes.array, - isVendorArchived: PropTypes.bool - }; + static propTypes = { + onVendorParamChanged: PropTypes.func.isRequired, + vendorId: PropTypes.string, + licensingVersion: PropTypes.string, + licensingVersionsList: PropTypes.array, + licensingData: PropTypes.shape({ + licenceAgreement: PropTypes.string, + featureGroups: PropTypes.array + }), + onFeatureGroupsChanged: PropTypes.func.isRequired, + onLicensingDataChanged: PropTypes.func.isRequired, + featureGroupsList: PropTypes.array, + licenseAgreementList: PropTypes.array, + isVendorArchived: PropTypes.bool + }; - onVendorParamChanged(e) { - const selectedIndex = e.target.selectedIndex; - const licensingVersion = e.target.options[selectedIndex].value; - this.props.onVendorParamChanged({vendorId: this.props.vendorId, licensingVersion}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); - } + onVendorParamChanged(e) { + const selectedIndex = e.target.selectedIndex; + const licensingVersion = e.target.options[selectedIndex].value; + this.props.onVendorParamChanged( + { vendorId: this.props.vendorId, licensingVersion }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ); + } - onLicensingDataChanged(e) { - const selectedIndex = e.target.selectedIndex; - const licenseAgreement = e.target.options[selectedIndex].value; - this.props.onLicensingDataChanged({licenseAgreement, featureGroups: []}); - } + onLicensingDataChanged(e) { + const selectedIndex = e.target.selectedIndex; + const licenseAgreement = e.target.options[selectedIndex].value; + this.props.onLicensingDataChanged({ + licenseAgreement, + featureGroups: [] + }); + } - render(){ - return ( - <GridSection title={i18n('Licenses')}> - <GridItem> - <Input - data-test-id='vsp-licensing-version' - onChange={e => this.onVendorParamChanged(e)} - value={this.props.licensingVersion || ''} - label={i18n('Licensing Version')} - disabled={this.props.isVendorArchived} - type='select'> - {this.props.licensingVersionsList.map(version => - <option - key={version.enum} - value={version.enum}>{version.title} - </option> - )} - </Input> - </GridItem> - <GridItem> - <Input - data-test-id='vsp-license-agreement' - label={i18n('License Agreement')} - type='select' - disabled={this.props.isVendorArchived} - value={this.props.licensingData.licenseAgreement ? this.props.licensingData.licenseAgreement : '' } - onChange={(e) => this.onLicensingDataChanged(e)}> - <option key='placeholder' value=''>{i18n('Select...')}</option> - {this.props.licenseAgreementList.map(la => <option value={la.id} key={la.id}>{la.name}</option>)} - </Input> - </GridItem> - <GridItem> - {this.props.licensingData.licenseAgreement && ( - <InputOptions - data-test-id='vsp-feature-group' - type='select' - isMultiSelect={true} - onInputChange={()=>{}} - disabled={this.props.isVendorArchived} - onEnumChange={featureGroups => this.props.onFeatureGroupsChanged({featureGroups})} - multiSelectedEnum={this.props.licensingData.featureGroups} - name='feature-groups' - label={i18n('Feature Groups')} - clearable={false} - values={this.props.featureGroupsList}/>) - } - </GridItem> - </GridSection> - ); - } + render() { + return ( + <GridSection title={i18n('Licenses')}> + <GridItem> + <Input + data-test-id="vsp-licensing-version" + onChange={e => this.onVendorParamChanged(e)} + value={this.props.licensingVersion || ''} + label={i18n('Licensing Version')} + disabled={this.props.isVendorArchived} + type="select"> + {this.props.licensingVersionsList.map(version => ( + <option key={version.enum} value={version.enum}> + {version.title} + </option> + ))} + </Input> + </GridItem> + <GridItem> + <Input + data-test-id="vsp-license-agreement" + label={i18n('License Agreement')} + type="select" + disabled={this.props.isVendorArchived} + value={ + this.props.licensingData.licenseAgreement + ? this.props.licensingData.licenseAgreement + : '' + } + onChange={e => this.onLicensingDataChanged(e)}> + <option key="placeholder" value=""> + {i18n('Select...')} + </option> + {this.props.licenseAgreementList.map(la => ( + <option value={la.id} key={la.id}> + {la.name} + </option> + ))} + </Input> + </GridItem> + <GridItem> + {this.props.licensingData.licenseAgreement && ( + <InputOptions + data-test-id="vsp-feature-group" + type="select" + isMultiSelect={true} + onInputChange={() => {}} + disabled={this.props.isVendorArchived} + onEnumChange={featureGroups => + this.props.onFeatureGroupsChanged({ + featureGroups + }) + } + multiSelectedEnum={ + this.props.licensingData.featureGroups + } + name="feature-groups" + label={i18n('Feature Groups')} + clearable={false} + values={this.props.featureGroupsList} + /> + )} + </GridItem> + </GridSection> + ); + } } -const AvailabilitySection = (props) => ( - <GridSection title={i18n('Availability')}> - <GridItem colSpan={2}> - <Input - data-test-id='vsp-use-availability-zone' - label={i18n('Use Availability Zones for High Availability')} - type='checkbox' - checked={props.dataMap['general/availability/useAvailabilityZonesForHighAvailability']} - value={props.dataMap['general/availability/useAvailabilityZonesForHighAvailability']} - onChange={(aZone) => props.onQDataChanged({'general/availability/useAvailabilityZonesForHighAvailability' : aZone})} /> - </GridItem> - </GridSection> +const AvailabilitySection = props => ( + <GridSection title={i18n('Availability')}> + <GridItem colSpan={2}> + <Input + data-test-id="vsp-use-availability-zone" + label={i18n('Use Availability Zones for High Availability')} + type="checkbox" + checked={ + props.dataMap[ + 'general/availability/useAvailabilityZonesForHighAvailability' + ] + } + value={ + props.dataMap[ + 'general/availability/useAvailabilityZonesForHighAvailability' + ] + } + onChange={aZone => + props.onQDataChanged({ + 'general/availability/useAvailabilityZonesForHighAvailability': aZone + }) + } + /> + </GridItem> + </GridSection> ); -const RegionsSection = (props) => ( - <GridSection title={i18n('Regions')}> - <GridItem> - <InputOptions - data-test-id='vsp-regions' - type='select' - isMultiSelect={true} - onInputChange={()=>{}} - onEnumChange={(regions) => props.onQDataChanged({'general/regionsData/regions' : regions})} - multiSelectedEnum={props.dataMap['general/regionsData/regions']} - name='vsp-regions' - clearable={false} - values={props.genericFieldInfo['general/regionsData/regions'].enum} /> - </GridItem> - </GridSection> +const RegionsSection = props => ( + <GridSection title={i18n('Regions')}> + <GridItem> + <InputOptions + data-test-id="vsp-regions" + type="select" + isMultiSelect={true} + onInputChange={() => {}} + onEnumChange={regions => + props.onQDataChanged({ + 'general/regionsData/regions': regions + }) + } + multiSelectedEnum={props.dataMap['general/regionsData/regions']} + name="vsp-regions" + clearable={false} + values={ + props.genericFieldInfo['general/regionsData/regions'].enum + } + /> + </GridItem> + </GridSection> ); -const StorageDataReplicationSection = (props) => ( - <GridSection title={i18n('Storage Data Replication')}> - <GridItem> - <Input - data-test-id='vsp-storage-rep-size' - label={i18n('Storage Replication Size (GB)')} - type='number' - isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationSize'].isValid} - errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationSize'].errorText} - value={props.dataMap['general/storageDataReplication/storageReplicationSize']} - onChange={(sRep) => props.onQDataChanged({'general/storageDataReplication/storageReplicationSize' : sRep})} /> - </GridItem> - <GridItem> - <Input - data-test-id='vsp-storage-rep-source' - label={i18n('Storage Replication Source')} - type='text' - isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationSource'].isValid} - errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationSource'].errorText} - value={props.dataMap['general/storageDataReplication/storageReplicationSource']} - onChange={(sRepSource) => props.onQDataChanged({'general/storageDataReplication/storageReplicationSource' : sRepSource})} /> - </GridItem> - <GridItem> - <Input - data-test-id='vsp-storage-rep-freq' - label={i18n('Storage Replication Freq. (min)')} - type='number' - isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationFrequency'].isValid} - errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationFrequency'].errorText} - value={props.dataMap['general/storageDataReplication/storageReplicationFrequency']} - onChange={(sRepFreq) => props.onQDataChanged({'general/storageDataReplication/storageReplicationFrequency' : sRepFreq})} /> - </GridItem> - <GridItem> - <Input - data-test-id='vsp-storage-rep-dest' - label={i18n('Storage Replication Destination')} - type='text' - isValid={props.genericFieldInfo['general/storageDataReplication/storageReplicationDestination'].isValid} - errorText={props.genericFieldInfo['general/storageDataReplication/storageReplicationDestination'].errorText} - value={props.dataMap['general/storageDataReplication/storageReplicationDestination']} - onChange={(sRepDest) => props.onQDataChanged({'general/storageDataReplication/storageReplicationDestination' : sRepDest})} /> - </GridItem> - </GridSection> +const StorageDataReplicationSection = props => ( + <GridSection title={i18n('Storage Data Replication')}> + <GridItem> + <Input + data-test-id="vsp-storage-rep-size" + label={i18n('Storage Replication Size (GB)')} + type="number" + isValid={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationSize' + ].isValid + } + errorText={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationSize' + ].errorText + } + value={ + props.dataMap[ + 'general/storageDataReplication/storageReplicationSize' + ] + } + onChange={sRep => + props.onQDataChanged({ + 'general/storageDataReplication/storageReplicationSize': sRep + }) + } + /> + </GridItem> + <GridItem> + <Input + data-test-id="vsp-storage-rep-source" + label={i18n('Storage Replication Source')} + type="text" + isValid={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationSource' + ].isValid + } + errorText={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationSource' + ].errorText + } + value={ + props.dataMap[ + 'general/storageDataReplication/storageReplicationSource' + ] + } + onChange={sRepSource => + props.onQDataChanged({ + 'general/storageDataReplication/storageReplicationSource': sRepSource + }) + } + /> + </GridItem> + <GridItem> + <Input + data-test-id="vsp-storage-rep-freq" + label={i18n('Storage Replication Freq. (min)')} + type="number" + isValid={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationFrequency' + ].isValid + } + errorText={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationFrequency' + ].errorText + } + value={ + props.dataMap[ + 'general/storageDataReplication/storageReplicationFrequency' + ] + } + onChange={sRepFreq => + props.onQDataChanged({ + 'general/storageDataReplication/storageReplicationFrequency': sRepFreq + }) + } + /> + </GridItem> + <GridItem> + <Input + data-test-id="vsp-storage-rep-dest" + label={i18n('Storage Replication Destination')} + type="text" + isValid={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationDestination' + ].isValid + } + errorText={ + props.genericFieldInfo[ + 'general/storageDataReplication/storageReplicationDestination' + ].errorText + } + value={ + props.dataMap[ + 'general/storageDataReplication/storageReplicationDestination' + ] + } + onChange={sRepDest => + props.onQDataChanged({ + 'general/storageDataReplication/storageReplicationDestination': sRepDest + }) + } + /> + </GridItem> + </GridSection> ); class SoftwareProductDetails extends Component { + static propTypes = { + vendorName: PropTypes.string, + currentSoftwareProduct: PropTypes.shape({ + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + category: PropTypes.string, + subCategory: PropTypes.string, + vendorId: PropTypes.string, + vendorName: PropTypes.string, + licensingVersion: PropTypes.string, + licensingData: PropTypes.shape({ + licenceAgreement: PropTypes.string, + featureGroups: PropTypes.array + }) + }), + softwareProductCategories: PropTypes.array, + finalizedLicenseModelList: PropTypes.array, + licenseAgreementList: PropTypes.array, + featureGroupsList: PropTypes.array, + onSubmit: PropTypes.func.isRequired, + onDataChanged: PropTypes.func.isRequired, + onValidityChanged: PropTypes.func.isRequired, + qdata: PropTypes.object.isRequired, + onQDataChanged: PropTypes.func.isRequired, + onVendorParamChanged: PropTypes.func.isRequired + }; - static propTypes = { - vendorName: PropTypes.string, - currentSoftwareProduct: PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - category: PropTypes.string, - subCategory: PropTypes.string, - vendorId: PropTypes.string, - vendorName: PropTypes.string, - licensingVersion: PropTypes.string, - licensingData: PropTypes.shape({ - licenceAgreement: PropTypes.string, - featureGroups: PropTypes.array - }) - }), - softwareProductCategories: PropTypes.array, - finalizedLicenseModelList: PropTypes.array, - licenseAgreementList: PropTypes.array, - featureGroupsList: PropTypes.array, - onSubmit: PropTypes.func.isRequired, - onDataChanged: PropTypes.func.isRequired, - onValidityChanged: PropTypes.func.isRequired, - qdata: PropTypes.object.isRequired, - onQDataChanged: PropTypes.func.isRequired, - onVendorParamChanged: PropTypes.func.isRequired - }; - - prepareDataForGeneralSection(){ - let {softwareProductCategories, finalizedLicenseModelList, onDataChanged, currentSoftwareProduct, genericFieldInfo, isVendorArchived, onArchivedVendorRemove} = this.props; - let {name, description, vendorId, subCategory, vendorName} = currentSoftwareProduct; - return { - name, - description, - vendorId, - subCategory, - softwareProductCategories, - finalizedLicenseModelList, - onDataChanged, - onVendorParamChanged: args => this.onVendorParamChanged(args), - onSelectSubCategory: args => this.onSelectSubCategory(args), - genericFieldInfo, - vendorName, - isVendorArchived, - onArchivedVendorRemove - }; - - } + prepareDataForGeneralSection() { + let { + softwareProductCategories, + finalizedLicenseModelList, + onDataChanged, + currentSoftwareProduct, + genericFieldInfo, + isVendorArchived, + onArchivedVendorRemove + } = this.props; + let { + name, + description, + vendorId, + subCategory, + vendorName + } = currentSoftwareProduct; + return { + name, + description, + vendorId, + subCategory, + softwareProductCategories, + finalizedLicenseModelList, + onDataChanged, + onVendorParamChanged: args => this.onVendorParamChanged(args), + onSelectSubCategory: args => this.onSelectSubCategory(args), + genericFieldInfo, + vendorName, + isVendorArchived, + onArchivedVendorRemove + }; + } - prepareDataForLicensesSection(){ - let { featureGroupsList, licenseAgreementList, currentSoftwareProduct, isVendorArchived} = this.props; - let {vendorId, licensingVersion, licensingData = {}} = currentSoftwareProduct; - return { - onVendorParamChanged: args => this.onVendorParamChanged(args), - vendorId, - licensingVersion, - licensingVersionsList: this.buildLicensingVersionsListItems(), - licensingData, - onFeatureGroupsChanged: args => this.onFeatureGroupsChanged(args), - onLicensingDataChanged: args => this.onLicensingDataChanged(args), - featureGroupsList, - licenseAgreementList, - isVendorArchived - }; + prepareDataForLicensesSection() { + let { + featureGroupsList, + licenseAgreementList, + currentSoftwareProduct, + isVendorArchived + } = this.props; + let { + vendorId, + licensingVersion, + licensingData = {} + } = currentSoftwareProduct; + return { + onVendorParamChanged: args => this.onVendorParamChanged(args), + vendorId, + licensingVersion, + licensingVersionsList: this.buildLicensingVersionsListItems(), + licensingData, + onFeatureGroupsChanged: args => this.onFeatureGroupsChanged(args), + onLicensingDataChanged: args => this.onLicensingDataChanged(args), + featureGroupsList, + licenseAgreementList, + isVendorArchived + }; + } - } + render() { + let { currentSoftwareProduct } = this.props; + let { qdata, onQDataChanged, dataMap, qGenericFieldInfo } = this.props; + let { isReadOnlyMode } = this.props; - render() { - let {currentSoftwareProduct} = this.props; - let {qdata, onQDataChanged, dataMap, qGenericFieldInfo} = this.props; - let {isReadOnlyMode} = this.props; + return ( + <div className="vsp-details-page"> + <Form + ref={validationForm => + (this.validationForm = validationForm) + } + className="vsp-general-tab" + hasButtons={false} + formReady={null} + isValid={this.props.isFormValid} + onSubmit={() => + this.props.onSubmit(currentSoftwareProduct, qdata) + } + onValidityChanged={isValidityData => + this.props.onValidityChanged(isValidityData) + } + isReadOnlyMode={isReadOnlyMode}> + <GeneralSection {...this.prepareDataForGeneralSection()} /> + <LicensesSection + {...this.prepareDataForLicensesSection()} + /> + <AvailabilitySection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + /> + <RegionsSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + genericFieldInfo={qGenericFieldInfo} + /> + <StorageDataReplicationSection + onQDataChanged={onQDataChanged} + dataMap={dataMap} + genericFieldInfo={qGenericFieldInfo} + /> + </Form> + </div> + ); + } - return ( - <div className='vsp-details-page'> - <Form - ref={(validationForm) => this.validationForm = validationForm} - className='vsp-general-tab' - hasButtons={false} - formReady={null} - isValid={this.props.isFormValid} - onSubmit={() => this.props.onSubmit(currentSoftwareProduct, qdata)} - onValidityChanged={(isValidityData) => this.props.onValidityChanged(isValidityData)} - isReadOnlyMode={isReadOnlyMode}> - <GeneralSection {...this.prepareDataForGeneralSection()}/> - <LicensesSection {...this.prepareDataForLicensesSection()}/> - <AvailabilitySection onQDataChanged={onQDataChanged} dataMap={dataMap} /> - <RegionsSection onQDataChanged={onQDataChanged} dataMap={dataMap} genericFieldInfo={qGenericFieldInfo} /> - <StorageDataReplicationSection onQDataChanged={onQDataChanged} dataMap={dataMap} genericFieldInfo={qGenericFieldInfo} /> - </Form> - </div> - ); - } + onVendorParamChanged({ vendorId, licensingVersion }) { + let { finalizedLicenseModelList, onVendorParamChanged } = this.props; + if (!licensingVersion) { + const licensingVersionsList = this.buildLicensingVersionsListItems(); + licensingVersion = licensingVersionsList[0].enum; + } - onVendorParamChanged({vendorId, licensingVersion}) { - - let {finalizedLicenseModelList, onVendorParamChanged} = this.props; - if(!licensingVersion) { - const licensingVersionsList = this.buildLicensingVersionsListItems(); - licensingVersion = licensingVersionsList[0].enum; - } - - if (!vendorId) { - vendorId = finalizedLicenseModelList[0].id; - } - - let vendorName = finalizedLicenseModelList.find(licenseModelItem => licenseModelItem.id === vendorId).name || ''; - let deltaData = { - vendorId, - vendorName, - licensingVersion, - licensingData: {} - }; + if (!vendorId) { + vendorId = finalizedLicenseModelList[0].id; + } - onVendorParamChanged(deltaData, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); + let vendorName = + finalizedLicenseModelList.find( + licenseModelItem => licenseModelItem.id === vendorId + ).name || ''; + let deltaData = { + vendorId, + vendorName, + licensingVersion, + licensingData: {} + }; - } + onVendorParamChanged(deltaData, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); + } - buildLicensingVersionsListItems() { - let {licensingVersionsList} = this.props; + buildLicensingVersionsListItems() { + let { licensingVersionsList } = this.props; - let licensingVersionsListItems = [{ - enum: '', - title: i18n('Select...') - }]; + let licensingVersionsListItems = [ + { + enum: '', + title: i18n('Select...') + } + ]; - return licensingVersionsListItems.concat(licensingVersionsList.map(version => ({enum: version.id, title: version.name}))); - } + return licensingVersionsListItems.concat( + licensingVersionsList.map(version => ({ + enum: version.id, + title: version.name + })) + ); + } - onFeatureGroupsChanged({featureGroups}) { - this.onLicensingDataChanged({featureGroups}); - } + onFeatureGroupsChanged({ featureGroups }) { + this.onLicensingDataChanged({ featureGroups }); + } - onLicensingDataChanged(deltaData) { - this.props.onDataChanged({ - licensingData: { - ...this.props.currentSoftwareProduct.licensingData, - ...deltaData - } - }, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); - } + onLicensingDataChanged(deltaData) { + this.props.onDataChanged( + { + licensingData: { + ...this.props.currentSoftwareProduct.licensingData, + ...deltaData + } + }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ); + } - onSelectSubCategory(subCategory) { - let {softwareProductCategories, onDataChanged} = this.props; - let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory(subCategory, softwareProductCategories); - onDataChanged({category, subCategory}, forms.VENDOR_SOFTWARE_PRODUCT_DETAILS); - } + onSelectSubCategory(subCategory) { + let { softwareProductCategories, onDataChanged } = this.props; + let category = SoftwareProductCategoriesHelper.getCurrentCategoryOfSubCategory( + subCategory, + softwareProductCategories + ); + onDataChanged( + { category, subCategory }, + forms.VENDOR_SOFTWARE_PRODUCT_DETAILS + ); + } - save(){ - return this.validationForm.handleFormSubmit(new Event('dummy')); - } + save() { + return this.validationForm.handleFormSubmit(new Event('dummy')); + } } export default SoftwareProductDetails; 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 64e0d562ce..34bfceec24 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPage.js @@ -13,106 +13,134 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.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'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { onboardingMethod } from '../SoftwareProductConstants.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; - +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; export const mapStateToProps = ({ - softwareProduct, - licenseModel: {licenseAgreement}, + softwareProduct, + licenseModel: { licenseAgreement } }) => { - let {softwareProductEditor: {data:currentSoftwareProduct = {}}, softwareProductComponents, softwareProductCategories = [], } = softwareProduct; - let {licensingData = {}} = currentSoftwareProduct; - let {licenseAgreementList} = licenseAgreement; - let {componentsList} = softwareProductComponents; - let licenseAgreementName = licenseAgreementList.find(la => la.id === licensingData.licenseAgreement); - if (licenseAgreementName) { - licenseAgreementName = licenseAgreementName.name; - } else if (licenseAgreementList.length === 0) { // otherwise the state of traingle svgicon will be updated post unmounting - licenseAgreementName = null; - } - - let categoryName = '', subCategoryName = '', fullCategoryDisplayName = ''; - const category = softwareProductCategories.find(ca => ca.uniqueId === currentSoftwareProduct.category); - if (category) { - categoryName = category.name; - const subcategories = category.subcategories || []; - const subcat = subcategories.find(sc => sc.uniqueId === currentSoftwareProduct.subCategory); - subCategoryName = subcat && subcat.name ? subcat.name : ''; - } - fullCategoryDisplayName = `${subCategoryName} (${categoryName})`; + let { + softwareProductEditor: { data: currentSoftwareProduct = {} }, + softwareProductComponents, + softwareProductCategories = [] + } = softwareProduct; + let { licensingData = {} } = currentSoftwareProduct; + let { licenseAgreementList } = licenseAgreement; + let { componentsList } = softwareProductComponents; + let licenseAgreementName = licenseAgreementList.find( + la => la.id === licensingData.licenseAgreement + ); + if (licenseAgreementName) { + licenseAgreementName = licenseAgreementName.name; + } else if (licenseAgreementList.length === 0) { + // otherwise the state of traingle svgicon will be updated post unmounting + licenseAgreementName = null; + } + let categoryName = '', + subCategoryName = '', + fullCategoryDisplayName = ''; + const category = softwareProductCategories.find( + ca => ca.uniqueId === currentSoftwareProduct.category + ); + if (category) { + categoryName = category.name; + const subcategories = category.subcategories || []; + const subcat = subcategories.find( + sc => sc.uniqueId === currentSoftwareProduct.subCategory + ); + subCategoryName = subcat && subcat.name ? subcat.name : ''; + } + fullCategoryDisplayName = `${subCategoryName} (${categoryName})`; - return { - currentSoftwareProduct: { - ...currentSoftwareProduct, - licenseAgreementName, - fullCategoryDisplayName - }, - componentsList, - isManual: currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL - }; + return { + currentSoftwareProduct: { + ...currentSoftwareProduct, + licenseAgreementName, + fullCategoryDisplayName + }, + componentsList, + isManual: + currentSoftwareProduct.onboardingMethod === onboardingMethod.MANUAL + }; }; -const mapActionsToProps = (dispatch, {version}) => { - return { - onDetailsSelect: ({id: softwareProductId}) => - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }), - onCandidateInProcess: (softwareProductId) => ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version} - }), - onUpload: (softwareProductId, formData) => - SoftwareProductActionHelper.uploadFile(dispatch, { - softwareProductId, - formData, - failedNotificationTitle: i18n('Upload validation failed'), - version - }), +const mapActionsToProps = (dispatch, { version }) => { + return { + onDetailsSelect: ({ id: softwareProductId }) => + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_DETAILS, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }), + onCandidateInProcess: softwareProductId => + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_ATTACHMENTS_SETUP, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version } + }), + onUpload: (softwareProductId, formData) => + SoftwareProductActionHelper.uploadFile(dispatch, { + softwareProductId, + formData, + failedNotificationTitle: i18n('Upload validation failed'), + version + }), - onUploadConfirmation: (softwareProductId, formData) => - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Upload will erase existing data. Do you want to continue?'), - confirmationButtonText: i18n('Continue'), - title: i18n('Warning'), - onConfirmed: ()=>SoftwareProductActionHelper.uploadFile(dispatch, { - softwareProductId, - formData, - failedNotificationTitle: i18n('Upload validation failed'), - version - }), - onDeclined: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }) - } - }), + onUploadConfirmation: (softwareProductId, formData) => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n( + 'Upload will erase existing data. Do you want to continue?' + ), + confirmationButtonText: i18n('Continue'), + title: i18n('Warning'), + onConfirmed: () => + SoftwareProductActionHelper.uploadFile(dispatch, { + softwareProductId, + formData, + failedNotificationTitle: i18n( + 'Upload validation failed' + ), + version + }), + onDeclined: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }) + } + }), - onInvalidFileSizeUpload: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_ERROR, - data: { - title: i18n('Upload Failed'), - confirmationButtonText: i18n('Continue'), - msg: i18n('no zip or csar file was uploaded or expected file doesn\'t exist') - } - }), - onComponentSelect: ({id: softwareProductId, componentId}) => ScreensHelper.loadScreen(dispatch, { - screen: screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId, version, componentId} - }), - /** for the next version */ - onAddComponent: () => SoftwareProductActionHelper.addComponent(dispatch) - }; + onInvalidFileSizeUpload: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_ERROR, + data: { + title: i18n('Upload Failed'), + confirmationButtonText: i18n('Continue'), + msg: i18n( + "no zip or csar file was uploaded or expected file doesn't exist" + ) + } + }), + onComponentSelect: ({ id: softwareProductId, componentId }) => + ScreensHelper.loadScreen(dispatch, { + screen: screenTypes.SOFTWARE_PRODUCT_COMPONENT_DEFAULT_GENERAL, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId, version, componentId } + }), + /** for the next version */ + onAddComponent: () => SoftwareProductActionHelper.addComponent(dispatch) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(LandingPageView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(LandingPageView); 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 a73a849a08..bc8a2be646 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/landingPage/SoftwareProductLandingPageView.jsx @@ -18,7 +18,6 @@ import PropTypes from 'prop-types'; import classnames from 'classnames'; import Dropzone from 'react-dropzone'; - import i18n from 'nfvo-utils/i18n/i18n.js'; import DraggableUploadFileBox from 'nfvo-components/fileupload/DraggableUploadFileBox.jsx'; @@ -26,192 +25,237 @@ import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import SoftwareProductComponentsList from 'sdc-app/onboarding/softwareProduct/components/SoftwareProductComponents.js'; const SoftwareProductPropType = PropTypes.shape({ - name: PropTypes.string, - description: PropTypes.string, - version: PropTypes.string, - id: PropTypes.string, - categoryId: PropTypes.string, - vendorId: PropTypes.string, - status: PropTypes.string, - licensingData: PropTypes.object, - validationData: PropTypes.object + name: PropTypes.string, + description: PropTypes.string, + version: PropTypes.string, + id: PropTypes.string, + categoryId: PropTypes.string, + vendorId: PropTypes.string, + status: PropTypes.string, + licensingData: PropTypes.object, + validationData: PropTypes.object }); const ComponentPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - displayName: PropTypes.string, - description: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + displayName: PropTypes.string, + description: PropTypes.string }); class SoftwareProductLandingPageView extends React.Component { + state = { + fileName: '', + dragging: false, + files: [] + }; + + static propTypes = { + currentSoftwareProduct: SoftwareProductPropType, + isReadOnlyMode: PropTypes.bool, + componentsList: PropTypes.arrayOf(ComponentPropType), + version: PropTypes.object, + onDetailsSelect: PropTypes.func, + onUpload: PropTypes.func, + onUploadConfirmation: PropTypes.func, + onInvalidFileSizeUpload: PropTypes.func, + onComponentSelect: PropTypes.func, + onAddComponent: PropTypes.func + }; + componentDidMount() { + const { onCandidateInProcess, currentSoftwareProduct } = this.props; + if (currentSoftwareProduct.candidateOnboardingOrigin) { + onCandidateInProcess(currentSoftwareProduct.id); + } + } + render() { + let { + currentSoftwareProduct, + isReadOnlyMode, + isManual, + onDetailsSelect + } = 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, isManual) + } + onDragEnter={() => + this.handleOnDragEnter(isReadOnlyMode, isManual) + } + onDragLeave={() => this.setState({ dragging: false })} + multiple={false} + disableClick={true} + ref="fileInput" + name="fileInput" + accept=".zip, .csar"> + <div className="draggable-wrapper"> + <div className="software-product-landing-view-top"> + <div className="row"> + <ProductSummary + currentSoftwareProduct={ + currentSoftwareProduct + } + onDetailsSelect={onDetailsSelect} + /> + {this.renderProductDetails( + isManual, + isReadOnlyMode + )} + </div> + </div> + </div> + </Dropzone> + <SoftwareProductComponentsList /> + </div> + ); + } + + handleOnDragEnter(isReadOnlyMode, isManual) { + if (!isReadOnlyMode && !isManual) { + this.setState({ dragging: true }); + } + } + + renderProductDetails(isManual, isReadOnlyMode) { + return ( + <div className="details-panel"> + {!isManual && ( + <div> + <div className="software-product-landing-view-heading-title"> + {i18n('Software Product Attachments')} + </div> + <DraggableUploadFileBox + dataTestId="upload-btn" + isReadOnlyMode={isReadOnlyMode} + className={classnames( + 'software-product-landing-view-top-block-col-upl', + { disabled: isReadOnlyMode } + )} + onClick={() => this.refs.fileInput.open()} + /> + </div> + )} + </div> + ); + } + + handleImportSubmit(files, isReadOnlyMode, isManual) { + if (isReadOnlyMode || isManual) { + return; + } + if (files[0] && files[0].size) { + this.setState({ + fileName: files[0].name, + dragging: false, + complete: '0' + }); + this.startUploading(files); + } else { + this.setState({ + dragging: false + }); + this.props.onInvalidFileSizeUpload(); + } + } - state = { - - fileName: '', - dragging: false, - files: [] - }; - - static propTypes = { - currentSoftwareProduct: SoftwareProductPropType, - isReadOnlyMode: PropTypes.bool, - componentsList: PropTypes.arrayOf(ComponentPropType), - version: PropTypes.object, - onDetailsSelect: PropTypes.func, - onUpload: PropTypes.func, - onUploadConfirmation: PropTypes.func, - onInvalidFileSizeUpload: PropTypes.func, - onComponentSelect: PropTypes.func, - onAddComponent: PropTypes.func - }; - componentDidMount() { - const {onCandidateInProcess, currentSoftwareProduct} = this.props; - if (currentSoftwareProduct.candidateOnboardingOrigin) { - onCandidateInProcess(currentSoftwareProduct.id); - } - } - render() { - let {currentSoftwareProduct, isReadOnlyMode, isManual, onDetailsSelect} = 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, isManual)} - onDragEnter={() => this.handleOnDragEnter(isReadOnlyMode, isManual)} - onDragLeave={() => this.setState({dragging:false})} - multiple={false} - disableClick={true} - ref='fileInput' - name='fileInput' - accept='.zip, .csar'> - <div className='draggable-wrapper'> - <div className='software-product-landing-view-top'> - <div className='row'> - <ProductSummary currentSoftwareProduct={currentSoftwareProduct} onDetailsSelect={onDetailsSelect} /> - {this.renderProductDetails(isManual, isReadOnlyMode)} - </div> - </div> - </div> - </Dropzone> - <SoftwareProductComponentsList/> - </div> - ); - } - - handleOnDragEnter(isReadOnlyMode, isManual) { - if (!isReadOnlyMode && !isManual) { - this.setState({dragging: true}); - } - } - - renderProductDetails(isManual, isReadOnlyMode) { - return ( - <div className='details-panel'> - { !isManual && <div> - <div className='software-product-landing-view-heading-title'>{i18n('Software Product Attachments')}</div> - <DraggableUploadFileBox - dataTestId='upload-btn' - isReadOnlyMode={isReadOnlyMode} - className={classnames('software-product-landing-view-top-block-col-upl', {'disabled': isReadOnlyMode})} - onClick={() => this.refs.fileInput.open()}/> - </div> - } - </div> - ); - } - - handleImportSubmit(files, isReadOnlyMode, isManual) { - if (isReadOnlyMode || isManual) { - return; - } - if (files[0] && files[0].size) { - this.setState({ - fileName: files[0].name, - dragging: false, - complete: '0', - }); - this.startUploading(files); - } - else { - this.setState({ - dragging: false - }); - this.props.onInvalidFileSizeUpload(); - } - - } - - startUploading(files) { - let {onUpload, currentSoftwareProduct, onUploadConfirmation} = this.props; - - let {validationData} = currentSoftwareProduct; - - if (!(files && files.length)) { - return; - } - let file = files[0]; - let formData = new FormData(); - formData.append('upload', file); - this.refs.fileInput.value = ''; - - if (validationData) { - onUploadConfirmation(currentSoftwareProduct.id, formData); - }else { - onUpload(currentSoftwareProduct.id, formData); - } - - } + startUploading(files) { + let { + onUpload, + currentSoftwareProduct, + onUploadConfirmation + } = this.props; + + let { validationData } = currentSoftwareProduct; + + if (!(files && files.length)) { + return; + } + let file = files[0]; + let formData = new FormData(); + formData.append('upload', file); + this.refs.fileInput.value = ''; + + if (validationData) { + onUploadConfirmation(currentSoftwareProduct.id, formData); + } else { + onUpload(currentSoftwareProduct.id, formData); + } + } } -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 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 color='warning' name='exclamationTriangleFull'/><div className='warning-text'>{i18n('Missing')}</div></div>); - } - return <div>{licenseAgreementName}</div>; +const LicenseAgreement = ({ licenseAgreementName }) => { + if (!licenseAgreementName) { + return ( + <div className="missing-license"> + <SVGIcon color="warning" 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/networks/SoftwareProductNetworks.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworks.js index 6161eadba9..27dd471a00 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworks.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworks.js @@ -13,13 +13,14 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SoftwareProductNetworksView from './SoftwareProductNetworksView.jsx'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductNetworks: {networksList = []}} = softwareProduct; - return {networksList}; +export const mapStateToProps = ({ softwareProduct }) => { + let { softwareProductNetworks: { networksList = [] } } = softwareProduct; + return { networksList }; }; -export default connect(mapStateToProps, null, null, {withRef: true})(SoftwareProductNetworksView); - +export default connect(mapStateToProps, null, null, { withRef: true })( + SoftwareProductNetworksView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksActionHelper.js index 4cb460ecc6..388c641b46 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksActionHelper.js @@ -13,30 +13,29 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductNetworksConstants.js'; +import { actionTypes } from './SoftwareProductNetworksConstants.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; function baseUrl(vspId, version) { - let {id: versionId} = version; - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/networks`; + let { id: versionId } = version; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/networks`; } - function fetchNetworksList(softwareProductId, version) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); } const SoftwareProductNetworksActionHelper = { - fetchNetworksList(dispatch, {softwareProductId, version}) { - return fetchNetworksList(softwareProductId, version).then(response => { - dispatch({ - type: actionTypes.FETCH_SOFTWARE_PRODUCT_NETWORKS, - networksList: response.results - }); - }); - } + fetchNetworksList(dispatch, { softwareProductId, version }) { + return fetchNetworksList(softwareProductId, version).then(response => { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_NETWORKS, + networksList: response.results + }); + }); + } }; -export default SoftwareProductNetworksActionHelper; +export default SoftwareProductNetworksActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksConstants.js index a3d5578dc4..17e4bdfe8d 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksConstants.js @@ -16,5 +16,5 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - FETCH_SOFTWARE_PRODUCT_NETWORKS: null, + FETCH_SOFTWARE_PRODUCT_NETWORKS: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksListReducer.js index e7c2fcb045..796de822df 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksListReducer.js @@ -13,13 +13,13 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductNetworksConstants.js'; +import { actionTypes } from './SoftwareProductNetworksConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FETCH_SOFTWARE_PRODUCT_NETWORKS: - return [...action.networksList]; - default: - return state; - } + switch (action.type) { + case actionTypes.FETCH_SOFTWARE_PRODUCT_NETWORKS: + return [...action.networksList]; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksView.jsx index e8c365f124..458f3192f4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/networks/SoftwareProductNetworksView.jsx @@ -22,73 +22,76 @@ import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.js import ListEditorItemViewField from 'nfvo-components/listEditor/ListEditorItemViewField.jsx'; class SoftwareProductNetworksView extends React.Component { + static propTypes = { + networksList: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.string.isRequired, + name: PropTypes.string.isRequired, + dhcp: PropTypes.bool.isRequired + }) + ).isRequired, + isReadOnlyMode: PropTypes.bool.isRequired + }; - static propTypes = { - networksList: PropTypes.arrayOf(PropTypes.shape({ - id: PropTypes.string.isRequired, - name: PropTypes.string.isRequired, - dhcp: PropTypes.bool.isRequired - })).isRequired, - isReadOnlyMode: PropTypes.bool.isRequired - }; + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; + render() { + const { localFilter } = this.state; + const { isReadOnlyMode } = this.props; - render() { - const {localFilter} = this.state; - const {isReadOnlyMode} = this.props; + return ( + <div className="vsp-networks-page"> + <ListEditorView + title={i18n('Networks')} + filterValue={localFilter} + placeholder={i18n('Filter Networks')} + onFilter={value => this.setState({ localFilter: value })} + twoColumns> + {this.filterList().map(network => + this.renderNetworksListItem({ network, isReadOnlyMode }) + )} + </ListEditorView> + </div> + ); + } - return ( - <div className='vsp-networks-page'> - <ListEditorView - title={i18n('Networks')} - filterValue={localFilter} - placeholder={i18n('Filter Networks')} - onFilter={value => this.setState({localFilter: value})} - twoColumns> - {this.filterList().map(network => this.renderNetworksListItem({network, isReadOnlyMode}))} - </ListEditorView> - </div> - ); - } + renderNetworksListItem({ network, isReadOnlyMode }) { + let { id, name, dhcp } = network; + return ( + <ListEditorItemView + key={id} + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode}> + <ListEditorItemViewField> + <div className="name">{name}</div> + </ListEditorItemViewField> + <ListEditorItemViewField> + <div className="details"> + <div className="title">{i18n('DHCP')}</div> + <div className="artifact-name"> + {dhcp ? i18n('YES') : i18n('NO')} + </div> + </div> + </ListEditorItemViewField> + </ListEditorItemView> + ); + } - renderNetworksListItem({network, isReadOnlyMode}) { - let {id, name, dhcp} = network; - return ( - <ListEditorItemView - key={id} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode}> + filterList() { + let { networksList } = this.props; - <ListEditorItemViewField> - <div className='name'>{name}</div> - </ListEditorItemViewField> - <ListEditorItemViewField> - <div className='details'> - <div className='title'>{i18n('DHCP')}</div> - <div className='artifact-name'>{dhcp ? i18n('YES') : i18n('NO')}</div> - </div> - </ListEditorItemViewField> - </ListEditorItemView> - ); - } - - filterList() { - let {networksList} = this.props; - - let {localFilter} = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return networksList.filter(({name = ''}) => { - return escape(name).match(filter); - }); - } - else { - return networksList; - } - } + let { localFilter } = this.state; + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return networksList.filter(({ name = '' }) => { + return escape(name).match(filter); + }); + } else { + return networksList; + } + } } export default SoftwareProductNetworksView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessListView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessListView.jsx index aa39c87dd0..cee46abc69 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessListView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessListView.jsx @@ -20,80 +20,86 @@ import i18n from 'nfvo-utils/i18n/i18n.js'; import ListEditorView from 'nfvo-components/listEditor/ListEditorView.jsx'; import ListEditorItemView from 'nfvo-components/listEditor/ListEditorItemView.jsx'; - class SoftwareProductProcessesListView extends React.Component { + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; - - static propTypes = { - onAddProcess: PropTypes.func.isRequired, - onEditProcess: PropTypes.func.isRequired, - onDeleteProcess: PropTypes.func.isRequired, - isReadOnlyMode: PropTypes.bool.isRequired, - currentSoftwareProduct:PropTypes.object, - addButtonTitle: PropTypes.string - }; - - render() { - const {localFilter} = this.state; - let {onAddProcess, isReadOnlyMode, addButtonTitle} = this.props; + static propTypes = { + onAddProcess: PropTypes.func.isRequired, + onEditProcess: PropTypes.func.isRequired, + onDeleteProcess: PropTypes.func.isRequired, + isReadOnlyMode: PropTypes.bool.isRequired, + currentSoftwareProduct: PropTypes.object, + addButtonTitle: PropTypes.string + }; - return ( - <ListEditorView - plusButtonTitle={addButtonTitle} - filterValue={localFilter} - placeholder={i18n('Filter Process')} - onAdd={onAddProcess} - isReadOnlyMode={isReadOnlyMode} - title={i18n('Process Details')} - onFilter={value => this.setState({localFilter: value})}> - {this.filterList().map(processes => this.renderProcessListItem(processes, isReadOnlyMode))} - </ListEditorView>); - } + render() { + const { localFilter } = this.state; + let { onAddProcess, isReadOnlyMode, addButtonTitle } = this.props; - renderProcessListItem(process, isReadOnlyMode) { - let {id, name, description, artifactName = ''} = process; - let {currentSoftwareProduct: {version}, onEditProcess, onDeleteProcess} = this.props; - return ( - <ListEditorItemView - key={id} - className='list-editor-item-view' - isReadOnlyMode={isReadOnlyMode} - onSelect={() => onEditProcess(process)} - onDelete={() => onDeleteProcess(process, version)}> + return ( + <ListEditorView + plusButtonTitle={addButtonTitle} + filterValue={localFilter} + placeholder={i18n('Filter Process')} + onAdd={onAddProcess} + isReadOnlyMode={isReadOnlyMode} + title={i18n('Process Details')} + onFilter={value => this.setState({ localFilter: value })}> + {this.filterList().map(processes => + this.renderProcessListItem(processes, isReadOnlyMode) + )} + </ListEditorView> + ); + } - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Name')}</div> - <div className='name'>{name}</div> - </div> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Artifact name')}</div> - <div className='artifact-name'>{artifactName}</div> - </div> - <div className='list-editor-item-view-field'> - <div className='title'>{i18n('Notes')}</div> - <div className='description'>{description}</div> - </div> - </ListEditorItemView> - ); - } + renderProcessListItem(process, isReadOnlyMode) { + let { id, name, description, artifactName = '' } = process; + let { + currentSoftwareProduct: { version }, + onEditProcess, + onDeleteProcess + } = this.props; + return ( + <ListEditorItemView + key={id} + className="list-editor-item-view" + isReadOnlyMode={isReadOnlyMode} + onSelect={() => onEditProcess(process)} + onDelete={() => onDeleteProcess(process, version)}> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Name')}</div> + <div className="name">{name}</div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Artifact name')}</div> + <div className="artifact-name">{artifactName}</div> + </div> + <div className="list-editor-item-view-field"> + <div className="title">{i18n('Notes')}</div> + <div className="description">{description}</div> + </div> + </ListEditorItemView> + ); + } - filterList() { - let {processesList} = this.props; - let {localFilter} = this.state; + filterList() { + let { processesList } = this.props; + let { localFilter } = this.state; - if (localFilter.trim()) { - const filter = new RegExp(escape(localFilter), 'i'); - return processesList.filter(({name = '', description = ''}) => { - return escape(name).match(filter) || escape(description).match(filter); - }); - } - else { - return processesList; - } - } + if (localFilter.trim()) { + const filter = new RegExp(escape(localFilter), 'i'); + return processesList.filter(({ name = '', description = '' }) => { + return ( + escape(name).match(filter) || + escape(description).match(filter) + ); + }); + } else { + return processesList; + } + } } export default SoftwareProductProcessesListView; 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 b0403abde5..fb44530dae 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcesses.js @@ -13,40 +13,57 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import SoftwareProductProcessesActionHelper from './SoftwareProductProcessesActionHelper.js'; import SoftwareProductProcessesView from './SoftwareProductProcessesView.jsx'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductEditor: {data: currentSoftwareProduct = {}}, softwareProductProcesses: {processesList, processesEditor}} = softwareProduct; - let {data} = processesEditor; +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductEditor: { data: currentSoftwareProduct = {} }, + softwareProductProcesses: { processesList, processesEditor } + } = softwareProduct; + let { data } = processesEditor; - return { - currentSoftwareProduct, - processesList, - isDisplayEditor: Boolean(data), - isModalInEditMode: Boolean(data && data.id) - }; + return { + currentSoftwareProduct, + processesList, + isDisplayEditor: Boolean(data), + isModalInEditMode: Boolean(data && data.id) + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onAddProcess: () => SoftwareProductProcessesActionHelper.openEditor(dispatch), - onEditProcess: (process) => SoftwareProductProcessesActionHelper.openEditor(dispatch, process), - onDeleteProcess: (process) => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data:{ - msg: i18n('Are you sure you want to delete "{name}"?', {name: process.name}), - confirmationButtonText: i18n('Delete'), - title: i18n('Delete'), - onConfirmed: ()=> SoftwareProductProcessesActionHelper.deleteProcess(dispatch, - {process, softwareProductId, version}) - } - }) - }; +const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onAddProcess: () => + SoftwareProductProcessesActionHelper.openEditor(dispatch), + onEditProcess: process => + SoftwareProductProcessesActionHelper.openEditor(dispatch, process), + onDeleteProcess: process => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + msg: i18n('Are you sure you want to delete "{name}"?', { + name: process.name + }), + confirmationButtonText: i18n('Delete'), + title: i18n('Delete'), + onConfirmed: () => + SoftwareProductProcessesActionHelper.deleteProcess( + dispatch, + { + process, + softwareProductId, + version + } + ) + } + }) + }; }; -export default connect(mapStateToProps, mapActionsToProps, null, {withRef: true})(SoftwareProductProcessesView); +export default connect(mapStateToProps, mapActionsToProps, null, { + withRef: true +})(SoftwareProductProcessesView); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesActionHelper.js index 8fd370b6cc..7c72c5b892 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesActionHelper.js @@ -13,127 +13,145 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductProcessesConstants.js'; +import { actionTypes } from './SoftwareProductProcessesConstants.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; function baseUrl(vspId, version) { - let {id: versionId} = version; - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/processes`; + let { id: versionId } = version; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/vendor-software-products/${vspId}/versions/${versionId}/processes`; } function putProcess(softwareProductId, version, process) { - return RestAPIUtil.put(`${baseUrl(softwareProductId, version)}/${process.id}`, { - name: process.name, - description: process.description, - type: process.type === '' ? null : process.type - }); + return RestAPIUtil.put( + `${baseUrl(softwareProductId, version)}/${process.id}`, + { + name: process.name, + description: process.description, + type: process.type === '' ? null : process.type + } + ); } function postProcess(softwareProductId, version, process) { - return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { - name: process.name, - description: process.description, - type: process.type === '' ? null : process.type - }); + return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}`, { + name: process.name, + description: process.description, + type: process.type === '' ? null : process.type + }); } function deleteProcess(softwareProductId, version, processId) { - return RestAPIUtil.destroy(`${baseUrl(softwareProductId, version)}/${processId}`); + return RestAPIUtil.destroy( + `${baseUrl(softwareProductId, version)}/${processId}` + ); } -function uploadFileToProcess(softwareProductId, version, processId, formData) -{ - return RestAPIUtil.post(`${baseUrl(softwareProductId, version)}/${processId}/upload`, formData); +function uploadFileToProcess(softwareProductId, version, processId, formData) { + return RestAPIUtil.post( + `${baseUrl(softwareProductId, version)}/${processId}/upload`, + formData + ); } function fetchProcesses(softwareProductId, version) { - return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); + return RestAPIUtil.fetch(`${baseUrl(softwareProductId, version)}`); } const SoftwareProductActionHelper = { - - fetchProcessesList(dispatch, {softwareProductId, version}) { - - dispatch({ - type: actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES, - processesList: [] - }); - - return fetchProcesses(softwareProductId, version).then(response => { - dispatch({ - type: actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES, - processesList: response.results - }); - }); - }, - openEditor(dispatch, process = {}) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN, - process - }); - }, - - deleteProcess(dispatch, {process, softwareProductId, version}) { - return deleteProcess(softwareProductId, version, process.id).then(() => { - dispatch({ - type: actionTypes.DELETE_SOFTWARE_PRODUCT_PROCESS, - processId: process.id - }); - }); - - }, - - closeEditor(dispatch) { - dispatch({ - type:actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE - }); - }, - - saveProcess(dispatch, {softwareProductId, version, previousProcess, process}) { - if (previousProcess) { - return putProcess(softwareProductId, version, process).then(() => { - if (process.formData){ - uploadFileToProcess(softwareProductId, version, process.id, process.formData); - } - dispatch({ - type: actionTypes.EDIT_SOFTWARE_PRODUCT_PROCESS, - process - }); - }); - } - else { - return postProcess(softwareProductId, version, process).then(response => { - if (process.formData) { - uploadFileToProcess(softwareProductId, version, response.value, process.formData); - } - dispatch({ - type: actionTypes.ADD_SOFTWARE_PRODUCT_PROCESS, - process: { - ...process, - id: response.value - } - }); - }); - } - }, - - hideDeleteConfirm(dispatch) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM, - processToDelete: false - }); - }, - - openDeleteProcessesConfirm(dispatch, {process} ) { - dispatch({ - type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM, - processToDelete: process - }); - } - + fetchProcessesList(dispatch, { softwareProductId, version }) { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES, + processesList: [] + }); + + return fetchProcesses(softwareProductId, version).then(response => { + dispatch({ + type: actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES, + processesList: response.results + }); + }); + }, + openEditor(dispatch, process = {}) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN, + process + }); + }, + + deleteProcess(dispatch, { process, softwareProductId, version }) { + return deleteProcess(softwareProductId, version, process.id).then( + () => { + dispatch({ + type: actionTypes.DELETE_SOFTWARE_PRODUCT_PROCESS, + processId: process.id + }); + } + ); + }, + + closeEditor(dispatch) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE + }); + }, + + saveProcess( + dispatch, + { softwareProductId, version, previousProcess, process } + ) { + if (previousProcess) { + return putProcess(softwareProductId, version, process).then(() => { + if (process.formData) { + uploadFileToProcess( + softwareProductId, + version, + process.id, + process.formData + ); + } + dispatch({ + type: actionTypes.EDIT_SOFTWARE_PRODUCT_PROCESS, + process + }); + }); + } else { + return postProcess(softwareProductId, version, process).then( + response => { + if (process.formData) { + uploadFileToProcess( + softwareProductId, + version, + response.value, + process.formData + ); + } + dispatch({ + type: actionTypes.ADD_SOFTWARE_PRODUCT_PROCESS, + process: { + ...process, + id: response.value + } + }); + } + ); + } + }, + + hideDeleteConfirm(dispatch) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM, + processToDelete: false + }); + }, + + openDeleteProcessesConfirm(dispatch, { process }) { + dispatch({ + type: actionTypes.SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM, + processToDelete: process + }); + } }; export default SoftwareProductActionHelper; - diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesConstants.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesConstants.js index 6eee24cdde..7f09ea8e73 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesConstants.js @@ -16,20 +16,20 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - ADD_SOFTWARE_PRODUCT_PROCESS: null, - EDIT_SOFTWARE_PRODUCT_PROCESS: null, - DELETE_SOFTWARE_PRODUCT_PROCESS: null, - SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN: null, - SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE: null, - FETCH_SOFTWARE_PRODUCT_PROCESSES: null, - SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM: null + ADD_SOFTWARE_PRODUCT_PROCESS: null, + EDIT_SOFTWARE_PRODUCT_PROCESS: null, + DELETE_SOFTWARE_PRODUCT_PROCESS: null, + SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN: null, + SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE: null, + FETCH_SOFTWARE_PRODUCT_PROCESSES: null, + SOFTWARE_PRODUCT_PROCESS_DELETE_CONFIRM: null }); export const optionsInputValues = { - PROCESS_TYPE: [ - {title: 'Select...', enum: ''}, - {title: 'Other', enum: 'Other'} - ] + PROCESS_TYPE: [ + { title: 'Select...', enum: '' }, + { title: 'Other', enum: 'Other' } + ] }; export const VSP_PROCESS_FORM = 'VSPPROCESSFORM'; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditor.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditor.js index fc194fac13..58cc894a21 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditor.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditor.js @@ -13,41 +13,56 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; import SoftwareProductProcessesActionHelper from './SoftwareProductProcessesActionHelper'; import SoftwareProductProcessesEditorView from './SoftwareProductProcessesEditorView.jsx'; -import {VSP_PROCESS_FORM} from './SoftwareProductProcessesConstants.js'; +import { VSP_PROCESS_FORM } from './SoftwareProductProcessesConstants.js'; -export const mapStateToProps = ({softwareProduct}) => { - let {softwareProductProcesses: {processesList, processesEditor}} = softwareProduct; - let {data, genericFieldInfo, formReady} = processesEditor; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - let previousData; - const processId = data ? data.id : null; - if(processId) { - previousData = processesList.find(process => process.id === processId); - } +export const mapStateToProps = ({ softwareProduct }) => { + let { + softwareProductProcesses: { processesList, processesEditor } + } = softwareProduct; + let { data, genericFieldInfo, formReady } = processesEditor; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); + let previousData; + const processId = data ? data.id : null; + if (processId) { + previousData = processesList.find(process => process.id === processId); + } - return { - data, - genericFieldInfo, - previousData, - isFormValid, - formReady - }; + return { + data, + genericFieldInfo, + previousData, + isFormValid, + formReady + }; }; -const mapActionsToProps = (dispatch, {softwareProductId, version}) => { - return { - onDataChanged: (deltaData) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: VSP_PROCESS_FORM}), - onSubmit: ({previousProcess, process}) => { - SoftwareProductProcessesActionHelper.closeEditor(dispatch); - SoftwareProductProcessesActionHelper.saveProcess(dispatch, {softwareProductId, version, previousProcess, process}); - }, - onCancel: () => SoftwareProductProcessesActionHelper.closeEditor(dispatch), - onValidateForm: () => ValidationHelper.validateForm(dispatch, VSP_PROCESS_FORM) - }; +const mapActionsToProps = (dispatch, { softwareProductId, version }) => { + return { + onDataChanged: deltaData => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: VSP_PROCESS_FORM + }), + onSubmit: ({ previousProcess, process }) => { + SoftwareProductProcessesActionHelper.closeEditor(dispatch); + SoftwareProductProcessesActionHelper.saveProcess(dispatch, { + softwareProductId, + version, + previousProcess, + process + }); + }, + onCancel: () => + SoftwareProductProcessesActionHelper.closeEditor(dispatch), + onValidateForm: () => + ValidationHelper.validateForm(dispatch, VSP_PROCESS_FORM) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(SoftwareProductProcessesEditorView); +export default connect(mapStateToProps, mapActionsToProps)( + SoftwareProductProcessesEditorView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorForm.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorForm.jsx index d1bd602683..6e8254f65b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorForm.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorForm.jsx @@ -25,157 +25,212 @@ import GridSection from 'nfvo-components/grid/GridSection.jsx'; import GridItem from 'nfvo-components/grid/GridItem.jsx'; const SoftwareProductProcessEditorPropType = PropTypes.shape({ - id: PropTypes.string, - name: PropTypes.string, - description: PropTypes.string, - artifactName: PropTypes.string, - type: PropTypes.string + id: PropTypes.string, + name: PropTypes.string, + description: PropTypes.string, + artifactName: PropTypes.string, + type: PropTypes.string }); - - class SoftwareProductProcessesEditorForm extends React.Component { + static propTypes = { + data: SoftwareProductProcessEditorPropType, + previousData: SoftwareProductProcessEditorPropType, + isReadOnlyMode: PropTypes.bool, + onDataChanged: PropTypes.func, + onSubmit: PropTypes.func, + onCancel: PropTypes.func + }; + state = { + dragging: false, + files: [] + }; + render() { + let { + data = {}, + isReadOnlyMode, + onDataChanged, + onCancel, + genericFieldInfo, + optionsInputValues + } = this.props; + let { name, description, artifactName, type } = data; - static propTypes = { - data: SoftwareProductProcessEditorPropType, - previousData: SoftwareProductProcessEditorPropType, - isReadOnlyMode: PropTypes.bool, - onDataChanged: PropTypes.func, - onSubmit: PropTypes.func, - onCancel: PropTypes.func - }; - state = { - dragging: false, - files: [] - }; - - render() { - let {data = {}, isReadOnlyMode, onDataChanged, onCancel, genericFieldInfo, optionsInputValues} = this.props; - let {name, description, artifactName, type} = data; - - return ( - <div> - {genericFieldInfo && <Form - ref='validationForm' - hasButtons={true} - labledButtons={true} - isReadOnlyMode={isReadOnlyMode} - onSubmit={ () => this.submit() } - onReset={ () => onCancel() } - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.props.onValidateForm() } - className='vsp-processes-editor'> - <div className={`vsp-processes-editor-data${isReadOnlyMode ? ' disabled' : '' }`}> - <Dropzone - className={`vsp-process-dropzone-view ${this.state.dragging ? 'active-dragging' : ''}`} - onDrop={(acceptedFiles, rejectedFiles) => this.handleImportSubmit(acceptedFiles, rejectedFiles)} - onDragEnter={() => this.setState({dragging: true})} - onDragLeave={() => this.setState({dragging: false})} - multiple={false} - disableClick={true} - ref='processEditorFileInput' - name='processEditorFileInput'> - <GridSection hasLastColSet={true}> - <GridItem colSpan={2}> - <Input - onChange={name => onDataChanged({name})} - isValid={genericFieldInfo.name.isValid} - isRequired={true} - data-test-id='name' - errorText={genericFieldInfo.name.errorText} - label={i18n('Name')} - value={name} - type='text'/> - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - <label> </label> - <DraggableUploadFileBox className='process-editor-file-box' isReadOnlyMode={isReadOnlyMode} onClick={() => this.refs.processEditorFileInput.open()}/> - </GridItem> - </GridSection> - <GridSection hasLastColSet={true}> - <GridItem colSpan={2}> - <Input - name='vsp-process-description' - groupClassName='vsp-process-description' - onChange={description => onDataChanged({description})} - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - label={i18n('Notes')} - value={description} - data-test-id='vsp-process-description' - type='textarea'/> - </GridItem> - <GridItem colSpan={2} lastColInRow={true}> - <Input - label={i18n('Artifacts')} - value={artifactName} - type='text' - disabled/> - <Input - onChange={e => { - // setting the unit to the correct value - const selectedIndex = e.target.selectedIndex; - const val = e.target.options[selectedIndex].value; - onDataChanged({type: val});} - } - value={type} - label={i18n('Process Type')} - className='process-type' - data-test-id='process-type' - isValid={genericFieldInfo.type.isValid} - errorText={genericFieldInfo.type.errorText} - type='select'> - {optionsInputValues.PROCESS_TYPE.map(mtype => - <option key={mtype.enum} value={mtype.enum}>{`${mtype.title}`}</option>)} - </Input> - </GridItem> - </GridSection> - </Dropzone> - </div> - </Form>} - </div> - ); - } - - submit() { - const {data: process, previousData: previousProcess} = this.props; - let {files} = this.state; - let formData = false; - if (files.length) { - let file = files[0]; - formData = new FormData(); - formData.append('upload', file); - } + return ( + <div> + {genericFieldInfo && ( + <Form + ref="validationForm" + hasButtons={true} + labledButtons={true} + isReadOnlyMode={isReadOnlyMode} + onSubmit={() => this.submit()} + onReset={() => onCancel()} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => this.props.onValidateForm()} + className="vsp-processes-editor"> + <div + className={`vsp-processes-editor-data${ + isReadOnlyMode ? ' disabled' : '' + }`}> + <Dropzone + className={`vsp-process-dropzone-view ${ + this.state.dragging ? 'active-dragging' : '' + }`} + onDrop={(acceptedFiles, rejectedFiles) => + this.handleImportSubmit( + acceptedFiles, + rejectedFiles + ) + } + onDragEnter={() => + this.setState({ dragging: true }) + } + onDragLeave={() => + this.setState({ dragging: false }) + } + multiple={false} + disableClick={true} + ref="processEditorFileInput" + name="processEditorFileInput"> + <GridSection hasLastColSet={true}> + <GridItem colSpan={2}> + <Input + onChange={name => + onDataChanged({ name }) + } + isValid={ + genericFieldInfo.name.isValid + } + isRequired={true} + data-test-id="name" + errorText={ + genericFieldInfo.name.errorText + } + label={i18n('Name')} + value={name} + type="text" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow={true}> + <label> </label> + <DraggableUploadFileBox + className="process-editor-file-box" + isReadOnlyMode={isReadOnlyMode} + onClick={() => + this.refs.processEditorFileInput.open() + } + /> + </GridItem> + </GridSection> + <GridSection hasLastColSet={true}> + <GridItem colSpan={2}> + <Input + name="vsp-process-description" + groupClassName="vsp-process-description" + onChange={description => + onDataChanged({ description }) + } + isValid={ + genericFieldInfo.description + .isValid + } + errorText={ + genericFieldInfo.description + .errorText + } + label={i18n('Notes')} + value={description} + data-test-id="vsp-process-description" + type="textarea" + /> + </GridItem> + <GridItem colSpan={2} lastColInRow={true}> + <Input + label={i18n('Artifacts')} + value={artifactName} + type="text" + disabled + /> + <Input + onChange={e => { + // setting the unit to the correct value + const selectedIndex = + e.target.selectedIndex; + const val = + e.target.options[ + selectedIndex + ].value; + onDataChanged({ type: val }); + }} + value={type} + label={i18n('Process Type')} + className="process-type" + data-test-id="process-type" + isValid={ + genericFieldInfo.type.isValid + } + errorText={ + genericFieldInfo.type.errorText + } + type="select"> + {optionsInputValues.PROCESS_TYPE.map( + mtype => ( + <option + key={mtype.enum} + value={mtype.enum}>{`${ + mtype.title + }`}</option> + ) + )} + </Input> + </GridItem> + </GridSection> + </Dropzone> + </div> + </Form> + )} + </div> + ); + } - let updatedProcess = { - ...process, - formData - }; - this.props.onSubmit({process: updatedProcess, previousProcess}); - } + submit() { + const { data: process, previousData: previousProcess } = this.props; + let { files } = this.state; + let formData = false; + if (files.length) { + let file = files[0]; + formData = new FormData(); + formData.append('upload', file); + } + let updatedProcess = { + ...process, + formData + }; + this.props.onSubmit({ process: updatedProcess, previousProcess }); + } - handleImportSubmit(files, rejectedFiles) { - if (files.length > 0) { - let {onDataChanged} = this.props; - this.setState({ - dragging: false, - complete: '0', - files - }); - onDataChanged({artifactName: files[0].name}); - } - else if (rejectedFiles.length > 0) { - this.setState({ - dragging: false - }); - if (DEBUG) { - console.log('file was rejected.' + rejectedFiles[0].name); - } - } - } + handleImportSubmit(files, rejectedFiles) { + if (files.length > 0) { + let { onDataChanged } = this.props; + this.setState({ + dragging: false, + complete: '0', + files + }); + onDataChanged({ artifactName: files[0].name }); + } else if (rejectedFiles.length > 0) { + this.setState({ + dragging: false + }); + if (DEBUG) { + console.log('file was rejected.' + rejectedFiles[0].name); + } + } + } } export default SoftwareProductProcessesEditorForm; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorReducer.js index 11b89b17c2..a8731fd163 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorReducer.js @@ -13,43 +13,49 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, VSP_PROCESS_FORM} from './SoftwareProductProcessesConstants.js'; +import { + actionTypes, + VSP_PROCESS_FORM +} from './SoftwareProductProcessesConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN: - return { - ...state, - formReady: null, - formName: VSP_PROCESS_FORM, - genericFieldInfo: { - 'name' : { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - 'description' : { - isValid: true, - errorText: '', - validations: [{type: 'maxLength', data: 1000}] - }, - 'artifactName' : { - isValid: true, - errorText: '', - validations: [] - }, - 'type' : { - isValid: true, - errorText: '', - validations: [] - } - }, - data: action.process - }; - case actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE: - return {}; + switch (action.type) { + case actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_OPEN: + return { + ...state, + formReady: null, + formName: VSP_PROCESS_FORM, + genericFieldInfo: { + name: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + description: { + isValid: true, + errorText: '', + validations: [{ type: 'maxLength', data: 1000 }] + }, + artifactName: { + isValid: true, + errorText: '', + validations: [] + }, + type: { + isValid: true, + errorText: '', + validations: [] + } + }, + data: action.process + }; + case actionTypes.SOFTWARE_PRODUCT_PROCESS_EDITOR_CLOSE: + return {}; - default: - return state; - } + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorView.jsx index 9ce690a1ca..867090bb31 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesEditorView.jsx @@ -15,16 +15,18 @@ */ import React from 'react'; -import {optionsInputValues as ProcessesOptionsInputValues} from './SoftwareProductProcessesConstants.js'; +import { optionsInputValues as ProcessesOptionsInputValues } from './SoftwareProductProcessesConstants.js'; import SoftwareProductProcessesEditorForm from './SoftwareProductProcessesEditorForm.jsx'; - class SoftwareProductProcessesEditorView extends React.Component { - render() { - return ( - <SoftwareProductProcessesEditorForm optionsInputValues={ProcessesOptionsInputValues} {...this.props}/> - ); - } + render() { + return ( + <SoftwareProductProcessesEditorForm + optionsInputValues={ProcessesOptionsInputValues} + {...this.props} + /> + ); + } } export default SoftwareProductProcessesEditorView; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesListReducer.js b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesListReducer.js index 20390d1f60..0e4d94650e 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesListReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesListReducer.js @@ -13,20 +13,26 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './SoftwareProductProcessesConstants.js'; +import { actionTypes } from './SoftwareProductProcessesConstants.js'; export default (state = [], action) => { - switch (action.type) { - case actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES: - return [...action.processesList]; - case actionTypes.EDIT_SOFTWARE_PRODUCT_PROCESS: - const indexForEdit = state.findIndex(process => process.id === action.process.id); - return [...state.slice(0, indexForEdit), action.process, ...state.slice(indexForEdit + 1)]; - case actionTypes.ADD_SOFTWARE_PRODUCT_PROCESS: - return [...state, action.process]; - case actionTypes.DELETE_SOFTWARE_PRODUCT_PROCESS: - return state.filter(process => process.id !== action.processId); - default: - return state; - } + switch (action.type) { + case actionTypes.FETCH_SOFTWARE_PRODUCT_PROCESSES: + return [...action.processesList]; + case actionTypes.EDIT_SOFTWARE_PRODUCT_PROCESS: + const indexForEdit = state.findIndex( + process => process.id === action.process.id + ); + return [ + ...state.slice(0, indexForEdit), + action.process, + ...state.slice(indexForEdit + 1) + ]; + case actionTypes.ADD_SOFTWARE_PRODUCT_PROCESS: + return [...state, action.process]; + case actionTypes.DELETE_SOFTWARE_PRODUCT_PROCESS: + return state.filter(process => process.id !== action.processId); + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesView.jsx b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesView.jsx index b0da767a2b..1357c31e12 100644 --- a/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/softwareProduct/processes/SoftwareProductProcessesView.jsx @@ -20,45 +20,63 @@ import Modal from 'nfvo-components/modal/Modal.jsx'; import SoftwareProductProcessesEditor from './SoftwareProductProcessesEditor.js'; import SoftwareProductProcessListView from './SoftwareProductProcessListView.jsx'; - class SoftwareProductProcessesView extends React.Component { + state = { + localFilter: '' + }; - state = { - localFilter: '' - }; - - static propTypes = { - onAddProcess: PropTypes.func.isRequired, - onEditProcess: PropTypes.func.isRequired, - onDeleteProcess: PropTypes.func.isRequired, - isDisplayEditor: PropTypes.bool.isRequired, - isReadOnlyMode: PropTypes.bool.isRequired, - currentSoftwareProduct:PropTypes.object - }; - - render() { - return ( - <div className='software-product-landing-view-right-side vsp-processes-page'> - {this.renderEditor()} - <SoftwareProductProcessListView addButtonTitle={i18n('Add Process Details')} {...this.props}/> - </div> - ); - } + static propTypes = { + onAddProcess: PropTypes.func.isRequired, + onEditProcess: PropTypes.func.isRequired, + onDeleteProcess: PropTypes.func.isRequired, + isDisplayEditor: PropTypes.bool.isRequired, + isReadOnlyMode: PropTypes.bool.isRequired, + currentSoftwareProduct: PropTypes.object + }; - renderEditor() { - let {currentSoftwareProduct: {id}, version, isModalInEditMode, isReadOnlyMode, isDisplayEditor} = this.props; - return ( + render() { + return ( + <div className="software-product-landing-view-right-side vsp-processes-page"> + {this.renderEditor()} + <SoftwareProductProcessListView + addButtonTitle={i18n('Add Process Details')} + {...this.props} + /> + </div> + ); + } - <Modal show={isDisplayEditor} bsSize='large' animation={true} className='onborading-modal'> - <Modal.Header> - <Modal.Title>{isModalInEditMode ? i18n('Edit Process Details') : i18n('Create New Process Details')}</Modal.Title> - </Modal.Header> - <Modal.Body className='edit-process-modal'> - <SoftwareProductProcessesEditor softwareProductId={id} version={version} isReadOnlyMode={isReadOnlyMode}/> - </Modal.Body> - </Modal> - ); - } + renderEditor() { + let { + currentSoftwareProduct: { id }, + version, + isModalInEditMode, + isReadOnlyMode, + isDisplayEditor + } = this.props; + return ( + <Modal + show={isDisplayEditor} + bsSize="large" + animation={true} + className="onborading-modal"> + <Modal.Header> + <Modal.Title> + {isModalInEditMode + ? i18n('Edit Process Details') + : i18n('Create New Process Details')} + </Modal.Title> + </Modal.Header> + <Modal.Body className="edit-process-modal"> + <SoftwareProductProcessesEditor + softwareProductId={id} + version={version} + isReadOnlyMode={isReadOnlyMode} + /> + </Modal.Body> + </Modal> + ); + } } export default SoftwareProductProcessesView; diff --git a/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsReducer.js b/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsReducer.js index 2c3442ee68..a3004995d7 100644 --- a/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsReducer.js @@ -14,59 +14,66 @@ * permissions and limitations under the License. */ -import {actionTypes} from './UserNotificationsConstants.js'; +import { actionTypes } from './UserNotificationsConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.NOTIFICATION: - let list = (state.notificationsList) ? state.notificationsList : []; - const {notifications, lastScanned} = action.data; - return { - ...state, - lastScanned, - notificationsList: [...notifications, ...list], - numOfNotSeenNotifications: state.numOfNotSeenNotifications + notifications.length - }; - case actionTypes.LOAD_NOTIFICATIONS: - return { - ...state, - ...action.result, - notificationsList: action.result.notifications, - notifications: undefined - }; - case actionTypes.LOAD_PREV_NOTIFICATIONS: - const {notifications: prevNotifications, endOfPage: newEndOfPage} = action.result; - return { - ...state, - notificationsList: [ - ...state.notificationsList, - ...prevNotifications - ], - endOfPage: newEndOfPage - }; - case actionTypes.UPDATE_READ_NOTIFICATION: - let {notificationForUpdate} = action; - notificationForUpdate = {...notificationForUpdate, read: true}; - const indexForEdit = state.notificationsList.findIndex(notification => notification.eventId === notificationForUpdate.eventId); - return { - ...state, - notificationsList: [ - ...state.notificationsList.slice(0, indexForEdit), - notificationForUpdate, - ...state.notificationsList.slice(indexForEdit + 1) - ] - }; - case actionTypes.RESET_NEW_NOTIFICATIONS: - return { - ...state, - numOfNotSeenNotifications: 0 - }; - case actionTypes.TOGGLE_OVERLAY: - return { - ...state, - showNotificationsOverlay: action.showNotificationsOverlay - }; - default: - return state; - } + switch (action.type) { + case actionTypes.NOTIFICATION: + let list = state.notificationsList ? state.notificationsList : []; + const { notifications, lastScanned } = action.data; + return { + ...state, + lastScanned, + notificationsList: [...notifications, ...list], + numOfNotSeenNotifications: + state.numOfNotSeenNotifications + notifications.length + }; + case actionTypes.LOAD_NOTIFICATIONS: + return { + ...state, + ...action.result, + notificationsList: action.result.notifications, + notifications: undefined + }; + case actionTypes.LOAD_PREV_NOTIFICATIONS: + const { + notifications: prevNotifications, + endOfPage: newEndOfPage + } = action.result; + return { + ...state, + notificationsList: [ + ...state.notificationsList, + ...prevNotifications + ], + endOfPage: newEndOfPage + }; + case actionTypes.UPDATE_READ_NOTIFICATION: + let { notificationForUpdate } = action; + notificationForUpdate = { ...notificationForUpdate, read: true }; + const indexForEdit = state.notificationsList.findIndex( + notification => + notification.eventId === notificationForUpdate.eventId + ); + return { + ...state, + notificationsList: [ + ...state.notificationsList.slice(0, indexForEdit), + notificationForUpdate, + ...state.notificationsList.slice(indexForEdit + 1) + ] + }; + case actionTypes.RESET_NEW_NOTIFICATIONS: + return { + ...state, + numOfNotSeenNotifications: 0 + }; + case actionTypes.TOGGLE_OVERLAY: + return { + ...state, + showNotificationsOverlay: action.showNotificationsOverlay + }; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsView.jsx b/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsView.jsx index de105d23a7..7f5b334586 100644 --- a/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/userNotifications/NotificationsView.jsx @@ -18,89 +18,155 @@ import React from 'react'; import PropTypes from 'prop-types'; import enhanceWithClickOutside from 'react-click-outside'; import classnames from 'classnames'; -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; import Overlay from 'nfvo-components/overlay/Overlay.jsx'; import UserNotifications from 'sdc-app/onboarding/userNotifications/UserNotifications.jsx'; import UserNotificationsActionHelper from 'sdc-app/onboarding/userNotifications/UserNotificationsActionHelper.js'; -import {actionTypes} from './UserNotificationsConstants.js'; +import { actionTypes } from './UserNotificationsConstants.js'; import OnboardingActionHelper from 'sdc-app/onboarding/OnboardingActionHelper.js'; -const mapStateToProps = ({currentScreen, notifications, users: {usersList}}) => { - return {currentScreen, notifications, usersList}; +const mapStateToProps = ({ + currentScreen, + notifications, + users: { usersList } +}) => { + return { currentScreen, notifications, usersList }; }; -const mapActionToProps = (dispatch) => { - return { - resetNewNotifications: notificationId => UserNotificationsActionHelper.updateLastSeenNotification(dispatch, {notificationId}), - toggleOverlay: ({showNotificationsOverlay}) => dispatch({type: actionTypes.TOGGLE_OVERLAY, showNotificationsOverlay}), - onLoadPrevNotifications: (lastScanned, endOfPage) => UserNotificationsActionHelper.loadPreviousNotifications(dispatch, {lastScanned, endOfPage}), - onSync: ({itemId, itemName, versionId, versionName, currentScreen}) => UserNotificationsActionHelper.syncItem(dispatch, {itemId, itemName, versionId, versionName, currentScreen}), - updateNotification: notificationForUpdate => UserNotificationsActionHelper.updateNotification(dispatch, {notificationForUpdate}), - onLoadItemsLists: () => OnboardingActionHelper.loadItemsLists(dispatch) - }; +const mapActionToProps = dispatch => { + return { + resetNewNotifications: notificationId => + UserNotificationsActionHelper.updateLastSeenNotification(dispatch, { + notificationId + }), + toggleOverlay: ({ showNotificationsOverlay }) => + dispatch({ + type: actionTypes.TOGGLE_OVERLAY, + showNotificationsOverlay + }), + onLoadPrevNotifications: (lastScanned, endOfPage) => + UserNotificationsActionHelper.loadPreviousNotifications(dispatch, { + lastScanned, + endOfPage + }), + onSync: ({ itemId, itemName, versionId, versionName, currentScreen }) => + UserNotificationsActionHelper.syncItem(dispatch, { + itemId, + itemName, + versionId, + versionName, + currentScreen + }), + updateNotification: notificationForUpdate => + UserNotificationsActionHelper.updateNotification(dispatch, { + notificationForUpdate + }), + onLoadItemsLists: () => OnboardingActionHelper.loadItemsLists(dispatch) + }; }; - class NotificationsView extends React.Component { + static propTypes = { + currentScreen: PropTypes.object, + notifications: PropTypes.object, + resetNewNotifications: PropTypes.func, + toggleOverlay: PropTypes.func, + onLoadPrevNotifications: PropTypes.func, + onSync: PropTypes.func, + updateNotification: PropTypes.func, + onLoadItemsLists: PropTypes.func + }; - static propTypes = { - currentScreen: PropTypes.object, - notifications: PropTypes.object, - resetNewNotifications: PropTypes.func, - toggleOverlay: PropTypes.func, - onLoadPrevNotifications: PropTypes.func, - onSync: PropTypes.func, - updateNotification: PropTypes.func, - onLoadItemsLists: PropTypes.func - }; - - render() { - const {usersList, notifications, onLoadPrevNotifications, onSync, updateNotification, onLoadItemsLists, currentScreen} = this.props; - const {notificationsList, numOfNotSeenNotifications, showNotificationsOverlay, lastScanned, endOfPage} = notifications; + render() { + const { + usersList, + notifications, + onLoadPrevNotifications, + onSync, + updateNotification, + onLoadItemsLists, + currentScreen + } = this.props; + const { + notificationsList, + numOfNotSeenNotifications, + showNotificationsOverlay, + lastScanned, + endOfPage + } = notifications; - return ( - <div className='onboarding-notifications'> - <div className='notifications-icon' onClick={() => this.onNotificationIconClick()}> - <SVGIcon name={numOfNotSeenNotifications > 0 ? 'notificationFullBell' : 'notificationBell'} color={numOfNotSeenNotifications > 0 ? 'primary' : ''}/> - <div className={classnames('notifications-count', {'hidden-count': numOfNotSeenNotifications === 0})}> - {numOfNotSeenNotifications} - </div> - </div> - {showNotificationsOverlay && - <Overlay> - <UserNotifications notificationsList={notificationsList} usersList={usersList} lastScanned={lastScanned} endOfPage={endOfPage} - onLoadPrevNotifications={onLoadPrevNotifications} onSync={onSync} updateNotification={updateNotification} onLoadItemsLists={onLoadItemsLists} - currentScreen={currentScreen}/> - </Overlay> - } - </div> - ); - } + return ( + <div className="onboarding-notifications"> + <div + className="notifications-icon" + onClick={() => this.onNotificationIconClick()}> + <SVGIcon + name={ + numOfNotSeenNotifications > 0 + ? 'notificationFullBell' + : 'notificationBell' + } + color={numOfNotSeenNotifications > 0 ? 'primary' : ''} + /> + <div + className={classnames('notifications-count', { + 'hidden-count': numOfNotSeenNotifications === 0 + })}> + {numOfNotSeenNotifications} + </div> + </div> + {showNotificationsOverlay && ( + <Overlay> + <UserNotifications + notificationsList={notificationsList} + usersList={usersList} + lastScanned={lastScanned} + endOfPage={endOfPage} + onLoadPrevNotifications={onLoadPrevNotifications} + onSync={onSync} + updateNotification={updateNotification} + onLoadItemsLists={onLoadItemsLists} + currentScreen={currentScreen} + /> + </Overlay> + )} + </div> + ); + } - handleClickOutside() { - const {notifications: {showNotificationsOverlay}} = this.props; - if(showNotificationsOverlay) { - this.onCloseOverlay(); - } - } + handleClickOutside() { + const { notifications: { showNotificationsOverlay } } = this.props; + if (showNotificationsOverlay) { + this.onCloseOverlay(); + } + } - onNotificationIconClick() { - const {notifications: {showNotificationsOverlay}, toggleOverlay} = this.props; - if (showNotificationsOverlay) { - this.onCloseOverlay(); - } else { - toggleOverlay({showNotificationsOverlay: true}); - } - } + onNotificationIconClick() { + const { + notifications: { showNotificationsOverlay }, + toggleOverlay + } = this.props; + if (showNotificationsOverlay) { + this.onCloseOverlay(); + } else { + toggleOverlay({ showNotificationsOverlay: true }); + } + } - onCloseOverlay() { - const {notifications: {numOfNotSeenNotifications, lastScanned}, resetNewNotifications, toggleOverlay} = this.props; - if (numOfNotSeenNotifications) { - resetNewNotifications(lastScanned); - } - toggleOverlay({showNotificationsOverlay: false}); - } + onCloseOverlay() { + const { + notifications: { numOfNotSeenNotifications, lastScanned }, + resetNewNotifications, + toggleOverlay + } = this.props; + if (numOfNotSeenNotifications) { + resetNewNotifications(lastScanned); + } + toggleOverlay({ showNotificationsOverlay: false }); + } } -export default connect(mapStateToProps, mapActionToProps)(enhanceWithClickOutside(NotificationsView)); +export default connect(mapStateToProps, mapActionToProps)( + enhanceWithClickOutside(NotificationsView) +); diff --git a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotifications.jsx b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotifications.jsx index fd5c04db92..01ca50cd4f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotifications.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotifications.jsx @@ -19,126 +19,193 @@ import PropTypes from 'prop-types'; import ReactDOM from 'react-dom'; import classnames from 'classnames'; import i18n from 'nfvo-utils/i18n/i18n.js'; -import {notificationType} from './UserNotificationsConstants.js'; +import { notificationType } from './UserNotificationsConstants.js'; import ShowMore from 'react-show-more'; -const Notification = ({notification, users, onActionClicked, getNotificationTypeDesc}) => { - const {eventType, read, eventAttributes, dateTime} = notification; - const {itemName, userId, description, versionName, permission, granted} = eventAttributes; - const {fullName: userName} = users.find(user => user.userId === userId); - return ( - <div className={classnames('notification', {'unread': !read})}> - <div className='notification-data'> - <div className='item-name'> - {itemName} - {versionName && <span> v{versionName}</span>} - {!read && <div className='unread-circle-icon'></div> } - </div> - <div className='flex-items'> - <div className='type'>{getNotificationTypeDesc(eventType, permission, granted)}</div> - <div className='separator'/> - <div className='user-name'>{`${i18n('By')} ${userName}`}</div> - </div> - {(description || versionName) && <div className='description'> - {description && <ShowMore anchorClass='more-less' lines={2} more={i18n('More')} less={i18n('Less')}> - {description} - </ShowMore>} - {eventType === notificationType.ITEM_CHANGED.SUBMIT && - <div> - <div>{i18n('Version {versionName} was submitted.', {versionName: versionName})}</div> - </div> - } - </div> - } - <div className='date'>{dateTime}</div> - </div> - <div className='notification-action'> - <div className={classnames('action-button', {'hidden': read})} onClick={() => onActionClicked(notification)}> - {eventType === notificationType.PERMISSION_CHANGED - || eventType === notificationType.ITEM_DELETED - || eventType === notificationType.ITEM_ARCHIVED - || eventType === notificationType.ITEM_RESTORED ? i18n('OK') : i18n('Sync')} - </div> - </div> - </div> - ); +const Notification = ({ + notification, + users, + onActionClicked, + getNotificationTypeDesc +}) => { + const { eventType, read, eventAttributes, dateTime } = notification; + const { + itemName, + userId, + description, + versionName, + permission, + granted + } = eventAttributes; + const { fullName: userName } = users.find(user => user.userId === userId); + return ( + <div className={classnames('notification', { unread: !read })}> + <div className="notification-data"> + <div className="item-name"> + {itemName} + {versionName && ( + <span> v{versionName}</span> + )} + {!read && <div className="unread-circle-icon" />} + </div> + <div className="flex-items"> + <div className="type"> + {getNotificationTypeDesc( + eventType, + permission, + granted + )} + </div> + <div className="separator" /> + <div className="user-name">{`${i18n( + 'By' + )} ${userName}`}</div> + </div> + {(description || versionName) && ( + <div className="description"> + {description && ( + <ShowMore + anchorClass="more-less" + lines={2} + more={i18n('More')} + less={i18n('Less')}> + {description} + </ShowMore> + )} + {eventType === notificationType.ITEM_CHANGED.SUBMIT && ( + <div> + <div> + {i18n( + 'Version {versionName} was submitted.', + { versionName: versionName } + )} + </div> + </div> + )} + </div> + )} + <div className="date">{dateTime}</div> + </div> + <div className="notification-action"> + <div + className={classnames('action-button', { hidden: read })} + onClick={() => onActionClicked(notification)}> + {eventType === notificationType.PERMISSION_CHANGED || + eventType === notificationType.ITEM_DELETED || + eventType === notificationType.ITEM_ARCHIVED || + eventType === notificationType.ITEM_RESTORED + ? i18n('OK') + : i18n('Sync')} + </div> + </div> + </div> + ); }; function getNotificationTypeDesc(eventType, permission, granted) { - switch (eventType) { - case notificationType.PERMISSION_CHANGED: - const grantedStr = granted ? i18n('Granted') : i18n('Taken'); - return `${i18n('Permission')} ${grantedStr}: ${permission}`; - case notificationType.ITEM_CHANGED.COMMIT: - return i18n('Your Copy Is Out Of Sync'); - case notificationType.ITEM_CHANGED.SUBMIT: - return i18n('Version Submitted'); - case notificationType.ITEM_DELETED: - return i18n('Item was deleted'); - case notificationType.ITEM_ARCHIVED: - return i18n('Item was archived'); - case notificationType.ITEM_RESTORED: - return i18n('Item was restored from archive'); - } + switch (eventType) { + case notificationType.PERMISSION_CHANGED: + const grantedStr = granted ? i18n('Granted') : i18n('Taken'); + return `${i18n('Permission')} ${grantedStr}: ${permission}`; + case notificationType.ITEM_CHANGED.COMMIT: + return i18n('Your Copy Is Out Of Sync'); + case notificationType.ITEM_CHANGED.SUBMIT: + return i18n('Version Submitted'); + case notificationType.ITEM_DELETED: + return i18n('Item was deleted'); + case notificationType.ITEM_ARCHIVED: + return i18n('Item was archived'); + case notificationType.ITEM_RESTORED: + return i18n('Item was restored from archive'); + } } class UserNotifications extends React.Component { + static propTypes = { + currentScreen: PropTypes.object, + notificationsList: PropTypes.array, + usersList: PropTypes.array, + lastScanned: PropTypes.string, + endOfPage: PropTypes.string, + onLoadPrevNotifications: PropTypes.func, + onSync: PropTypes.func, + updateNotification: PropTypes.func, + onLoadItemsLists: PropTypes.func + }; - static propTypes = { - currentScreen: PropTypes.object, - notificationsList: PropTypes.array, - usersList: PropTypes.array, - lastScanned: PropTypes.string, - endOfPage:PropTypes.string, - onLoadPrevNotifications: PropTypes.func, - onSync: PropTypes.func, - updateNotification: PropTypes.func, - onLoadItemsLists: PropTypes.func - }; + render() { + const { + notificationsList = [], + usersList, + lastScanned, + endOfPage + } = this.props; - render() { - const {notificationsList = [], usersList, lastScanned, endOfPage} = this.props; + return ( + <div className="user-notifications"> + <div className="notifications-title"> + {i18n('Notifications')} + </div> + <div + className="notifications-list" + ref="notificationList" + onScroll={() => + this.loadPrevNotifications(lastScanned, endOfPage) + }> + {notificationsList.map(notification => ( + <Notification + key={notification.eventId} + notification={notification} + users={usersList} + onActionClicked={notification => + this.onActionClicked(notification) + } + getNotificationTypeDesc={getNotificationTypeDesc} + /> + ))} + </div> + </div> + ); + } - return ( - <div className='user-notifications'> - <div className='notifications-title'>{i18n('Notifications')}</div> - <div className='notifications-list' ref='notificationList' onScroll={() => this.loadPrevNotifications(lastScanned, endOfPage)}> - { - notificationsList.map(notification => ( - <Notification key={notification.eventId} notification={notification} users={usersList} - onActionClicked={notification => this.onActionClicked(notification)} - getNotificationTypeDesc={getNotificationTypeDesc}/>)) - } - </div> - </div> - ); - } + onActionClicked(notification) { + const { + onSync, + updateNotification, + currentScreen, + onLoadItemsLists + } = this.props; + const { + eventType, + eventAttributes: { itemId, itemName, versionId, versionName } + } = notification; + if ( + eventType !== notificationType.PERMISSION_CHANGED && + eventType !== notificationType.ITEM_DELETED && + eventType !== notificationType.ITEM_ARCHIVED && + eventType !== notificationType.ITEM_RESTORED + ) { + onSync({ itemId, itemName, versionId, versionName, currentScreen }); + } else { + onLoadItemsLists(); + } + updateNotification(notification); + } - onActionClicked(notification) { - const {onSync, updateNotification, currentScreen, onLoadItemsLists} = this.props; - const {eventType, eventAttributes: {itemId, itemName, versionId, versionName}} = notification; - if(eventType !== notificationType.PERMISSION_CHANGED && - eventType !== notificationType.ITEM_DELETED && - eventType !== notificationType.ITEM_ARCHIVED && - eventType !== notificationType.ITEM_RESTORED) { - onSync({itemId, itemName, versionId, versionName, currentScreen}); - } - else { - onLoadItemsLists(); - } - updateNotification(notification); - } + loadPrevNotifications(lastScanned, endOfPage) { + if (endOfPage && lastScanned) { + let element = ReactDOM.findDOMNode(this.refs['notificationList']); + const { onLoadPrevNotifications } = this.props; - loadPrevNotifications(lastScanned, endOfPage) { - if(endOfPage && lastScanned) { - let element = ReactDOM.findDOMNode(this.refs['notificationList']); - const {onLoadPrevNotifications} = this.props; - - if (element && element.clientHeight + element.scrollTop === element.scrollHeight) { - onLoadPrevNotifications(lastScanned, endOfPage); - } - } - } + if ( + element && + element.clientHeight + element.scrollTop === + element.scrollHeight + ) { + onLoadPrevNotifications(lastScanned, endOfPage); + } + } + } } -export default UserNotifications;
\ No newline at end of file +export default UserNotifications; diff --git a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsActionHelper.js index 574aa0f3fc..f8693e15be 100644 --- a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsActionHelper.js @@ -1,123 +1,175 @@ -import {actionTypes} from './UserNotificationsConstants.js'; +import { actionTypes } from './UserNotificationsConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import Configuration from 'sdc-app/config/Configuration.js'; import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; -import WebSocketUtil, {websocketUrl} from 'nfvo-utils/WebSocketUtil.js'; -import {actionsEnum as VersionControllerActionsEnum} from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; +import WebSocketUtil, { websocketUrl } from 'nfvo-utils/WebSocketUtil.js'; +import { actionsEnum as VersionControllerActionsEnum } from 'nfvo-components/panel/versionController/VersionControllerConstants.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; import MergeEditorActionHelper from 'sdc-app/common/merge/MergeEditorActionHelper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; -import {SyncStates} from 'sdc-app/common/merge/MergeEditorConstants.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; +import { SyncStates } from 'sdc-app/common/merge/MergeEditorConstants.js'; function baseUrl() { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/notifications`; + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/notifications`; } function fetch() { - return RestAPIUtil.fetch(baseUrl()); + return RestAPIUtil.fetch(baseUrl()); } function updateNotification(notificationId) { - return RestAPIUtil.put(`${baseUrl()}/${notificationId}`); + return RestAPIUtil.put(`${baseUrl()}/${notificationId}`); } function updateLastSeenNotification(notificationId) { - return RestAPIUtil.put(`${baseUrl()}/last-seen/${notificationId}`); + return RestAPIUtil.put(`${baseUrl()}/last-seen/${notificationId}`); } function loadPrevNotifications(lastScanned, endOfPage) { - return RestAPIUtil.fetch(`${baseUrl()}?LAST_DELIVERED_EVENT_ID=${lastScanned}&END_OF_PAGE_EVENT_ID=${endOfPage}`); + return RestAPIUtil.fetch( + `${baseUrl()}?LAST_DELIVERED_EVENT_ID=${lastScanned}&END_OF_PAGE_EVENT_ID=${endOfPage}` + ); } const INITIAL_LAST_SCANNED = '00000000-0000-1000-8080-808080808080'; const UserNotificationsActionHelper = { - notificationsFirstHandling(dispatch) { - console.log('Websocket Url: ', websocketUrl); - UserNotificationsActionHelper.fetchUserNotificationsList(dispatch).then(({lastScanned}) => { - WebSocketUtil.open(websocketUrl, {lastScanned: lastScanned || INITIAL_LAST_SCANNED}); - }); - }, + notificationsFirstHandling(dispatch) { + console.log('Websocket Url: ', websocketUrl); + UserNotificationsActionHelper.fetchUserNotificationsList(dispatch).then( + ({ lastScanned }) => { + WebSocketUtil.open(websocketUrl, { + lastScanned: lastScanned || INITIAL_LAST_SCANNED + }); + } + ); + }, - fetchUserNotificationsList(dispatch) { - return fetch().then(result => { - dispatch({ - type: actionTypes.LOAD_NOTIFICATIONS, - result - }); - return Promise.resolve({lastScanned: result.lastScanned}); - }); - }, + fetchUserNotificationsList(dispatch) { + return fetch().then(result => { + dispatch({ + type: actionTypes.LOAD_NOTIFICATIONS, + result + }); + return Promise.resolve({ lastScanned: result.lastScanned }); + }); + }, - loadPreviousNotifications(dispatch, {lastScanned, endOfPage}) { - loadPrevNotifications(lastScanned, endOfPage).then(result => dispatch({ - type: actionTypes.LOAD_PREV_NOTIFICATIONS, - result - })); - }, + loadPreviousNotifications(dispatch, { lastScanned, endOfPage }) { + loadPrevNotifications(lastScanned, endOfPage).then(result => + dispatch({ + type: actionTypes.LOAD_PREV_NOTIFICATIONS, + result + }) + ); + }, - notifyAboutConflicts(dispatch, {itemId, itemName, version, currentScreen}) { - let {props} = currentScreen; - let currentItemId = props.softwareProductId || props.licenseModelId; - let currentVersion = props.version; - if(currentItemId === itemId && currentVersion.id === version.id) { - MergeEditorActionHelper.analyzeSyncResult(dispatch, {itemId, version}).then(() => ScreensHelper.loadScreen(dispatch, currentScreen)); - } - else { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_WARNING, - data: { - title: i18n('Conflicts'), - msg: i18n('There are conflicts in {itemName} version {versionName} that you have to resolve', {itemName: itemName.toUpperCase(), versionName: version.versionName}), - cancelButtonText: i18n('OK') - } - }); - } - }, + notifyAboutConflicts( + dispatch, + { itemId, itemName, version, currentScreen } + ) { + let { props } = currentScreen; + let currentItemId = props.softwareProductId || props.licenseModelId; + let currentVersion = props.version; + if (currentItemId === itemId && currentVersion.id === version.id) { + MergeEditorActionHelper.analyzeSyncResult(dispatch, { + itemId, + version + }).then(() => ScreensHelper.loadScreen(dispatch, currentScreen)); + } else { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_WARNING, + data: { + title: i18n('Conflicts'), + msg: i18n( + 'There are conflicts in {itemName} version {versionName} that you have to resolve', + { + itemName: itemName.toUpperCase(), + versionName: version.versionName + } + ), + cancelButtonText: i18n('OK') + } + }); + } + }, - syncItem(dispatch, {itemId, itemName, versionId, versionName, currentScreen}) { - let version = {id: versionId, versionName}; - ItemsHelper.fetchVersion({itemId, versionId}).then(response => { - let inMerge = response && response.state && response.state.synchronizationState === SyncStates.MERGE; - if (!inMerge) { - ItemsHelper.performVCAction({itemId, version, action: VersionControllerActionsEnum.SYNC}).then(() => { - return ItemsHelper.fetchVersion({itemId, versionId}).then(response => { - let inMerge = response && response.state && response.state.synchronizationState === SyncStates.MERGE; - if (!inMerge) { - return ScreensHelper.loadScreen(dispatch, currentScreen); - } - else { - return this.notifyAboutConflicts(dispatch, {itemId, itemName, version, currentScreen}); - } - }); - }); - } - else { - this.notifyAboutConflicts(dispatch, {itemId, itemName, version, currentScreen}); - } - }); - }, + syncItem( + dispatch, + { itemId, itemName, versionId, versionName, currentScreen } + ) { + let version = { id: versionId, versionName }; + ItemsHelper.fetchVersion({ itemId, versionId }).then(response => { + let inMerge = + response && + response.state && + response.state.synchronizationState === SyncStates.MERGE; + if (!inMerge) { + ItemsHelper.performVCAction({ + itemId, + version, + action: VersionControllerActionsEnum.SYNC + }).then(() => { + return ItemsHelper.fetchVersion({ itemId, versionId }).then( + response => { + let inMerge = + response && + response.state && + response.state.synchronizationState === + SyncStates.MERGE; + if (!inMerge) { + return ScreensHelper.loadScreen( + dispatch, + currentScreen + ); + } else { + return this.notifyAboutConflicts(dispatch, { + itemId, + itemName, + version, + currentScreen + }); + } + } + ); + }); + } else { + this.notifyAboutConflicts(dispatch, { + itemId, + itemName, + version, + currentScreen + }); + } + }); + }, - updateNotification(dispatch, {notificationForUpdate}) { - updateNotification(notificationForUpdate.eventId).then(response => { - if(response.status === 'Success' && Object.keys(response.errors).length === 0) { - dispatch({ - type: actionTypes.UPDATE_READ_NOTIFICATION, - notificationForUpdate - }); - } - }); - }, + updateNotification(dispatch, { notificationForUpdate }) { + updateNotification(notificationForUpdate.eventId).then(response => { + if ( + response.status === 'Success' && + Object.keys(response.errors).length === 0 + ) { + dispatch({ + type: actionTypes.UPDATE_READ_NOTIFICATION, + notificationForUpdate + }); + } + }); + }, - updateLastSeenNotification(dispatch, {notificationId}) { - updateLastSeenNotification(notificationId).then(response => { - if (response.status === 'Success' && Object.keys(response.errors).length === 0) { - dispatch({type: actionTypes.RESET_NEW_NOTIFICATIONS}); - } - }); - } + updateLastSeenNotification(dispatch, { notificationId }) { + updateLastSeenNotification(notificationId).then(response => { + if ( + response.status === 'Success' && + Object.keys(response.errors).length === 0 + ) { + dispatch({ type: actionTypes.RESET_NEW_NOTIFICATIONS }); + } + }); + } }; export default UserNotificationsActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsConstants.js b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsConstants.js index a8e92e29fd..b2466f19af 100644 --- a/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/userNotifications/UserNotificationsConstants.js @@ -1,22 +1,21 @@ - import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - NOTIFICATION: null, - LOAD_NOTIFICATIONS: null, - LOAD_PREV_NOTIFICATIONS: null, - UPDATE_READ_NOTIFICATION: null, - RESET_NEW_NOTIFICATIONS: null, - TOGGLE_OVERLAY: null + NOTIFICATION: null, + LOAD_NOTIFICATIONS: null, + LOAD_PREV_NOTIFICATIONS: null, + UPDATE_READ_NOTIFICATION: null, + RESET_NEW_NOTIFICATIONS: null, + TOGGLE_OVERLAY: null }); export const notificationType = keyMirror({ - PERMISSION_CHANGED: 'PermissionChanged', - ITEM_CHANGED: { - COMMIT: 'commit', - SUBMIT: 'submit' - }, - ITEM_DELETED: 'delete', - ITEM_ARCHIVED: 'archive', - ITEM_RESTORED: 'restore' -});
\ No newline at end of file + PERMISSION_CHANGED: 'PermissionChanged', + ITEM_CHANGED: { + COMMIT: 'commit', + SUBMIT: 'submit' + }, + ITEM_DELETED: 'delete', + ITEM_ARCHIVED: 'archive', + ITEM_RESTORED: 'restore' +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/users/UsersActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/users/UsersActionHelper.js index a2e92fe0bc..98bce1ce56 100644 --- a/openecomp-ui/src/sdc-app/onboarding/users/UsersActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/users/UsersActionHelper.js @@ -16,46 +16,41 @@ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './UsersConstants.js'; +import { actionTypes } from './UsersConstants.js'; function getUserId() { - let catalogApiHeaders = Configuration.get('CatalogApiHeaders'); - let User = catalogApiHeaders && catalogApiHeaders.userId; - let userId = User && User.value ? User.value : ''; - return userId; + let catalogApiHeaders = Configuration.get('CatalogApiHeaders'); + let User = catalogApiHeaders && catalogApiHeaders.userId; + let userId = User && User.value ? User.value : ''; + return userId; } function baseUrl() { - const restCatalogPrefix = Configuration.get('restCatalogPrefix'); - return `${restCatalogPrefix}`; + const restCatalogPrefix = Configuration.get('restCatalogPrefix'); + return `${restCatalogPrefix}`; } - function fetchUsersList() { - const url = '/v1/user/users'; - return RestAPIUtil.fetch(`${baseUrl()}${url}`); + const url = '/v1/user/users'; + return RestAPIUtil.fetch(`${baseUrl()}${url}`); } - - const UsersActionHelper = { - fetchUsersList(dispatch) { - fetchUsersList().then(response => { - dispatch({ - type: actionTypes.USERS_LIST_LOADED, - usersList: response - }); - - let userId = getUserId(); - let userInfo = response.find(user => user.userId === userId); - dispatch({ - type: actionTypes.GOT_USER_INFO, - userInfo - }); - - }); - - } + fetchUsersList(dispatch) { + fetchUsersList().then(response => { + dispatch({ + type: actionTypes.USERS_LIST_LOADED, + usersList: response + }); + + let userId = getUserId(); + let userInfo = response.find(user => user.userId === userId); + dispatch({ + type: actionTypes.GOT_USER_INFO, + userInfo + }); + }); + } }; export default UsersActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/users/UsersConstants.js b/openecomp-ui/src/sdc-app/onboarding/users/UsersConstants.js index fdcf4b179b..216d28ad47 100644 --- a/openecomp-ui/src/sdc-app/onboarding/users/UsersConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/users/UsersConstants.js @@ -17,6 +17,6 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - USERS_LIST_LOADED: null, - GOT_USER_INFO: null + USERS_LIST_LOADED: null, + GOT_USER_INFO: null }); diff --git a/openecomp-ui/src/sdc-app/onboarding/users/UsersReducers.js b/openecomp-ui/src/sdc-app/onboarding/users/UsersReducers.js index 6bd72e3b3c..89a04d2a8b 100644 --- a/openecomp-ui/src/sdc-app/onboarding/users/UsersReducers.js +++ b/openecomp-ui/src/sdc-app/onboarding/users/UsersReducers.js @@ -14,29 +14,28 @@ * permissions and limitations under the License. */ -import {actionTypes} from './UsersConstants.js'; -import {combineReducers} from 'redux'; +import { actionTypes } from './UsersConstants.js'; +import { combineReducers } from 'redux'; -function usersList (state = [], action) { - switch (action.type) { - case (actionTypes.USERS_LIST_LOADED): - return [...action.usersList]; - default: - return state; - } -}; - -function userInfo (state = {}, action) { - switch (action.type) { - case (actionTypes.GOT_USER_INFO): - return action.userInfo; - default: - return state; - } +function usersList(state = [], action) { + switch (action.type) { + case actionTypes.USERS_LIST_LOADED: + return [...action.usersList]; + default: + return state; + } } +function userInfo(state = {}, action) { + switch (action.type) { + case actionTypes.GOT_USER_INFO: + return action.userInfo; + default: + return state; + } +} export default combineReducers({ - usersList: usersList, - userInfo: userInfo -});
\ No newline at end of file + usersList: usersList, + userInfo: userInfo +}); diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.js index 0fd0eabd86..457d096219 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.js @@ -14,76 +14,100 @@ * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import VersionsPageActionHelper from './VersionsPageActionHelper.js'; import VersionsPageCreationActionHelper from './creation/VersionsPageCreationActionHelper.js'; import PermissionsActionHelper from '../permissions/PermissionsActionHelper.js'; -import {onboardingMethod as onboardingMethodType} from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; +import { onboardingMethod as onboardingMethodType } from 'sdc-app/onboarding/softwareProduct/SoftwareProductConstants.js'; import VersionsPageView from './VersionsPage.jsx'; export const mapStateToProps = ({ - users: {userInfo}, - versionsPage: {permissions, versionsList}, - currentScreen: {itemPermission: {isCollaborator, isArchived}, props: {itemId}}, - softwareProductList = [] + users: { userInfo }, + versionsPage: { permissions, versionsList }, + currentScreen: { + itemPermission: { isCollaborator, isArchived }, + props: { itemId } + }, + softwareProductList = [] }) => { + let { versions = [], selectedVersion } = versionsList; + let { owner, contributors, viewers } = permissions; - let {versions = [], selectedVersion} = versionsList; - let {owner, contributors, viewers} = permissions; - - // sorting the version list - versions.sort((a,b) => { - let statusCompare = b.status.localeCompare(a.status); - if (statusCompare === 0) { - return b.modificationTime - a.modificationTime; - } else { - return statusCompare; - } - - }); - const curentSoftwareProduct = softwareProductList.find(item => item.id === itemId); - return { - versions, - contributors, - viewers, - owner, - currentUser: userInfo, - selectedVersion, - isCollaborator, - isManual: curentSoftwareProduct && curentSoftwareProduct.onboardingMethod === onboardingMethodType.MANUAL, - isArchived - }; - + // sorting the version list + versions.sort((a, b) => { + let statusCompare = b.status.localeCompare(a.status); + if (statusCompare === 0) { + return b.modificationTime - a.modificationTime; + } else { + return statusCompare; + } + }); + const curentSoftwareProduct = softwareProductList.find( + item => item.id === itemId + ); + return { + versions, + contributors, + viewers, + owner, + currentUser: userInfo, + selectedVersion, + isCollaborator, + isManual: + curentSoftwareProduct && + curentSoftwareProduct.onboardingMethod === + onboardingMethodType.MANUAL, + isArchived + }; }; -export const mapActionsToProps = (dispatch, {itemType, itemId, additionalProps}) => { - return { - onNavigateToVersion({version}) { - VersionsPageActionHelper.onNavigateToVersion(dispatch, {version, itemId, itemType, additionalProps}); - }, +export const mapActionsToProps = ( + dispatch, + { itemType, itemId, additionalProps } +) => { + return { + onNavigateToVersion({ version }) { + VersionsPageActionHelper.onNavigateToVersion(dispatch, { + version, + itemId, + itemType, + additionalProps + }); + }, - onSelectVersion({version}) { - VersionsPageActionHelper.selectVersion(dispatch, {version}); - }, + onSelectVersion({ version }) { + VersionsPageActionHelper.selectVersion(dispatch, { version }); + }, - onCreateVersion({version}) { - VersionsPageCreationActionHelper.open(dispatch, {baseVersion: version, itemId, itemType, additionalProps}); - }, + onCreateVersion({ version }) { + VersionsPageCreationActionHelper.open(dispatch, { + baseVersion: version, + itemId, + itemType, + additionalProps + }); + }, - onManagePermissions() { - PermissionsActionHelper.openPermissonsManager(dispatch, {itemId, askForRights: false}); - }, + onManagePermissions() { + PermissionsActionHelper.openPermissonsManager(dispatch, { + itemId, + askForRights: false + }); + }, - onTreeFullScreen(treeProps) { - VersionsPageActionHelper.openTree(dispatch, treeProps); - }, + onTreeFullScreen(treeProps) { + VersionsPageActionHelper.openTree(dispatch, treeProps); + }, - onModalNodeClick({version}) { - VersionsPageActionHelper.selectVersionFromModal(dispatch, {version}); - }, - onArchive: () => VersionsPageActionHelper.archiveItem(dispatch, itemId), - onRestore: () => VersionsPageActionHelper.restoreItemFromArchive(dispatch, itemId) - }; + onModalNodeClick({ version }) { + VersionsPageActionHelper.selectVersionFromModal(dispatch, { + version + }); + }, + onArchive: () => VersionsPageActionHelper.archiveItem(dispatch, itemId), + onRestore: () => + VersionsPageActionHelper.restoreItemFromArchive(dispatch, itemId) + }; }; export default connect(mapStateToProps, mapActionsToProps)(VersionsPageView); diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.jsx b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.jsx index f8417fafbf..7f7af8130f 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPage.jsx @@ -22,81 +22,144 @@ import Button from 'sdc-ui/lib/react/Button.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import featureToggle from 'sdc-app/features/featureToggle.js'; -const DepricateButton = ({depricateAction, title}) => ( - <div className='depricate-btn-wrapper'> - <Button data-test-id='depricate-action-btn' className='depricate-btn' onClick={depricateAction}>{title}</Button> - </div> +const DepricateButton = ({ depricateAction, title }) => ( + <div className="depricate-btn-wrapper"> + <Button + data-test-id="depricate-action-btn" + className="depricate-btn" + onClick={depricateAction}> + {title} + </Button> + </div> ); -const FeatureDepricatedButton = featureToggle('ARCHIVE_ITEM')(DepricateButton); +const FeatureDepricatedButton = featureToggle('ARCHIVE_ITEM')(DepricateButton); -const VersionPageTitle = ({itemName, depricatedTitle, isArchived, onRestore, onArchive}) => { - return ( - <div className='version-page-header'> - <div className='versions-page-title'>{`${i18n('Available Versions')} - ${itemName} ${depricatedTitle}`}</div> - <FeatureDepricatedButton depricateAction={isArchived ? () => onRestore() : () => onArchive() } title={i18n(isArchived ? 'RESTORE' : 'ARCHIVE')}/> - </div> - ); +const VersionPageTitle = ({ + itemName, + depricatedTitle, + isArchived, + onRestore, + onArchive +}) => { + return ( + <div className="version-page-header"> + <div className="versions-page-title">{`${i18n( + 'Available Versions' + )} - ${itemName} ${depricatedTitle}`}</div> + <FeatureDepricatedButton + depricateAction={ + isArchived ? () => onRestore() : () => onArchive() + } + title={i18n(isArchived ? 'RESTORE' : 'ARCHIVE')} + /> + </div> + ); }; class VersionsPage extends React.Component { - state = { - showExpanded : false - } - render() { - let { versions, owner, contributors, currentUser, isCollaborator, itemName = '', viewers, onSelectVersion, onNavigateToVersion, - onTreeFullScreen, onManagePermissions, onCreateVersion, selectedVersion, onModalNodeClick, isManual, isArchived, onArchive, onRestore} = this.props; - const depricatedTitle = isArchived ? i18n('(Archived)') : ''; - return ( - <div className='versions-page-view'> - <VersionPageTitle - itemName={itemName} - depricatedTitle={depricatedTitle} - onArchive={onArchive} - isArchived={isArchived} - onRestore={onRestore}/> - <PermissionsView - owner={owner} - contributors={contributors} - viewers={viewers} - currentUser={currentUser} - isManual={isManual} - onManagePermissions={onManagePermissions}/> - <div className='versions-page-list-and-tree'> - <div className='version-tree-wrapper'> - <div className='version-tree-title-container'> - <div className='version-tree-title'>{i18n('Version Tree')}</div> - {this.state.showExpanded && <SVGIcon name='expand' className='version-tree-full-screen' onClick={() => onTreeFullScreen({ - name: 'versions-tree-popup', - width: 798, - height: 500, - nodes: versions.map(version => ({id: version.id, name: version.name, parent: version.baseId || ''})), - onNodeClick: (version) => onModalNodeClick({version}), - selectedNodeId: selectedVersion, - scrollable: true, - toWiden: true - })} />} - </div> - <Tree - name={'versions-tree'} - width={200} - allowScaleWidth={false} - nodes={versions.map(version => ({id: version.id, name: version.name, parent: version.baseId || ''}))} - onNodeClick={version => onSelectVersion({version})} - onRenderedBeyondWidth={() => {this.setState({showExpanded : true});}} - selectedNodeId={selectedVersion}/> - </div> - <VersionList - versions={versions} - onSelectVersion={onSelectVersion} - onNavigateToVersion={onNavigateToVersion} - onCreateVersion={isArchived ? false : onCreateVersion} - selectedVersion={selectedVersion} - isCollaborator={isCollaborator} /> - </div> - </div> - ); - } + state = { + showExpanded: false + }; + render() { + let { + versions, + owner, + contributors, + currentUser, + isCollaborator, + itemName = '', + viewers, + onSelectVersion, + onNavigateToVersion, + onTreeFullScreen, + onManagePermissions, + onCreateVersion, + selectedVersion, + onModalNodeClick, + isManual, + isArchived, + onArchive, + onRestore + } = this.props; + const depricatedTitle = isArchived ? i18n('(Archived)') : ''; + return ( + <div className="versions-page-view"> + <VersionPageTitle + itemName={itemName} + depricatedTitle={depricatedTitle} + onArchive={onArchive} + isArchived={isArchived} + onRestore={onRestore} + /> + <PermissionsView + owner={owner} + contributors={contributors} + viewers={viewers} + currentUser={currentUser} + isManual={isManual} + onManagePermissions={onManagePermissions} + /> + <div className="versions-page-list-and-tree"> + <div className="version-tree-wrapper"> + <div className="version-tree-title-container"> + <div className="version-tree-title"> + {i18n('Version Tree')} + </div> + {this.state.showExpanded && ( + <SVGIcon + name="expand" + className="version-tree-full-screen" + onClick={() => + onTreeFullScreen({ + name: 'versions-tree-popup', + width: 798, + height: 500, + nodes: versions.map(version => ({ + id: version.id, + name: version.name, + parent: version.baseId || '' + })), + onNodeClick: version => + onModalNodeClick({ version }), + selectedNodeId: selectedVersion, + scrollable: true, + toWiden: true + }) + } + /> + )} + </div> + <Tree + name={'versions-tree'} + width={200} + allowScaleWidth={false} + nodes={versions.map(version => ({ + id: version.id, + name: version.name, + parent: version.baseId || '' + }))} + onNodeClick={version => + onSelectVersion({ version }) + } + onRenderedBeyondWidth={() => { + this.setState({ showExpanded: true }); + }} + selectedNodeId={selectedVersion} + /> + </div> + <VersionList + versions={versions} + onSelectVersion={onSelectVersion} + onNavigateToVersion={onNavigateToVersion} + onCreateVersion={isArchived ? false : onCreateVersion} + selectedVersion={selectedVersion} + isCollaborator={isCollaborator} + /> + </div> + </div> + ); + } } export default VersionsPage; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js index d475c03c31..606b17b897 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageActionHelper.js @@ -14,94 +14,96 @@ * permissions and limitations under the License. */ import ItemsHelper from '../../common/helpers/ItemsHelper.js'; -import {actionTypes} from './VersionsPageConstants.js'; -import {itemTypes} from './VersionsPageConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './VersionsPageConstants.js'; +import { itemTypes } from './VersionsPageConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import ScreensHelper from 'sdc-app/common/helpers/ScreensHelper.js'; -import {enums, screenTypes} from 'sdc-app/onboarding/OnboardingConstants.js'; - +import { enums, screenTypes } from 'sdc-app/onboarding/OnboardingConstants.js'; const VersionsPageActionHelper = { - fetchVersions(dispatch, {itemType, itemId}) { - return ItemsHelper.fetchVersions({itemId}).then(response => { - dispatch({ - type: actionTypes.VERSIONS_LOADED, - versions: response.results, - itemType, - itemId - }); - return Promise.resolve(response); - }); - }, + fetchVersions(dispatch, { itemType, itemId }) { + return ItemsHelper.fetchVersions({ itemId }).then(response => { + dispatch({ + type: actionTypes.VERSIONS_LOADED, + versions: response.results, + itemType, + itemId + }); + return Promise.resolve(response); + }); + }, - selectVersion(dispatch, {version}) { - dispatch({ - type: actionTypes.SELECT_VERSION, - versionId: version.id - }); - }, + selectVersion(dispatch, { version }) { + dispatch({ + type: actionTypes.SELECT_VERSION, + versionId: version.id + }); + }, - selectNone(dispatch) { - dispatch({ type: actionTypes.SELECT_NONE }); - }, + selectNone(dispatch) { + dispatch({ type: actionTypes.SELECT_NONE }); + }, - onNavigateToVersion(dispatch, {version, itemId, itemType}) { - switch (itemType) { - case itemTypes.LICENSE_MODEL: - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, screenType: screenTypes.LICENSE_MODEL, - props: {licenseModelId: itemId, version} - }); - break; - case itemTypes.SOFTWARE_PRODUCT: - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, screenType: screenTypes.SOFTWARE_PRODUCT, - props: {softwareProductId: itemId, version} - }); - break; - } - }, + onNavigateToVersion(dispatch, { version, itemId, itemType }) { + switch (itemType) { + case itemTypes.LICENSE_MODEL: + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.LICENSE_MODEL_OVERVIEW, + screenType: screenTypes.LICENSE_MODEL, + props: { licenseModelId: itemId, version } + }); + break; + case itemTypes.SOFTWARE_PRODUCT: + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.SOFTWARE_PRODUCT_LANDING_PAGE, + screenType: screenTypes.SOFTWARE_PRODUCT, + props: { softwareProductId: itemId, version } + }); + break; + } + }, - openTree(dispatch, treeProps) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.VERSION_TREE, - modalComponentProps: treeProps, - onDeclined: () => dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }), - modalClassName: 'versions-tree-modal', - cancelButtonText: i18n('Close'), - title: i18n('Version Tree') - } - }); - }, + openTree(dispatch, treeProps) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.VERSION_TREE, + modalComponentProps: treeProps, + onDeclined: () => + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }), + modalClassName: 'versions-tree-modal', + cancelButtonText: i18n('Close'), + title: i18n('Version Tree') + } + }); + }, - selectVersionFromModal(dispatch, {version}) { - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - this.selectVersion(dispatch, {version}); - }, + selectVersionFromModal(dispatch, { version }) { + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + this.selectVersion(dispatch, { version }); + }, - archiveItem(dispatch, itemId) { - ItemsHelper.archiveItem(itemId).then(() => { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.ONBOARDING_CATALOG - }); - }); - }, + archiveItem(dispatch, itemId) { + ItemsHelper.archiveItem(itemId).then(() => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.ONBOARDING_CATALOG + }); + }); + }, - restoreItemFromArchive(dispatch, itemId) { - ItemsHelper.restoreItem(itemId).then(() => { - ScreensHelper.loadScreen(dispatch, { - screen: enums.SCREEN.ONBOARDING_CATALOG - }); - }); - } + restoreItemFromArchive(dispatch, itemId) { + ItemsHelper.restoreItem(itemId).then(() => { + ScreensHelper.loadScreen(dispatch, { + screen: enums.SCREEN.ONBOARDING_CATALOG + }); + }); + } }; export default VersionsPageActionHelper; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageConstants.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageConstants.js index 983ab79a14..3a3879ddb3 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageConstants.js @@ -16,12 +16,12 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - VERSIONS_LOADED: null, - SELECT_VERSION: null, - SELECT_NONE: null + VERSIONS_LOADED: null, + SELECT_VERSION: null, + SELECT_NONE: null }); export const itemTypes = { - LICENSE_MODEL: 'vendor-license-models', - SOFTWARE_PRODUCT: 'vendor-software-products' + LICENSE_MODEL: 'vendor-license-models', + SOFTWARE_PRODUCT: 'vendor-software-products' }; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageReducer.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageReducer.js index 9b6fa9f803..c270278f21 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/VersionsPageReducer.js @@ -13,30 +13,34 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes} from './VersionsPageConstants.js'; -import {combineReducers} from 'redux'; +import { actionTypes } from './VersionsPageConstants.js'; +import { combineReducers } from 'redux'; import VersionsPageCreationReducer from './creation/VersionsPageCreationReducer.js'; import PermissionsReducer from '../permissions/PermissionsReducer.js'; -import {createPlainDataReducer} from 'sdc-app/common/reducers/PlainDataReducer.js'; +import { createPlainDataReducer } from 'sdc-app/common/reducers/PlainDataReducer.js'; function VersionsListReducer(state = {}, action) { - switch (action.type) { - case actionTypes.VERSIONS_LOADED: - let {versions, itemType = state.itemType, itemId} = action; - return {...state, versions, itemType, itemId}; - case actionTypes.SELECT_VERSION: - return {...state, selectedVersion: action.versionId === state.selectedVersion ? null : action.versionId}; - case actionTypes.SELECT_NONE: - return {...state, selectedVersion: null}; - default: - return state; - } -}; - - + switch (action.type) { + case actionTypes.VERSIONS_LOADED: + let { versions, itemType = state.itemType, itemId } = action; + return { ...state, versions, itemType, itemId }; + case actionTypes.SELECT_VERSION: + return { + ...state, + selectedVersion: + action.versionId === state.selectedVersion + ? null + : action.versionId + }; + case actionTypes.SELECT_NONE: + return { ...state, selectedVersion: null }; + default: + return state; + } +} export default combineReducers({ - versionCreation: createPlainDataReducer(VersionsPageCreationReducer), - versionsList: VersionsListReducer, - permissions: PermissionsReducer + versionCreation: createPlainDataReducer(VersionsPageCreationReducer), + versionsList: VersionsListReducer, + permissions: PermissionsReducer }); diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/PermissionsView.jsx b/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/PermissionsView.jsx index 26f8450f4c..74d88f0b52 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/PermissionsView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/PermissionsView.jsx @@ -22,61 +22,108 @@ import Tooltip from 'react-bootstrap/lib/Tooltip.js'; const maxContributors = 6; -function extraUsersTooltip (extraUsers) { - return ( - <Tooltip className='extra-users-tooltip' id='extra-users-tooltip-id'> - {extraUsers.map(extraUser => <div key={extraUser.userId} className='extra-user'>{extraUser.fullName}</div>)} - </Tooltip> - ); +function extraUsersTooltip(extraUsers) { + return ( + <Tooltip className="extra-users-tooltip" id="extra-users-tooltip-id"> + {extraUsers.map(extraUser => ( + <div key={extraUser.userId} className="extra-user"> + {extraUser.fullName} + </div> + ))} + </Tooltip> + ); } -const User = ({user, isCurrentUser, dataTestId}) => ( - <SVGIcon className={`user-view ${isCurrentUser ? 'current-user' : ''}`} name='user' label={user.fullName} labelPosition='right' color='primary' - data-test-id={dataTestId}/> +const User = ({ user, isCurrentUser, dataTestId }) => ( + <SVGIcon + className={`user-view ${isCurrentUser ? 'current-user' : ''}`} + name="user" + label={user.fullName} + labelPosition="right" + color="primary" + data-test-id={dataTestId} + /> ); -const Owner = ({owner, isCurrentUser}) => ( - <div className='owner-view'> - <div className='permissions-view-title'>{i18n('Owner')}</div> - <User user={owner} isCurrentUser={isCurrentUser} dataTestId='owner'/> - </div> +const Owner = ({ owner, isCurrentUser }) => ( + <div className="owner-view"> + <div className="permissions-view-title">{i18n('Owner')}</div> + <User user={owner} isCurrentUser={isCurrentUser} dataTestId="owner" /> + </div> ); -const Contributors = ({contributors, owner, currentUser, onManagePermissions, isManual}) => { - let extraUsers = contributors.length - maxContributors; - return ( - <div className='contributors-view'> - <div className='permissions-view-title'>{i18n('Contributors')}</div> - {contributors.slice(0, maxContributors).map(contributor => - <User key={contributor.userId} user={contributor} isCurrentUser={contributor.userId === currentUser.userId} dataTestId='contributor'/> - )} - {extraUsers > 0 && - <OverlayTrigger placement='bottom' overlay={extraUsersTooltip(contributors.slice(maxContributors))}> - <div className='extra-contributors'>{`+${extraUsers}`}</div> - </OverlayTrigger> - } - {currentUser.userId === owner.userId && !isManual && - <span - className='manage-permissions' - onClick={onManagePermissions} - data-test-id='versions-page-manage-permissions'> - {i18n('Manage Permissions')} - </span> - } - </div> - ); +const Contributors = ({ + contributors, + owner, + currentUser, + onManagePermissions, + isManual +}) => { + let extraUsers = contributors.length - maxContributors; + return ( + <div className="contributors-view"> + <div className="permissions-view-title">{i18n('Contributors')}</div> + {contributors + .slice(0, maxContributors) + .map(contributor => ( + <User + key={contributor.userId} + user={contributor} + isCurrentUser={ + contributor.userId === currentUser.userId + } + dataTestId="contributor" + /> + ))} + {extraUsers > 0 && ( + <OverlayTrigger + placement="bottom" + overlay={extraUsersTooltip( + contributors.slice(maxContributors) + )}> + <div className="extra-contributors">{`+${extraUsers}`}</div> + </OverlayTrigger> + )} + {currentUser.userId === owner.userId && + !isManual && ( + <span + className="manage-permissions" + onClick={onManagePermissions} + data-test-id="versions-page-manage-permissions"> + {i18n('Manage Permissions')} + </span> + )} + </div> + ); }; -const PermissionsView = ({owner, contributors, currentUser = {}, onManagePermissions, isManual}) => ( - <div className='versions-page-permissions-view-wrapper'> - <div className='permissions-view-wrapper-title'>{i18n('Permissions')}</div> - <div className='permissions-view-content'> - <div className='permissions-view'> - <Owner owner={owner} isCurrentUser={owner.userId === currentUser.userId} /> - <Contributors owner={owner} contributors={contributors} currentUser={currentUser} onManagePermissions={onManagePermissions} isManual={isManual}/> - </div> - </div> - </div> +const PermissionsView = ({ + owner, + contributors, + currentUser = {}, + onManagePermissions, + isManual +}) => ( + <div className="versions-page-permissions-view-wrapper"> + <div className="permissions-view-wrapper-title"> + {i18n('Permissions')} + </div> + <div className="permissions-view-content"> + <div className="permissions-view"> + <Owner + owner={owner} + isCurrentUser={owner.userId === currentUser.userId} + /> + <Contributors + owner={owner} + contributors={contributors} + currentUser={currentUser} + onManagePermissions={onManagePermissions} + isManual={isManual} + /> + </div> + </div> + </div> ); export default PermissionsView; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/VersionList.jsx b/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/VersionList.jsx index 47255eb9dc..d74805eccc 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/VersionList.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/components/VersionList.jsx @@ -20,108 +20,177 @@ import Tooltip from 'react-bootstrap/lib/Tooltip.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import SVGIcon from 'sdc-ui/lib/react/SVGIcon.js'; -const formatTime = (time) => { - if (!time) { return ''; } +const formatTime = time => { + if (!time) { + return ''; + } - const date = new Date(time); - const options = { - year: 'numeric', - month: 'short', - day: 'numeric', - hour: '2-digit', - minute: '2-digit' - }; - const newDate = date.toLocaleTimeString('en-US', options); + const date = new Date(time); + const options = { + year: 'numeric', + month: 'short', + day: 'numeric', + hour: '2-digit', + minute: '2-digit' + }; + const newDate = date.toLocaleTimeString('en-US', options); - return newDate; + return newDate; }; const DescriptionField = ({ className, text, useTooltip }) => { - if (useTooltip) { - return ( - <div className={className}> - <OverlayTrigger - placement='bottom' - overlay={<Tooltip className='version-description-tooltip' id='version-description-tooltip'>{text}</Tooltip>}> - <div className='description-text'>{text}</div> - </OverlayTrigger> - </div> - ); - } - return <div className={className}>{text}</div>; + if (useTooltip) { + return ( + <div className={className}> + <OverlayTrigger + placement="bottom" + overlay={ + <Tooltip + className="version-description-tooltip" + id="version-description-tooltip"> + {text} + </Tooltip> + }> + <div className="description-text">{text}</div> + </OverlayTrigger> + </div> + ); + } + return <div className={className}>{text}</div>; }; -const VersionListItem = ({ data, onSelectVersion, onNavigateToVersion, onCreateVersion, isHeader, isSelected, isCollaborator }) => { +const VersionListItem = ({ + data, + onSelectVersion, + onNavigateToVersion, + onCreateVersion, + isHeader, + isSelected, + isCollaborator +}) => { + let { modificationTime, name, status, description, additionalInfo } = data; + const modificationText = !isHeader + ? formatTime(modificationTime) + : i18n('Last Edited On'); - let {modificationTime, name, status, description, additionalInfo} = data; - const modificationText = !isHeader ? formatTime(modificationTime) : i18n('Last Edited On'); - - return ( - <div - data-test-id='version-item-row' - className={`version-item-row ${isHeader ? 'header-row' : 'clickable'} ${isSelected ? 'selected' : ''}`} - onClick={e => { - e.stopPropagation(); - onSelectVersion(); - onNavigateToVersion(); - }}> - <div className={`version-item-field ${isHeader ? 'header-field item-version' : 'item-version'}`}>{name}</div> - <div className={`version-item-field ${isHeader ? 'header-field item-status' : 'item-status'}`}>{status}</div> - <div className={`version-item-field ${isHeader ? 'header-field' : 'item-last-edited'}`}>{modificationText}</div> - <DescriptionField - className={`version-item-field ${isHeader ? 'header-field header-description' : 'item-description'}`} - useTooltip={!isHeader && description} - text={description} /> - - { - isHeader ? - <div className='version-item-field header-field actions'>{i18n('Actions')}</div> - : - <div className='version-item-field item-actions'> - <div className='version-item-field item-select'> - <SVGIcon - name='check-circle' - data-test-id='versions-page-select-version' - onClick={e => {e.stopPropagation(); onNavigateToVersion();}} - label={i18n('Go to this Version')} - labelPosition='right' /> - </div> - <div className='version-item-field item-create'> - {!isHeader && isCollaborator && additionalInfo.OptionalCreationMethods.length > 0 && onCreateVersion && - <SVGIcon - name='plus-circle' - data-test-id='versions-page-create-version' - onClick={e => { e.stopPropagation(); onCreateVersion(); }} - label={i18n('Create New Version')} - labelPosition='right' - disabled={!isCollaborator || !onCreateVersion} /> - } - </div> - </div> - } - </div> - ); + return ( + <div + data-test-id="version-item-row" + className={`version-item-row ${ + isHeader ? 'header-row' : 'clickable' + } ${isSelected ? 'selected' : ''}`} + onClick={e => { + e.stopPropagation(); + onSelectVersion(); + onNavigateToVersion(); + }}> + <div + className={`version-item-field ${ + isHeader ? 'header-field item-version' : 'item-version' + }`}> + {name} + </div> + <div + className={`version-item-field ${ + isHeader ? 'header-field item-status' : 'item-status' + }`}> + {status} + </div> + <div + className={`version-item-field ${ + isHeader ? 'header-field' : 'item-last-edited' + }`}> + {modificationText} + </div> + <DescriptionField + className={`version-item-field ${ + isHeader + ? 'header-field header-description' + : 'item-description' + }`} + useTooltip={!isHeader && description} + text={description} + /> + {isHeader ? ( + <div className="version-item-field header-field actions"> + {i18n('Actions')} + </div> + ) : ( + <div className="version-item-field item-actions"> + <div className="version-item-field item-select"> + <SVGIcon + name="check-circle" + data-test-id="versions-page-select-version" + onClick={e => { + e.stopPropagation(); + onNavigateToVersion(); + }} + label={i18n('Go to this Version')} + labelPosition="right" + /> + </div> + <div className="version-item-field item-create"> + {!isHeader && + isCollaborator && + additionalInfo.OptionalCreationMethods.length > 0 && + onCreateVersion && ( + <SVGIcon + name="plus-circle" + data-test-id="versions-page-create-version" + onClick={e => { + e.stopPropagation(); + onCreateVersion(); + }} + label={i18n('Create New Version')} + labelPosition="right" + disabled={ + !isCollaborator || !onCreateVersion + } + /> + )} + </div> + </div> + )} + </div> + ); }; -const VersionList = ({ versions, onSelectVersion, onNavigateToVersion, onCreateVersion, selectedVersion, isCollaborator }) => ( - <div className='version-list'> - <VersionListItem - data={{ name: i18n('Version'), status: i18n('Status'), description: i18n('Description') }} - isHeader /> - <div className='version-list-items'> - {versions.map(version => - <VersionListItem - key={version.id} - data={version} - onSelectVersion={() => onSelectVersion({version})} - onNavigateToVersion={() => onNavigateToVersion({version})} - onCreateVersion={onCreateVersion ? () => onCreateVersion({version}) : false} - isSelected={selectedVersion === version.id} - isCollaborator={isCollaborator} /> - )} - </div> - </div> +const VersionList = ({ + versions, + onSelectVersion, + onNavigateToVersion, + onCreateVersion, + selectedVersion, + isCollaborator +}) => ( + <div className="version-list"> + <VersionListItem + data={{ + name: i18n('Version'), + status: i18n('Status'), + description: i18n('Description') + }} + isHeader + /> + <div className="version-list-items"> + {versions.map(version => ( + <VersionListItem + key={version.id} + data={version} + onSelectVersion={() => onSelectVersion({ version })} + onNavigateToVersion={() => onNavigateToVersion({ version })} + onCreateVersion={ + onCreateVersion + ? () => onCreateVersion({ version }) + : false + } + isSelected={selectedVersion === version.id} + isCollaborator={isCollaborator} + /> + ))} + </div> + </div> ); export default VersionList; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreation.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreation.js index 66c1c79be5..e0cb925df4 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreation.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreation.js @@ -13,32 +13,52 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {connect} from 'react-redux'; +import { connect } from 'react-redux'; import VersionsPageCreationActionHelper from './VersionsPageCreationActionHelper.js'; import VersionsPageActionHelper from '../VersionsPageActionHelper.js'; import VersionsPageCreationView from './VersionsPageCreationView.jsx'; import ValidationHelper from 'sdc-app/common/helpers/ValidationHelper.js'; -import {VERSION_CREATION_FORM_NAME} from './VersionsPageCreationConstants.js'; +import { VERSION_CREATION_FORM_NAME } from './VersionsPageCreationConstants.js'; -export const mapStateToProps = ({versionsPage: {versionCreation}}) => { - let {genericFieldInfo} = versionCreation; - let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); +export const mapStateToProps = ({ versionsPage: { versionCreation } }) => { + let { genericFieldInfo } = versionCreation; + let isFormValid = ValidationHelper.checkFormValid(genericFieldInfo); - return {...versionCreation, isFormValid}; + return { ...versionCreation, isFormValid }; }; -export const mapActionsToProps = (dispatch, {itemId, itemType, additionalProps}) => { - return { - onDataChanged: (deltaData, customValidations) => ValidationHelper.dataChanged(dispatch, {deltaData, formName: VERSION_CREATION_FORM_NAME, customValidations}), - onCancel: () => VersionsPageCreationActionHelper.close(dispatch), - onSubmit: ({baseVersion, payload}) => { - VersionsPageCreationActionHelper.close(dispatch); - VersionsPageCreationActionHelper.createVersion(dispatch, {baseVersion, itemId, payload}).then(response => { - VersionsPageActionHelper.onNavigateToVersion(dispatch, {version: response, itemId, itemType, additionalProps}); - }); - }, - onValidateForm: () => ValidationHelper.validateForm(dispatch, VERSION_CREATION_FORM_NAME) - }; +export const mapActionsToProps = ( + dispatch, + { itemId, itemType, additionalProps } +) => { + return { + onDataChanged: (deltaData, customValidations) => + ValidationHelper.dataChanged(dispatch, { + deltaData, + formName: VERSION_CREATION_FORM_NAME, + customValidations + }), + onCancel: () => VersionsPageCreationActionHelper.close(dispatch), + onSubmit: ({ baseVersion, payload }) => { + VersionsPageCreationActionHelper.close(dispatch); + VersionsPageCreationActionHelper.createVersion(dispatch, { + baseVersion, + itemId, + payload + }).then(response => { + VersionsPageActionHelper.onNavigateToVersion(dispatch, { + version: response, + itemId, + itemType, + additionalProps + }); + }); + }, + onValidateForm: () => + ValidationHelper.validateForm(dispatch, VERSION_CREATION_FORM_NAME) + }; }; -export default connect(mapStateToProps, mapActionsToProps)(VersionsPageCreationView); +export default connect(mapStateToProps, mapActionsToProps)( + VersionsPageCreationView +); diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationActionHelper.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationActionHelper.js index bc038689a4..6e3be705c0 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationActionHelper.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationActionHelper.js @@ -15,65 +15,76 @@ */ import RestAPIUtil from 'nfvo-utils/RestAPIUtil.js'; import Configuration from 'sdc-app/config/Configuration.js'; -import {actionTypes} from './VersionsPageCreationConstants.js'; -import {modalContentMapper} from 'sdc-app/common/modal/ModalContentMapper.js'; -import {actionTypes as modalActionTypes} from 'nfvo-components/modal/GlobalModalConstants.js'; +import { actionTypes } from './VersionsPageCreationConstants.js'; +import { modalContentMapper } from 'sdc-app/common/modal/ModalContentMapper.js'; +import { actionTypes as modalActionTypes } from 'nfvo-components/modal/GlobalModalConstants.js'; import i18n from 'nfvo-utils/i18n/i18n.js'; import ItemsHelper from 'sdc-app/common/helpers/ItemsHelper.js'; -import {actionTypes as VersionsPageActionTypes} from '../VersionsPageConstants.js'; +import { actionTypes as VersionsPageActionTypes } from '../VersionsPageConstants.js'; -function baseUrl({itemId, baseVersion}) { - const restPrefix = Configuration.get('restPrefix'); - return `${restPrefix}/v1.0/items/${itemId}/versions/${baseVersion.id}/`; +function baseUrl({ itemId, baseVersion }) { + const restPrefix = Configuration.get('restPrefix'); + return `${restPrefix}/v1.0/items/${itemId}/versions/${baseVersion.id}/`; } -function createVersion({itemId, baseVersion, payload: {description, creationMethod} }) { - return RestAPIUtil.post(baseUrl({itemId, baseVersion}), {description, creationMethod}); +function createVersion({ + itemId, + baseVersion, + payload: { description, creationMethod } +}) { + return RestAPIUtil.post(baseUrl({ itemId, baseVersion }), { + description, + creationMethod + }); } - export default { + open(dispatch, { itemType, itemId, additionalProps, baseVersion }) { + dispatch({ + type: actionTypes.OPEN + }); - open(dispatch, {itemType, itemId, additionalProps, baseVersion}) { - dispatch({ - type: actionTypes.OPEN - }); - - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_SHOW, - data: { - modalComponentName: modalContentMapper.VERSION_CREATION, - modalComponentProps: {itemType, itemId, additionalProps, baseVersion}, - title: i18n('New Version - From {name}', {name: baseVersion.name}) - } - }); - }, - - close(dispatch){ - dispatch({ - type: actionTypes.CLOSE - }); + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_SHOW, + data: { + modalComponentName: modalContentMapper.VERSION_CREATION, + modalComponentProps: { + itemType, + itemId, + additionalProps, + baseVersion + }, + title: i18n('New Version - From {name}', { + name: baseVersion.name + }) + } + }); + }, - dispatch({ - type: modalActionTypes.GLOBAL_MODAL_CLOSE - }); - }, + close(dispatch) { + dispatch({ + type: actionTypes.CLOSE + }); - createVersion(dispatch, {itemId, baseVersion, payload}){ - return createVersion({itemId, baseVersion, payload}).then(result => { - return ItemsHelper.fetchVersions({itemId}).then(response => { - dispatch({ - type: VersionsPageActionTypes.VERSIONS_LOADED, - versions: response.results, - itemId - }); - dispatch({ - type: actionTypes.VERSION_CREATED, - result - }); - return result; - }); - }); - } + dispatch({ + type: modalActionTypes.GLOBAL_MODAL_CLOSE + }); + }, + createVersion(dispatch, { itemId, baseVersion, payload }) { + return createVersion({ itemId, baseVersion, payload }).then(result => { + return ItemsHelper.fetchVersions({ itemId }).then(response => { + dispatch({ + type: VersionsPageActionTypes.VERSIONS_LOADED, + versions: response.results, + itemId + }); + dispatch({ + type: actionTypes.VERSION_CREATED, + result + }); + return result; + }); + }); + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationConstants.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationConstants.js index 4ce381d4de..e761232443 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationConstants.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationConstants.js @@ -16,13 +16,13 @@ import keyMirror from 'nfvo-utils/KeyMirror.js'; export const actionTypes = keyMirror({ - OPEN: null, - CLOSE: null, - VERSION_CREATED: null + OPEN: null, + CLOSE: null, + VERSION_CREATED: null }); export const VERSION_CREATION_FORM_NAME = 'VCREATIONFORM'; export const defaultState = { - creationMethod: 'major' -};
\ No newline at end of file + creationMethod: 'major' +}; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationReducer.js b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationReducer.js index 620cf4717f..a762e4d338 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationReducer.js +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationReducer.js @@ -13,32 +13,39 @@ * or implied. See the License for the specific language governing * permissions and limitations under the License. */ -import {actionTypes, VERSION_CREATION_FORM_NAME, defaultState} from './VersionsPageCreationConstants.js'; +import { + actionTypes, + VERSION_CREATION_FORM_NAME, + defaultState +} from './VersionsPageCreationConstants.js'; export default (state = {}, action) => { - switch (action.type) { - case actionTypes.OPEN: - return { - ...state, - formReady: null, - formName: VERSION_CREATION_FORM_NAME, - data: {...defaultState}, - genericFieldInfo: { - description: { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}, {type: 'maxLength', data: 120}] - }, - creationMethod: { - isValid: true, - errorText: '', - validations: [{type: 'required', data: true}] - } - } - }; - case actionTypes.CLOSE: - return {}; - default: - return state; - } + switch (action.type) { + case actionTypes.OPEN: + return { + ...state, + formReady: null, + formName: VERSION_CREATION_FORM_NAME, + data: { ...defaultState }, + genericFieldInfo: { + description: { + isValid: true, + errorText: '', + validations: [ + { type: 'required', data: true }, + { type: 'maxLength', data: 120 } + ] + }, + creationMethod: { + isValid: true, + errorText: '', + validations: [{ type: 'required', data: true }] + } + } + }; + case actionTypes.CLOSE: + return {}; + default: + return state; + } }; diff --git a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationView.jsx b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationView.jsx index caa85fe107..ba92d26067 100644 --- a/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationView.jsx +++ b/openecomp-ui/src/sdc-app/onboarding/versionsPage/creation/VersionsPageCreationView.jsx @@ -20,125 +20,116 @@ import Input from 'nfvo-components/input/validation/Input.jsx'; import Form from 'nfvo-components/input/validation/Form.jsx'; const VersionPropType = PropTypes.shape({ - name: PropTypes.string, - description: PropTypes.string, - creationMethod: PropTypes.string + name: PropTypes.string, + description: PropTypes.string, + creationMethod: PropTypes.string }); class VersionsPageCreationView extends React.Component { - - static propTypes = { - data: VersionPropType, - availableMethods: PropTypes.array, - onDataChanged: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - onCancel: PropTypes.func.isRequired - }; - - render() { - let {data = {}, genericFieldInfo, baseVersion, onDataChanged, onCancel} = this.props; - let {additionalInfo: {OptionalCreationMethods}} = baseVersion; - let {description, creationMethod} = data; - - return ( - <div className='version-creation-page'> - { genericFieldInfo && <Form - ref={(validationForm) => this.validationForm = validationForm} - hasButtons={true} - onSubmit={() => this.submit()} - submitButtonText={i18n('Create')} - onReset={() => onCancel()} - labledButtons={true} - isValid={this.props.isFormValid} - formReady={this.props.formReady} - onValidateForm={() => this.validate()}> - - <div className='version-form-row'> - <Input - label={i18n('Version Category')} - value={creationMethod} - onChange={e => this.onSelectMethod(e)} - type='select' - overlayPos='bottom' - data-test-id='new-version-category' - isValid={genericFieldInfo.creationMethod.isValid} - errorText={genericFieldInfo.creationMethod.errorText} - isRequired> - <option key='' value=''>{i18n('Please select…')}</option> - {OptionalCreationMethods.map(method => <option key={method} value={method}>{i18n(method)}</option>)} - </Input> - </div> - - <div className='version-form-row'> - <Input - label={i18n('Description')} - value={description} - type='text' - overlayPos='bottom' - data-test-id='new-version-description' - isValid={genericFieldInfo.description.isValid} - errorText={genericFieldInfo.description.errorText} - onChange={description => onDataChanged({description})} - isRequired /> - </div> - - </Form> } - </div> - ); - } - - onSelectMethod(e) { - const selectedIndex = e.target.selectedIndex; - const creationMethod = e.target.options[selectedIndex].value; - this.props.onDataChanged({creationMethod}); - } - - submit() { - let {baseVersion, data: {description, creationMethod}} = this.props; - this.props.onSubmit({baseVersion, payload: {description, creationMethod}}); - } - - validate() { - this.props.onValidateForm(); - } - + static propTypes = { + data: VersionPropType, + availableMethods: PropTypes.array, + onDataChanged: PropTypes.func.isRequired, + onSubmit: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired + }; + + render() { + let { + data = {}, + genericFieldInfo, + baseVersion, + onDataChanged, + onCancel + } = this.props; + let { additionalInfo: { OptionalCreationMethods } } = baseVersion; + let { description, creationMethod } = data; + + return ( + <div className="version-creation-page"> + {genericFieldInfo && ( + <Form + ref={validationForm => + (this.validationForm = validationForm) + } + hasButtons={true} + onSubmit={() => this.submit()} + submitButtonText={i18n('Create')} + onReset={() => onCancel()} + labledButtons={true} + isValid={this.props.isFormValid} + formReady={this.props.formReady} + onValidateForm={() => this.validate()}> + <div className="version-form-row"> + <Input + label={i18n('Version Category')} + value={creationMethod} + onChange={e => this.onSelectMethod(e)} + type="select" + overlayPos="bottom" + data-test-id="new-version-category" + isValid={ + genericFieldInfo.creationMethod.isValid + } + errorText={ + genericFieldInfo.creationMethod.errorText + } + isRequired> + <option key="" value=""> + {i18n('Please select…')} + </option> + {OptionalCreationMethods.map(method => ( + <option key={method} value={method}> + {i18n(method)} + </option> + ))} + </Input> + </div> + + <div className="version-form-row"> + <Input + label={i18n('Description')} + value={description} + type="text" + overlayPos="bottom" + data-test-id="new-version-description" + isValid={genericFieldInfo.description.isValid} + errorText={ + genericFieldInfo.description.errorText + } + onChange={description => + onDataChanged({ description }) + } + isRequired + /> + </div> + </Form> + )} + </div> + ); + } + + onSelectMethod(e) { + const selectedIndex = e.target.selectedIndex; + const creationMethod = e.target.options[selectedIndex].value; + this.props.onDataChanged({ creationMethod }); + } + + submit() { + let { baseVersion, data: { description, creationMethod } } = this.props; + this.props.onSubmit({ + baseVersion, + payload: { description, creationMethod } + }); + } + + validate() { + this.props.onValidateForm(); + } } export default VersionsPageCreationView; - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - /* <div className='software-product-inline-section'> <Input diff --git a/openecomp-ui/src/sdc-app/sdc.app.jsx b/openecomp-ui/src/sdc-app/sdc.app.jsx index b467e3ca9d..b759ffd259 100644 --- a/openecomp-ui/src/sdc-app/sdc.app.jsx +++ b/openecomp-ui/src/sdc-app/sdc.app.jsx @@ -25,9 +25,18 @@ import Application from './Application.jsx'; import Modules from './ModulesOptions.jsx'; //chrome 48 remove svg method which is used in jointjs core -> https://github.com/cpettitt/dagre-d3/issues/202 --> http://jointjs.com/blog/get-transform-to-element-polyfill.html -SVGElement.prototype.getTransformToElement = SVGElement.prototype.getTransformToElement || function(toElement) { - return toElement.getScreenCTM().inverse().multiply(this.getScreenCTM()); -}; - -ReactDOM.render(<Application><Modules/></Application>, document.getElementById('sdc-app')); +SVGElement.prototype.getTransformToElement = + SVGElement.prototype.getTransformToElement || + function(toElement) { + return toElement + .getScreenCTM() + .inverse() + .multiply(this.getScreenCTM()); + }; +ReactDOM.render( + <Application> + <Modules /> + </Application>, + document.getElementById('sdc-app') +); diff --git a/openecomp-ui/webpack.common.js b/openecomp-ui/webpack.common.js index d1038b6655..5506670e54 100644 --- a/openecomp-ui/webpack.common.js +++ b/openecomp-ui/webpack.common.js @@ -4,41 +4,77 @@ let path = require('path'); let localDevConfig = {}; try { - localDevConfig = require('./devConfig'); + localDevConfig = require('./devConfig'); } catch (e) { - console.log('Could not find local dev config.'); + console.log('Could not find local dev config.'); } -let devConfig = Object.assign({}, require('./devConfig.defaults'), localDevConfig); +let devConfig = Object.assign( + {}, + require('./devConfig.defaults'), + localDevConfig +); module.exports = { - entry: devConfig.bundles, - resolve: { - modules: [path.resolve('.'), path.join(__dirname, 'node_modules')], - alias: { - 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', - 'react-select/dist/' : 'node_modules/react-select/dist/', - 'jquery' : 'node_modules/restful-js/node_modules/jquery' - } - }, - module: { - rules: [ - {test: /\.(js|jsx)$/, loader: 'source-map-loader', exclude: [/node_modules/, path.resolve(__dirname, '../dox-sequence-diagram/')], enforce: 'pre'}, - {test: /\.(js|jsx)$/, use: [ - {loader : 'babel-loader'}, - {loader : 'eslint-loader'}], exclude: [/node_modules/, path.resolve(__dirname, '../dox-sequence-diagram/')]}, - {test: /\.(css|scss)$/, use: [ - {loader: 'style-loader'}, - {loader: 'css-loader?sourceMap'}, - {loader: 'sass-loader?sourceMap', options: { output: { path: path.join(__dirname, 'dist') } }}]}, + entry: devConfig.bundles, + resolve: { + modules: [path.resolve('.'), path.join(__dirname, 'node_modules')], + alias: { + 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', + 'react-select/dist/': 'node_modules/react-select/dist/', + jquery: 'node_modules/restful-js/node_modules/jquery' + } + }, + module: { + rules: [ + { + test: /\.(js|jsx)$/, + loader: 'source-map-loader', + exclude: [ + /node_modules/, + path.resolve(__dirname, '../dox-sequence-diagram/') + ], + enforce: 'pre' + }, + { + test: /\.(js|jsx)$/, + use: [ + { loader: 'babel-loader' }, + { loader: 'eslint-loader', options: { fix: false } } + ], + exclude: [ + /node_modules/, + path.resolve(__dirname, '../dox-sequence-diagram/') + ] + }, + { + test: /\.(css|scss)$/, + use: [ + { loader: 'style-loader' }, + { loader: 'css-loader?sourceMap' }, + { + loader: 'sass-loader?sourceMap', + options: { + output: { path: path.join(__dirname, 'dist') } + } + } + ] + }, - // required for font icons - {test: /\.(woff|woff2)(\?.*)?$/, loader: 'url-loader?limit=16384&mimetype=application/font-woff'}, - {test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader'}, - {test: /\.(png|jpg|svg)(\?.*)?$/, loader: 'url-loader?limit=16384', exclude: path.join(__dirname, 'resources/images/svg') }, - {test: /\.html$/, use: [ {loader: 'html-loader'}]} - ] - }, - plugins: [] + // required for font icons + { + test: /\.(woff|woff2)(\?.*)?$/, + loader: 'url-loader?limit=16384&mimetype=application/font-woff' + }, + { test: /\.(ttf|eot|otf)(\?.*)?$/, loader: 'file-loader' }, + { + test: /\.(png|jpg|svg)(\?.*)?$/, + loader: 'url-loader?limit=16384', + exclude: path.join(__dirname, 'resources/images/svg') + }, + { test: /\.html$/, use: [{ loader: 'html-loader' }] } + ] + }, + plugins: [] }; diff --git a/openecomp-ui/webpack.production.js b/openecomp-ui/webpack.production.js index 2dea2170ae..22da77e6ed 100644 --- a/openecomp-ui/webpack.production.js +++ b/openecomp-ui/webpack.production.js @@ -10,48 +10,57 @@ let webpackCommon = require('./webpack.common'); // copying the common config let webpackProdConfig = cloneDeep(webpackCommon); // setting production settings -assign( webpackProdConfig, { - devtool: undefined, - cache: true, - output: { - path: path.join(__dirname, 'dist'), - publicPath: '/onboarding/', - filename: '[name].js' - }, - resolveLoader: { - modules: [path.join(__dirname, 'node_modules'), path.resolve('.')], - alias: { - 'config-json-loader': 'tools/webpack/config-json-loader/index.js' - } - }, - plugins: [ - new webpack.DefinePlugin({ - 'process.env': { - // This has effect on the react lib size - 'NODE_ENV': JSON.stringify('production') - }, - DEBUG: false, - DEV: false - }), - new webpack.optimize.UglifyJsPlugin(), - new webpack.LoaderOptionsPlugin({ - options: { - eslint: { - configFile: './.eslintrc', - emitError: true, - emitWarning: true, - failOnError: true - } - } - }) - ] +assign(webpackProdConfig, { + devtool: undefined, + cache: true, + output: { + path: path.join(__dirname, 'dist'), + publicPath: '/onboarding/', + filename: '[name].js' + }, + resolveLoader: { + modules: [path.join(__dirname, 'node_modules'), path.resolve('.')], + alias: { + 'config-json-loader': 'tools/webpack/config-json-loader/index.js' + } + }, + plugins: [ + new webpack.DefinePlugin({ + 'process.env': { + // This has effect on the react lib size + NODE_ENV: JSON.stringify('production') + }, + DEBUG: false, + DEV: false + }), + new webpack.optimize.UglifyJsPlugin(), + new webpack.LoaderOptionsPlugin({ + options: { + eslint: { + configFile: './.eslintrc', + emitError: true, + emitWarning: true, + failOnError: true + } + } + }) + ] }); -webpackProdConfig.module.rules = webpackProdConfig.module.rules.filter(rule => ((rule.enforce !== 'pre') || (rule.enforce === 'pre' && rule.loader !== 'source-map-loader'))); +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', '')); - } + 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' }] }); -webpackProdConfig.module.rules.push({test: /config.json$/, use: [{loader:'config-json-loader'}]}); module.exports = webpackProdConfig; diff --git a/openecomp-ui/yarn.lock b/openecomp-ui/yarn.lock index fe991f31be..e7b68d1f36 100644 --- a/openecomp-ui/yarn.lock +++ b/openecomp-ui/yarn.lock @@ -2,26 +2,107 @@ # yarn lockfile v1 -"@angular/common@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@angular/common/-/common-2.3.1.tgz#146c2ed44e02b0f291dd9d4b2e5e2a693057e9bc" +"@angular/common@~2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/common/-/common-2.4.10.tgz#a3a682d2228fa30ec23dd0eb57c8e887fba26997" -"@angular/core@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@angular/core/-/core-2.3.1.tgz#be6e91fdfdd7498506604263e051797cf67a47be" +"@angular/core@~2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/core/-/core-2.4.10.tgz#0b8320a65065965d998645b1f5cd3cf769b441ea" -"@angular/platform-browser-dynamic@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-2.3.1.tgz#d01f3c0c25c628be83c308e83d53128222f558fa" +"@angular/forms@~2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/forms/-/forms-2.4.10.tgz#062133aaade1f3b3c962f1593208c541b622fd06" -"@angular/platform-browser@2.3.1": - version "2.3.1" - resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-2.3.1.tgz#114309150876188e0df8841b20ca2359fd5e7cad" +"@angular/http@^2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/http/-/http-2.4.10.tgz#ff6beade5b39c989ebf2393c49b34eebd43e9555" + +"@angular/platform-browser-dynamic@~2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/platform-browser-dynamic/-/platform-browser-dynamic-2.4.10.tgz#8df25dec2b06adc690cc9bc26448deccaebcd8ec" + +"@angular/platform-browser@~2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/platform-browser/-/platform-browser-2.4.10.tgz#cbf25608148fb4ffef96cc5005ba5d7b3e093906" "@angular/router@~3.2.1": version "3.2.4" resolved "https://registry.yarnpkg.com/@angular/router/-/router-3.2.4.tgz#dfec71ad072ec031364ba5d08bd6fe03fd5beadc" +"@angular/upgrade@^2.4.8": + version "2.4.10" + resolved "https://registry.yarnpkg.com/@angular/upgrade/-/upgrade-2.4.10.tgz#b69a3ee324d4450eb1696ddc9bded1a6ec06ca52" + +"@babel/code-frame@7.0.0-beta.40", "@babel/code-frame@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0-beta.40.tgz#37e2b0cf7c56026b4b21d3927cadf81adec32ac6" + dependencies: + "@babel/highlight" "7.0.0-beta.40" + +"@babel/generator@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.0.0-beta.40.tgz#ab61f9556f4f71dbd1138949c795bb9a21e302ea" + dependencies: + "@babel/types" "7.0.0-beta.40" + jsesc "^2.5.1" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +"@babel/helper-function-name@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.0.0-beta.40.tgz#9d033341ab16517f40d43a73f2d81fc431ccd7b6" + dependencies: + "@babel/helper-get-function-arity" "7.0.0-beta.40" + "@babel/template" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" + +"@babel/helper-get-function-arity@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0-beta.40.tgz#ac0419cf067b0ec16453e1274f03878195791c6e" + dependencies: + "@babel/types" "7.0.0-beta.40" + +"@babel/highlight@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.0.0-beta.40.tgz#b43d67d76bf46e1d10d227f68cddcd263786b255" + dependencies: + chalk "^2.0.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +"@babel/template@7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.0.0-beta.40.tgz#034988c6424eb5c3268fe6a608626de1f4410fc8" + dependencies: + "@babel/code-frame" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" + babylon "7.0.0-beta.40" + lodash "^4.2.0" + +"@babel/traverse@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.0.0-beta.40.tgz#d140e449b2e093ef9fe1a2eecc28421ffb4e521e" + dependencies: + "@babel/code-frame" "7.0.0-beta.40" + "@babel/generator" "7.0.0-beta.40" + "@babel/helper-function-name" "7.0.0-beta.40" + "@babel/types" "7.0.0-beta.40" + babylon "7.0.0-beta.40" + debug "^3.0.1" + globals "^11.1.0" + invariant "^2.2.0" + lodash "^4.2.0" + +"@babel/types@7.0.0-beta.40", "@babel/types@^7.0.0-beta.40": + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.40.tgz#25c3d7aae14126abe05fcb098c65a66b6d6b8c14" + dependencies: + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^2.0.0" + "@kadira/react-split-pane@^1.4.0": version "1.4.7" resolved "https://registry.yarnpkg.com/@kadira/react-split-pane/-/react-split-pane-1.4.7.tgz#6d753d4a9fe62fe82056e323a6bcef7f026972b5" @@ -365,6 +446,10 @@ acorn@^5.0.0, acorn@^5.2.1: version "5.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.3.0.tgz#7446d39459c54fb49a80e6ee6478149b940ec822" +acorn@^5.4.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.0.tgz#1abb587fbf051f94e3de20e6b26ef910b1828298" + airbnb-js-shims@^1.0.1, airbnb-js-shims@^1.4.0: version "1.4.1" resolved "https://registry.yarnpkg.com/airbnb-js-shims/-/airbnb-js-shims-1.4.1.tgz#cc3e8eb8d35877f9d0fdc6583e26b0ee75b98ad0" @@ -382,7 +467,7 @@ airbnb-js-shims@^1.0.1, airbnb-js-shims@^1.4.0: string.prototype.padend "^3.0.0" string.prototype.padstart "^3.0.0" -ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: +ajv-keywords@^1.1.1: version "1.5.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" @@ -390,6 +475,10 @@ ajv-keywords@^2.0.0, ajv-keywords@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-2.1.1.tgz#617997fc5f60576894c435f940d819e135b80762" +ajv-keywords@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.1.0.tgz#ac2b27939c543e95d2c06e7f7f5c27be4aa543be" + ajv@^4.7.0, ajv@^4.9.1: version "4.11.8" resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" @@ -397,7 +486,7 @@ ajv@^4.7.0, ajv@^4.9.1: co "^4.6.0" json-stable-stringify "^1.0.1" -ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: +ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5, ajv@^5.3.0: version "5.5.2" resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965" dependencies: @@ -406,6 +495,14 @@ ajv@^5.0.0, ajv@^5.1.0, ajv@^5.1.5: fast-json-stable-stringify "^2.0.0" json-schema-traverse "^0.3.0" +ajv@^6.0.1: + version "6.2.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.2.0.tgz#afac295bbaa0152449e522742e4547c1ae9328d2" + dependencies: + fast-deep-equal "^1.0.0" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.3.0" + align-text@^0.1.1, align-text@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" @@ -434,10 +531,6 @@ ansi-cyan@^0.1.1: dependencies: ansi-wrap "0.1.0" -ansi-escapes@^1.1.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" - ansi-escapes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.0.0.tgz#ec3e8b4e9f8064fc02c3ac9b65f1c275bda8ef92" @@ -804,14 +897,16 @@ babel-core@^6.0.0, babel-core@^6.11.4, babel-core@^6.24.0, babel-core@^6.26.0: slash "^1.0.0" source-map "^0.5.6" -babel-eslint@^7.2.1: - version "7.2.3" - resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" +babel-eslint@^8.2.1: + version "8.2.2" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-8.2.2.tgz#1102273354c6f0b29b4ea28a65f97d122296b68b" dependencies: - babel-code-frame "^6.22.0" - babel-traverse "^6.23.1" - babel-types "^6.23.0" - babylon "^6.17.0" + "@babel/code-frame" "^7.0.0-beta.40" + "@babel/traverse" "^7.0.0-beta.40" + "@babel/types" "^7.0.0-beta.40" + babylon "^7.0.0-beta.40" + eslint-scope "~3.7.1" + eslint-visitor-keys "^1.0.0" babel-generator@^6.18.0, babel-generator@^6.26.0: version "6.26.0" @@ -1877,12 +1972,6 @@ babel-register@^6.26.0: mkdirp "^0.5.1" source-map-support "^0.4.15" -babel-runtime@5.8.19: - version "5.8.19" - resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-5.8.19.tgz#05ee3aaf67e6d4a39f1bc0f07598b26b9ceb4d3e" - dependencies: - core-js "^0.9.0" - babel-runtime@6.11.6: version "6.11.6" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.11.6.tgz#6db707fef2d49c49bfa3cb64efdb436b518b8222" @@ -1907,7 +1996,7 @@ babel-template@^6.16.0, babel-template@^6.24.1, babel-template@^6.26.0, babel-te babylon "^6.18.0" lodash "^4.17.4" -babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-traverse@^6.24.1, babel-traverse@^6.26.0, babel-traverse@^6.4.5: +babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.24.1, babel-traverse@^6.26.0, babel-traverse@^6.4.5: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.26.0.tgz#46a9cbd7edcc62c8e5c064e2d2d8d0f4035766ee" dependencies: @@ -1921,7 +2010,7 @@ babel-traverse@^6.16.0, babel-traverse@^6.18.0, babel-traverse@^6.23.1, babel-tr invariant "^2.2.2" lodash "^4.17.4" -babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1, babel-types@^6.26.0: +babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.24.1, babel-types@^6.26.0: version "6.26.0" resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.26.0.tgz#a3b073f94ab49eb6fa55cd65227a334380632497" dependencies: @@ -1930,7 +2019,11 @@ babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.23 lodash "^4.17.4" to-fast-properties "^1.0.3" -babylon@^6.17.0, babylon@^6.18.0, babylon@^6.4.5: +babylon@7.0.0-beta.40, babylon@^7.0.0-beta.40: + version "7.0.0-beta.40" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-7.0.0-beta.40.tgz#91fc8cd56d5eb98b28e6fde41045f2957779940a" + +babylon@^6.18.0, babylon@^6.4.5: version "6.18.0" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3" @@ -2207,7 +2300,7 @@ buffer@^4.3.0, buffer@^4.9.0: ieee754 "^1.1.4" isarray "^1.0.0" -builtin-modules@^1.0.0: +builtin-modules@^1.0.0, builtin-modules@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" @@ -2359,6 +2452,14 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" +chalk@^2.0.0, chalk@^2.1.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.1.tgz#523fe2678aec7b04e8041909292fe8b17059b796" + dependencies: + ansi-styles "^3.2.0" + escape-string-regexp "^1.0.5" + supports-color "^5.2.0" + chalk@^2.0.1, chalk@^2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.3.0.tgz#b5ea48efc9c1793dccc9b4767c93914d3f2d52ba" @@ -2367,6 +2468,10 @@ chalk@^2.0.1, chalk@^2.3.0: escape-string-regexp "^1.0.5" supports-color "^4.0.0" +chardet@^0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.4.2.tgz#b5473b33dc97c424e5d98dc87d55d4d8a29c8bf2" + charenc@~0.0.1: version "0.0.2" resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667" @@ -2478,11 +2583,11 @@ clean-css@4.1.x: dependencies: source-map "0.5.x" -cli-cursor@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" dependencies: - restore-cursor "^1.0.1" + restore-cursor "^2.0.0" cli-width@^2.0.0: version "2.2.0" @@ -2681,7 +2786,7 @@ concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.5.0: +concat-stream@^1.5.0, concat-stream@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -2732,6 +2837,10 @@ constants-browserify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + content-disposition@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" @@ -2771,10 +2880,6 @@ copy-descriptor@^0.1.0: version "0.1.1" resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" -core-js@^0.9.0: - version "0.9.18" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-0.9.18.tgz#13f458e430232b0f4ec1f480da7c2f5288e9d095" - core-js@^1.0.0: version "1.2.7" resolved "https://registry.yarnpkg.com/core-js/-/core-js-1.2.7.tgz#652294c14651db28fa93bd2d5ff2983a4f08c636" @@ -2841,7 +2946,7 @@ cross-spawn@^3.0.0: lru-cache "^4.0.1" which "^1.2.9" -cross-spawn@^5.0.1: +cross-spawn@^5.0.1, cross-spawn@^5.1.0: version "5.1.0" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-5.1.0.tgz#e8bd0efee58fcff6f8f94510a0a554bbfa235449" dependencies: @@ -3315,13 +3420,13 @@ dateformat@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" -debug@2.6.9, debug@^2.1.1, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8: +debug@2.6.9, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" dependencies: ms "2.0.0" -debug@^3.1.0: +debug@^3.0.1, debug@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" dependencies: @@ -3511,14 +3616,14 @@ dns-txt@^2.0.2: dependencies: buffer-indexof "^1.0.0" -doctrine@^1.2.2: +doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" dependencies: esutils "^2.0.2" isarray "^1.0.0" -doctrine@^2.0.0: +doctrine@^2.0.0, doctrine@^2.0.2, doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" dependencies: @@ -3879,9 +3984,22 @@ escope@^3.6.0: esrecurse "^4.1.0" estraverse "^4.1.1" -eslint-loader@^1.3.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.9.0.tgz#7e1be9feddca328d3dcfaef1ad49d5beffe83a13" +eslint-config-prettier@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-2.9.0.tgz#5ecd65174d486c22dff389fe036febf502d468a3" + dependencies: + get-stdin "^5.0.1" + +eslint-import-resolver-node@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.2.tgz#58f15fb839b8d0576ca980413476aab2472db66a" + dependencies: + debug "^2.6.9" + resolve "^1.5.0" + +eslint-loader@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.0.0.tgz#d136619b5c684e36531ffc28c60a56e404608f5d" dependencies: loader-fs-cache "^1.0.0" loader-utils "^1.0.2" @@ -3889,65 +4007,102 @@ eslint-loader@^1.3.0: object-hash "^1.1.4" rimraf "^2.6.1" -eslint-plugin-import@^0.8.1: - version "0.8.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-0.8.1.tgz#c1e076097d913cbdfd58f1d14f49205d8a33a735" +eslint-module-utils@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.1.1.tgz#abaec824177613b8a95b299639e1b6facf473449" dependencies: - babel-runtime "5.8.19" - espree "^2.0.1" - resolve "^1.1.6" + debug "^2.6.8" + pkg-dir "^1.0.0" -eslint-plugin-react@^3.14.0: - version "3.16.1" - resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-3.16.1.tgz#262d96b77d7c4a42af809a73c0e527a58612293c" +eslint-plugin-import@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.9.0.tgz#26002efbfca5989b7288ac047508bd24f217b169" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.6.8" + doctrine "1.5.0" + eslint-import-resolver-node "^0.3.1" + eslint-module-utils "^2.1.1" + has "^1.0.1" + lodash "^4.17.4" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" -eslint@^2.13.1: - version "2.13.1" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-2.13.1.tgz#e4cc8fa0f009fb829aaae23855a29360be1f6c11" +eslint-plugin-prettier@^2.6.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-2.6.0.tgz#33e4e228bdb06142d03c560ce04ec23f6c767dd7" dependencies: - chalk "^1.1.3" - concat-stream "^1.4.6" - debug "^2.1.1" - doctrine "^1.2.2" - es6-map "^0.1.3" - escope "^3.6.0" - espree "^3.1.6" - estraverse "^4.2.0" + fast-diff "^1.1.1" + jest-docblock "^21.0.0" + +eslint-plugin-react@^7.7.0: + version "7.7.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-7.7.0.tgz#f606c719dbd8a1a2b3d25c16299813878cca0160" + dependencies: + doctrine "^2.0.2" + has "^1.0.1" + jsx-ast-utils "^2.0.1" + prop-types "^15.6.0" + +eslint-scope@^3.7.1, eslint-scope@~3.7.1: + version "3.7.1" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-3.7.1.tgz#3d63c3edfda02e06e01a452ad88caacc7cdcb6e8" + dependencies: + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-visitor-keys@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d" + +eslint@^4.18.1: + version "4.18.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-4.18.1.tgz#b9138440cb1e98b2f44a0d578c6ecf8eae6150b0" + dependencies: + ajv "^5.3.0" + babel-code-frame "^6.22.0" + chalk "^2.1.0" + concat-stream "^1.6.0" + cross-spawn "^5.1.0" + debug "^3.1.0" + doctrine "^2.1.0" + eslint-scope "^3.7.1" + eslint-visitor-keys "^1.0.0" + espree "^3.5.2" + esquery "^1.0.0" esutils "^2.0.2" - file-entry-cache "^1.1.1" - glob "^7.0.3" - globals "^9.2.0" - ignore "^3.1.2" + file-entry-cache "^2.0.0" + functional-red-black-tree "^1.0.1" + glob "^7.1.2" + globals "^11.0.1" + ignore "^3.3.3" imurmurhash "^0.1.4" - inquirer "^0.12.0" - is-my-json-valid "^2.10.0" + inquirer "^3.0.6" is-resolvable "^1.0.0" - js-yaml "^3.5.1" - json-stable-stringify "^1.0.0" + js-yaml "^3.9.1" + json-stable-stringify-without-jsonify "^1.0.1" levn "^0.3.0" - lodash "^4.0.0" - mkdirp "^0.5.0" - optionator "^0.8.1" - path-is-absolute "^1.0.0" - path-is-inside "^1.0.1" - pluralize "^1.2.1" - progress "^1.1.8" - require-uncached "^1.0.2" - shelljs "^0.6.0" - strip-json-comments "~1.0.1" - table "^3.7.8" + lodash "^4.17.4" + minimatch "^3.0.2" + mkdirp "^0.5.1" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.2" + pluralize "^7.0.0" + progress "^2.0.0" + require-uncached "^1.0.3" + semver "^5.3.0" + strip-ansi "^4.0.0" + strip-json-comments "~2.0.1" + table "^4.0.1" text-table "~0.2.0" - user-home "^2.0.0" - -espree@^2.0.1: - version "2.2.5" - resolved "https://registry.yarnpkg.com/espree/-/espree-2.2.5.tgz#df691b9310889402aeb29cc066708c56690b854b" -espree@^3.1.6: - version "3.5.2" - resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.2.tgz#756ada8b979e9dcfcdb30aad8d1a9304a905e1ca" +espree@^3.5.2: + version "3.5.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.5.3.tgz#931e0af64e7fbbed26b050a29daad1fc64799fa6" dependencies: - acorn "^5.2.1" + acorn "^5.4.0" acorn-jsx "^3.0.0" esprima-fb@^15001.1.0-dev-harmony-fb: @@ -3966,6 +4121,12 @@ esprima@^4.0.0, esprima@~4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804" +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + esrecurse@^4.1.0: version "4.2.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.0.tgz#fa9568d98d3823f9a41d91e902dcab9ea6e5b163" @@ -3973,7 +4134,7 @@ esrecurse@^4.1.0: estraverse "^4.1.0" object-assign "^4.0.1" -estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" @@ -4039,10 +4200,6 @@ exenv@^1.2.0, exenv@^1.2.1: version "1.2.2" resolved "https://registry.yarnpkg.com/exenv/-/exenv-1.2.2.tgz#2ae78e85d9894158670b03d47bec1f03bd91bb9d" -exit-hook@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" - exit@0.1.2, exit@0.1.x: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -4146,6 +4303,14 @@ extend@^3.0.0, extend@~3.0.0, extend@~3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" +external-editor@^2.0.4: + version "2.1.0" + resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-2.1.0.tgz#3d026a21b7f95b5726387d4200ac160d372c3b48" + dependencies: + chardet "^0.4.0" + iconv-lite "^0.4.17" + tmp "^0.0.33" + extglob@^0.3.1: version "0.3.2" resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" @@ -4189,6 +4354,10 @@ fast-deep-equal@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz#96256a3bc975595eb36d82e9929d060d893439ff" +fast-diff@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154" + fast-json-stable-stringify@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" @@ -4235,16 +4404,15 @@ fbjs@^0.8.12, fbjs@^0.8.16, fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" -figures@^1.3.5: - version "1.7.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" +figures@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" dependencies: escape-string-regexp "^1.0.5" - object-assign "^4.1.0" -file-entry-cache@^1.1.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-1.3.1.tgz#44c61ea607ae4be9c1402f41f44270cbfe334ff8" +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" dependencies: flat-cache "^1.2.1" object-assign "^4.0.1" @@ -4510,6 +4678,10 @@ function.prototype.name@^1.0.0, function.prototype.name@^1.1.0: function-bind "^1.1.1" is-callable "^1.1.3" +functional-red-black-tree@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" + fuse.js@^2.2.0: version "2.7.4" resolved "https://registry.yarnpkg.com/fuse.js/-/fuse.js-2.7.4.tgz#96e420fde7ef011ac49c258a621314fe576536f9" @@ -4565,6 +4737,10 @@ get-stdin@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + get-stream@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14" @@ -4717,7 +4893,11 @@ global@^4.3.0, global@^4.3.2: min-document "^2.19.0" process "~0.5.1" -globals@^9.18.0, globals@^9.2.0: +globals@^11.0.1, globals@^11.1.0: + version "11.3.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-11.3.0.tgz#e04fdb7b9796d8adac9c8f64c14837b2313378b0" + +globals@^9.18.0: version "9.18.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a" @@ -4967,6 +5147,10 @@ has-flag@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-2.0.0.tgz#e8207af1cc7b30d446cc70b734b5e8be18f88d51" +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + has-gulplog@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/has-gulplog/-/has-gulplog-0.1.0.tgz#6414c82913697da51590397dafb12f22967811ce" @@ -5215,6 +5399,10 @@ http-errors@1.6.2, http-errors@~1.6.2: setprototypeof "1.0.3" statuses ">= 1.3.1 < 2" +http-loader@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/http-loader/-/http-loader-0.0.1.tgz#b04f8c2d8e872ae079572606eff0f4b8ef55d07c" + http-parser-js@>=0.4.0: version "0.4.9" resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.9.tgz#ea1a04fb64adff0242e9974f297dd4c3cad271e1" @@ -5267,7 +5455,7 @@ i@0.3.x: version "0.3.6" resolved "https://registry.yarnpkg.com/i/-/i-0.3.6.tgz#d96c92732076f072711b6b10fd7d4f65ad8ee23d" -iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.5, iconv-lite@~0.4.13: +iconv-lite@0.4, iconv-lite@0.4.19, iconv-lite@^0.4.17, iconv-lite@^0.4.5, iconv-lite@~0.4.13: version "0.4.19" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b" @@ -5293,7 +5481,7 @@ ignore-loader@^0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/ignore-loader/-/ignore-loader-0.1.2.tgz#d81f240376d0ba4f0d778972c3ad25874117a463" -ignore@^3.1.2: +ignore@^3.3.3: version "3.3.7" resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.7.tgz#612289bfb3c220e186a58118618d5be8c1bab021" @@ -5371,22 +5559,23 @@ inline-style-prefixer@^3.0.6: bowser "^1.7.3" css-in-js-utils "^2.0.0" -inquirer@^0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" +inquirer@^3.0.6: + version "3.3.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-3.3.0.tgz#9dd2f2ad765dcab1ff0443b491442a20ba227dc9" dependencies: - ansi-escapes "^1.1.0" - ansi-regex "^2.0.0" - chalk "^1.0.0" - cli-cursor "^1.0.1" + ansi-escapes "^3.0.0" + chalk "^2.0.0" + cli-cursor "^2.1.0" cli-width "^2.0.0" - figures "^1.3.5" + external-editor "^2.0.4" + figures "^2.0.0" lodash "^4.3.0" - readline2 "^1.0.1" - run-async "^0.1.0" - rx-lite "^3.1.2" - string-width "^1.0.1" - strip-ansi "^3.0.0" + mute-stream "0.0.7" + run-async "^2.2.0" + rx-lite "^4.0.8" + rx-lite-aggregates "^4.0.8" + string-width "^2.1.0" + strip-ansi "^4.0.0" through "^2.3.6" insert-css@^1.0.0: @@ -5437,6 +5626,12 @@ invariant@2.x.x, invariant@^2.0.0, invariant@^2.1.0, invariant@^2.2.1, invariant dependencies: loose-envify "^1.0.0" +invariant@^2.2.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.3.tgz#1a827dfde7dcbd7c323f0ca826be8fa7c5e9d688" + dependencies: + loose-envify "^1.0.0" + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -5608,7 +5803,7 @@ is-glob@^4.0.0: dependencies: is-extglob "^2.1.1" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: +is-my-json-valid@^2.12.4: version "2.17.1" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.17.1.tgz#3da98914a70a22f0a8563ef1511a246c6fc55471" dependencies: @@ -5673,6 +5868,10 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-promise@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" + is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" @@ -5905,7 +6104,7 @@ jest-diff@^21.2.1: jest-get-type "^21.2.0" pretty-format "^21.2.1" -jest-docblock@^21.2.0: +jest-docblock@^21.0.0, jest-docblock@^21.2.0: version "21.2.0" resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-21.2.0.tgz#51529c3b30d5fd159da60c27ceedc195faf8d414" @@ -6073,7 +6272,7 @@ js-tokens@^3.0.0, js-tokens@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b" -js-yaml@^3.4.3, js-yaml@^3.5.1, js-yaml@^3.7.0: +js-yaml@^3.4.3, js-yaml@^3.7.0, js-yaml@^3.9.1: version "3.10.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.10.0.tgz#2e78441646bd4682e963f22b6e92823c309c62dc" dependencies: @@ -6119,6 +6318,10 @@ jsesc@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" +jsesc@^2.5.1: + version "2.5.1" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.1.tgz#e421a2a8e20d6b0819df28908f782526b96dd1fe" + jsesc@~0.5.0: version "0.5.0" resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" @@ -6148,7 +6351,11 @@ json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" -json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + +json-stable-stringify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" dependencies: @@ -6193,6 +6400,12 @@ jstransform@11: object-assign "^2.0.0" source-map "^0.4.2" +jsx-ast-utils@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-2.0.1.tgz#e801b1b39985e20fffc87b40e3748080e2dcac7f" + dependencies: + array-includes "^3.0.3" + jsx-loader@^0.13.2: version "0.13.2" resolved "https://registry.yarnpkg.com/jsx-loader/-/jsx-loader-0.13.2.tgz#9767f643975c78f5e5abeba9bc57885297e732d4" @@ -7019,11 +7232,7 @@ multipipe@^0.1.0, multipipe@^0.1.2: dependencies: duplexer2 "0.0.2" -mute-stream@0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" - -mute-stream@~0.0.4: +mute-stream@0.0.7, mute-stream@~0.0.4: version "0.0.7" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" @@ -7432,9 +7641,11 @@ once@~1.3.0: dependencies: wrappy "1" -onetime@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" opn@^5.1.0: version "5.2.0" @@ -7449,7 +7660,7 @@ optimist@^0.6.1, optimist@~0.6.0: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1: +optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -7504,7 +7715,7 @@ os-locale@^2.0.0: lcid "^1.0.0" mem "^1.1.0" -os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -7636,7 +7847,7 @@ path-is-absolute@^1.0.0, path-is-absolute@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" -path-is-inside@^1.0.1: +path-is-inside@^1.0.1, path-is-inside@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" @@ -7755,9 +7966,9 @@ plugin-error@^1.0.0: arr-union "^3.1.0" extend-shallow "^3.0.2" -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" +pluralize@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-7.0.0.tgz#298b89df8b93b0221dbf421ad2b1b1ea23fc6777" podda@^1.2.1, podda@^1.2.2: version "1.2.2" @@ -8089,6 +8300,10 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" +prettier@^1.10.2: + version "1.10.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.10.2.tgz#1af8356d1842276a99a5b5529c82dd9e9ad3cc93" + pretty-error@^2.0.2: version "2.1.1" resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3" @@ -8123,9 +8338,9 @@ process@~0.5.1: version "0.5.2" resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" -progress@^1.1.8: - version "1.1.8" - resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +progress@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.0.tgz#8a1be366bf8fc23db2bd23f10c6fe920b4389d1f" promise-inflight@^1.0.1: version "1.0.1" @@ -8417,6 +8632,15 @@ react-dom-factories@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/react-dom-factories/-/react-dom-factories-1.0.2.tgz#eb7705c4db36fb501b3aa38ff759616aa0ff96e0" +react-dom@15.6.2, react-dom@^15.6.2: + version "15.6.2" + resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.2.tgz#41cfadf693b757faf2708443a1d1fd5a02bef730" + dependencies: + fbjs "^0.8.9" + loose-envify "^1.1.0" + object-assign "^4.1.0" + prop-types "^15.5.10" + react-dom@16.x.x: version "16.2.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.2.0.tgz#69003178601c0ca19b709b33a83369fe6124c044" @@ -8426,15 +8650,6 @@ react-dom@16.x.x: object-assign "^4.1.1" prop-types "^15.6.0" -react-dom@^15.5.4, react-dom@^15.6.2: - version "15.6.2" - resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-15.6.2.tgz#41cfadf693b757faf2708443a1d1fd5a02bef730" - dependencies: - fbjs "^0.8.9" - loose-envify "^1.1.0" - object-assign "^4.1.0" - prop-types "^15.5.10" - react-dropzone@4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/react-dropzone/-/react-dropzone-4.2.3.tgz#f7bc92aa5fe4253fdb1fd3792114d2d29b47119a" @@ -8681,16 +8896,7 @@ react-truncate@^2.0.5: version "2.3.0" resolved "https://registry.yarnpkg.com/react-truncate/-/react-truncate-2.3.0.tgz#d469b355aff1f83ae9e0f2fed0d47dfd061e5d2e" -react@16.x.x: - version "16.2.0" - resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" - dependencies: - fbjs "^0.8.16" - loose-envify "^1.1.0" - object-assign "^4.1.1" - prop-types "^15.6.0" - -react@^15.4.1, react@^15.5.4, react@^15.6.2: +react@15.6.2, react@^15.4.1, react@^15.6.2: version "15.6.2" resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72" dependencies: @@ -8700,6 +8906,15 @@ react@^15.4.1, react@^15.5.4, react@^15.6.2: object-assign "^4.1.0" prop-types "^15.5.10" +react@16.x.x: + version "16.2.0" + resolved "https://registry.yarnpkg.com/react/-/react-16.2.0.tgz#a31bd2dab89bff65d42134fa187f24d054c273ba" + dependencies: + fbjs "^0.8.16" + loose-envify "^1.1.0" + object-assign "^4.1.1" + prop-types "^15.6.0" + reactcss@^1.2.0: version "1.2.3" resolved "https://registry.yarnpkg.com/reactcss/-/reactcss-1.2.3.tgz#c00013875e557b1cf0dfd9a368a1c3dab3b548dd" @@ -8790,14 +9005,6 @@ readdirp@^2.0.0: readable-stream "^2.0.2" set-immediate-shim "^1.0.1" -readline2@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" - dependencies: - code-point-at "^1.0.0" - is-fullwidth-code-point "^1.0.0" - mute-stream "0.0.5" - recast@^0.11.17, recast@~0.11.12: version "0.11.23" resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3" @@ -9063,7 +9270,7 @@ require-main-filename@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" -require-uncached@^1.0.2: +require-uncached@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" dependencies: @@ -9103,18 +9310,18 @@ resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.6, resolve@^1.1.7: +resolve@^1.1.6, resolve@^1.1.7, resolve@^1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36" dependencies: path-parse "^1.0.5" -restore-cursor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" dependencies: - exit-hook "^1.0.0" - onetime "^1.0.0" + onetime "^2.0.0" + signal-exit "^3.0.2" revalidator@0.1.x: version "0.1.8" @@ -9147,11 +9354,11 @@ rosie@^1.6.0: version "1.6.0" resolved "https://registry.yarnpkg.com/rosie/-/rosie-1.6.0.tgz#bc0ef64cd401d00794450d5792c0276e226b6ab0" -run-async@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" +run-async@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0" dependencies: - once "^1.3.0" + is-promise "^2.1.0" run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" @@ -9171,17 +9378,23 @@ rw@1: version "1.3.3" resolved "https://registry.yarnpkg.com/rw/-/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" -rx-lite@^3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +rx-lite-aggregates@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite-aggregates/-/rx-lite-aggregates-4.0.8.tgz#753b87a89a11c95467c4ac1626c4efc4e05c67be" + dependencies: + rx-lite "*" + +rx-lite@*, rx-lite@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-4.0.8.tgz#0b1e11af8bc44836f04a6407e92da42467b79444" rx@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -rxjs@5.0.0-beta.12: - version "5.0.0-beta.12" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.0.0-beta.12.tgz#cdfde2d8c4639d20ae7794bff8fddf32da7ad337" +rxjs@5.4.2: + version "5.4.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-5.4.2.tgz#2a3236fcbf03df57bae06fd6972fd99e5c08fcf7" dependencies: symbol-observable "^1.0.1" @@ -9246,22 +9459,27 @@ scss-tokenizer@^0.2.3: js-base64 "^2.1.8" source-map "^0.4.2" -sdc-ui@1.6.9: - version "1.6.9" - resolved "https://registry.yarnpkg.com/sdc-ui/-/sdc-ui-1.6.9.tgz#cfb85152b1ff4890e869b0903527462d562a8e68" +sdc-ui@1.6.24: + version "1.6.24" + resolved "https://registry.yarnpkg.com/sdc-ui/-/sdc-ui-1.6.24.tgz#059b0fe6fdc36c962b65853a8012885aa38e78a7" dependencies: - "@angular/common" "2.3.1" - "@angular/core" "2.3.1" - "@angular/platform-browser" "2.3.1" - "@angular/platform-browser-dynamic" "2.3.1" + "@angular/common" "~2.4.8" + "@angular/core" "~2.4.8" + "@angular/forms" "~2.4.8" + "@angular/http" "^2.4.8" + "@angular/platform-browser" "~2.4.8" + "@angular/platform-browser-dynamic" "~2.4.8" "@angular/router" "~3.2.1" + "@angular/upgrade" "^2.4.8" "@storybook/react" "^3.1.5" - react "^15.5.4" - react-dom "^15.5.4" + http-loader "0.0.1" + prop-types "^15.6.0" + react "15.6.2" + react-dom "15.6.2" reflect-metadata "^0.1.3" - rxjs "5.0.0-beta.12" + rxjs "5.4.2" svg-react-loader "^0.4.4" - zone.js "~0.6.26" + zone.js "^0.8.18" select-hose@^2.0.0: version "2.0.0" @@ -9426,10 +9644,6 @@ shelljs@0.3.x: version "0.3.0" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.3.0.tgz#3596e6307a781544f591f37da618360f31db57b1" -shelljs@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.6.1.tgz#ec6211bed1920442088fe0f70b2837232ed2c8a8" - shelljs@^0.7.4, shelljs@^0.7.8: version "0.7.8" resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.8.tgz#decbcf874b0d1e5fb72e14b164a9683048e9acb3" @@ -9454,9 +9668,11 @@ slash@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" -slice-ansi@0.0.4: - version "0.0.4" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slice-ansi@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-1.0.0.tgz#044f1a49d8842ff307aad6b505ed178bd950134d" + dependencies: + is-fullwidth-code-point "^2.0.0" slide@^1.1.5: version "1.1.6" @@ -9582,7 +9798,7 @@ source-map@0.5.6: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" -source-map@0.5.x, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.6: +source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1, source-map@~0.5.6: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -9768,7 +9984,7 @@ string-width@^1.0.1, string-width@^1.0.2: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -string-width@^2.0.0: +string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" dependencies: @@ -9850,7 +10066,7 @@ strip-indent@^1.0.1: dependencies: get-stdin "^4.0.1" -strip-json-comments@1.0.x, strip-json-comments@~1.0.1: +strip-json-comments@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" @@ -9903,6 +10119,12 @@ supports-color@^5.1.0: dependencies: has-flag "^2.0.0" +supports-color@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.2.0.tgz#b0d5333b1184dd3666cbe5aa0b45c5ac7ac17a4a" + dependencies: + has-flag "^3.0.0" + svg-react-loader@^0.4.4: version "0.4.5" resolved "https://registry.yarnpkg.com/svg-react-loader/-/svg-react-loader-0.4.5.tgz#1f324c9c7b858f5c89fac752bbe9ca3f6214f850" @@ -9948,16 +10170,16 @@ symbol-tree@^3.2.1: version "3.2.2" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6" -table@^3.7.8: - version "3.8.3" - resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" +table@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.3.tgz#00b5e2b602f1794b9acaf9ca908a76386a7813bc" dependencies: - ajv "^4.7.0" - ajv-keywords "^1.0.0" - chalk "^1.1.1" - lodash "^4.0.0" - slice-ansi "0.0.4" - string-width "^2.0.0" + ajv "^6.0.1" + ajv-keywords "^3.0.0" + chalk "^2.1.0" + lodash "^4.17.4" + slice-ansi "1.0.0" + string-width "^2.1.1" tapable@^0.1.8, tapable@~0.1.8: version "0.1.10" @@ -10074,6 +10296,12 @@ tinycolor2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/tinycolor2/-/tinycolor2-1.4.1.tgz#f4fad333447bc0b07d4dc8e9209d8f39a8ac77e8" +tmp@^0.0.33: + version "0.0.33" + resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" + dependencies: + os-tmpdir "~1.0.2" + tmpl@1.0.x: version "1.0.4" resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" @@ -10086,6 +10314,10 @@ to-fast-properties@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" +to-fast-properties@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + to-object-path@^0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" @@ -10361,12 +10593,6 @@ user-home@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" -user-home@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" - dependencies: - os-homedir "^1.0.0" - util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" @@ -10986,6 +11212,6 @@ yazl@^2.1.0: dependencies: buffer-crc32 "~0.2.3" -zone.js@~0.6.26: - version "0.6.26" - resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.6.26.tgz#067c13b8b80223a89b62e9dc82680f09762c4636" +zone.js@^0.8.18: + version "0.8.20" + resolved "https://registry.yarnpkg.com/zone.js/-/zone.js-0.8.20.tgz#a218c48db09464b19ff6fc8f0d4bb5b1046e185d" |