From eb2a14bfea2bab749e2d03d78b7e4d0f23961b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miha=20Ple=C5=A1ko?= Date: Fri, 27 Jul 2018 14:08:45 +0200 Subject: [PATCH] React component for creating Nuage subnet MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this commit we implement react component used to capture user inputs for creating CloudSubnet. Also, we add button to NetworkRouter details page to trigger the flow. RFE BZ: https://bugzilla.redhat.com/show_bug.cgi?id=1574972 Signed-off-by: Miha Pleško --- .babelrc | 31 +++++ .gitignore | 3 + .npmrc | 2 + .postcssrc.yml | 4 + .../network_router_center.rb | 35 ++++++ .../create-nuage-cloud-subnet-form.jsx | 68 +++++++++++ .../components/nuage-cloud-subnet-form.jsx | 106 ++++++++++++++++++ .../packs/component-definitions-common.js | 3 + package.json | 41 +++++++ 9 files changed, 293 insertions(+) create mode 100644 .babelrc create mode 100644 .npmrc create mode 100644 .postcssrc.yml create mode 100644 app/helpers/manageiq/providers/nuage/toolbar_overrides/network_router_center.rb create mode 100644 app/javascript/components/create-nuage-cloud-subnet-form.jsx create mode 100644 app/javascript/components/nuage-cloud-subnet-form.jsx create mode 100644 app/javascript/packs/component-definitions-common.js create mode 100644 package.json diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000000..37029bd039 --- /dev/null +++ b/.babelrc @@ -0,0 +1,31 @@ +{ + "presets": [ + [ + "env", + { + "targets": { + "browsers": [ + "> 1%", + "last 2 versions", + "Firefox ESR", + "IE 10", + "IE 11" + ] + } + } + ], + "react", + "es2015", + ], + "plugins": [ + "transform-class-properties", + "transform-export-extensions", + "transform-object-rest-spread", + "transform-object-assign" + ], + "env": { + "test": { + "plugins": ["transform-es2015-modules-commonjs"] + } + } +} diff --git a/.gitignore b/.gitignore index 182eeb079f..f2c7c3bb4b 100644 --- a/.gitignore +++ b/.gitignore @@ -14,3 +14,6 @@ /config/environments/*.local.yml /spec/manageiq + +node_modules/ +yarn.lock diff --git a/.npmrc b/.npmrc new file mode 100644 index 0000000000..99e12685ee --- /dev/null +++ b/.npmrc @@ -0,0 +1,2 @@ +# using yarn +package-lock = false diff --git a/.postcssrc.yml b/.postcssrc.yml new file mode 100644 index 0000000000..bc4f02ab33 --- /dev/null +++ b/.postcssrc.yml @@ -0,0 +1,4 @@ +plugins: + postcss-smart-import: {} + precss: {} + autoprefixer: {} diff --git a/app/helpers/manageiq/providers/nuage/toolbar_overrides/network_router_center.rb b/app/helpers/manageiq/providers/nuage/toolbar_overrides/network_router_center.rb new file mode 100644 index 0000000000..0b896ac151 --- /dev/null +++ b/app/helpers/manageiq/providers/nuage/toolbar_overrides/network_router_center.rb @@ -0,0 +1,35 @@ +module ManageIQ + module Providers + module Nuage + module ToolbarOverrides + class NetworkRouterCenter < ::ApplicationHelper::Toolbar::Override + button_group( + 'nuage_network_router', + [ + select( + :nuage_network_router, + 'fa fa-cog fa-lg', + t = N_('Edit'), + t, + :items => [ + button( + :nuage_create_cloud_subnet, + 'pficon pficon-add-circle-o fa-lg', + t = N_('Create L3 Cloud Subnet'), + t, + :data => {'function' => 'sendDataWithRx', + 'function-data' => {:controller => 'provider_dialogs', + :button => :nuage_create_cloud_subnet, + :modal_title => N_('Create L3 Cloud Subnet'), + :component_name => 'CreateNuageCloudSubnetForm'}.to_json}, + :klass => ApplicationHelper::Button::ButtonWithoutRbacCheck + ), + ] + ) + ] + ) + end + end + end + end +end diff --git a/app/javascript/components/create-nuage-cloud-subnet-form.jsx b/app/javascript/components/create-nuage-cloud-subnet-form.jsx new file mode 100644 index 0000000000..7e782f59f3 --- /dev/null +++ b/app/javascript/components/create-nuage-cloud-subnet-form.jsx @@ -0,0 +1,68 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import NuageCloudSubnetForm from './nuage-cloud-subnet-form' + +const API = window.API; + +const createSubnet = (values, emsId, routerRef) => { + API.post(`/api/providers/${emsId}/cloud_subnets`, { + action: 'create', + resource: {...values, router_ref: routerRef}, + }).then(response => { + let res = response['results'][0]; + window.add_flash(res.message, res.success ? 'success' : 'error'); + }) +}; + +class CreateNuageCloudSubnetForm extends React.Component { + constructor(props) { + super(props); + this.handleFormStateUpdate = this.handleFormStateUpdate.bind(this); + this.routerRef = 'ebca9d3b-53a4-4fd4-8268-196cb3fa6072'; // TODO: pass from Rails + this.emsId = 4; // TODO: pass from Rails + } + + componentDidMount() { + this.props.dispatch({ + type: 'FormButtons.init', + payload: { + newRecord: true, + pristine: true, + addClicked: () => { + createSubnet(this.state.values, this.emsId, this.routerRef); + } + }, + }); + } + + handleFormStateUpdate(formState) { + this.props.dispatch({ + type: 'FormButtons.saveable', + payload: formState.valid, + }); + this.props.dispatch({ + type: 'FormButtons.pristine', + payload: formState.pristine, + }); + this.setState({ values: formState.values }); + } + + render() { + return ( + createSubnet(values, this.emsId, this.routerRef)} + onCancel={() => {} } + loadData={() => {} } + updateFormState={this.handleFormStateUpdate} + hideControls={true} + /> + ); + } +} + +CreateNuageCloudSubnetForm.propTypes = { + dispatch: PropTypes.func.isRequired, +}; + +export default connect()(CreateNuageCloudSubnetForm); diff --git a/app/javascript/components/nuage-cloud-subnet-form.jsx b/app/javascript/components/nuage-cloud-subnet-form.jsx new file mode 100644 index 0000000000..bc4bdd47ae --- /dev/null +++ b/app/javascript/components/nuage-cloud-subnet-form.jsx @@ -0,0 +1,106 @@ +import React, { Component } from 'react'; +import { Form, Field, FormSpy } from 'react-final-form'; +import { Form as PfForm, Grid, Button, Col, Row, Spinner } from 'patternfly-react'; +import PropTypes from 'prop-types'; +import { required, addValidator } from 'redux-form-validators'; + +import { FinalFormField, FinalFormTextArea, FinalFormSelect } from '@manageiq/react-ui-components/dist/forms'; + +const ip4Validator = addValidator({ + defaultMessage: 'Must be IPv4 address', + validator: function(options, value, allValues) { + return (/^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/).test(value) + } +}); + +const netmaskValidator = addValidator({ + defaultMessage: 'Must be netmask', + validator: function(options, value, allValues) { + return (/^(((128|192|224|240|248|252|254)\.0\.0\.0)|(255\.(0|128|192|224|240|248|252|254)\.0\.0)|(255\.255\.(0|128|192|224|240|248|252|254)\.0)|(255\.255\.255\.(0|128|192|224|240|248|252|254)))$/).test(value) + } +}); + +class NuageCloudSubnetForm extends Component { + render() { + const { + onSave, + onCancel, + updateFormState, + hideControls, + } = this.props; + return ( +
( + + updateFormState({ ...state, values: state.values })} /> + + + + + + + + + + + + + + +
+
+ { + !hideControls && + + + + + + + } +
+
+ )} + /> + ); + } +} + +NuageCloudSubnetForm.propTypes = { + onSave: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + loadData: PropTypes.func.isRequired, + updateFormState: PropTypes.func.isRequired, + hideControls: PropTypes.bool, +}; + +NuageCloudSubnetForm.defaultProps = { + hideControls: false, +}; + +export default NuageCloudSubnetForm; diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js new file mode 100644 index 0000000000..e1cf75709d --- /dev/null +++ b/app/javascript/packs/component-definitions-common.js @@ -0,0 +1,3 @@ +import CreateNuageCloudSubnetForm from '../components/create-nuage-cloud-subnet-form'; + +ManageIQ.component.addReact('CreateNuageCloudSubnetForm', CreateNuageCloudSubnetForm); diff --git a/package.json b/package.json new file mode 100644 index 0000000000..972b8b9f6d --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "manageiq-providers-nuage", + "version": "1.0.0", + "description": "ManageIQ Cloud Management Platform", + "main": "index.js", + "repository": { + "type": "git", + "url": "git+https://github.com/ManageIQ/manageiq.git" + }, + "author": "ManageIQ", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/ManageIQ/manageiq/issues" + }, + "homepage": "https://github.com/ManageIQ/manageiq#readme", + "dependencies": { + "@manageiq/react-ui-components": "~0.9.5", + "prop-types": "^15.6.0", + "react": "^16.3.1", + "react-dom": "^16.3.1", + "react-redux": "^5.0.7", + "redux": "^4.0.0" + }, + "devDependencies": { + "babel-plugin-add-module-exports": "^0.2.1", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-plugin-transform-class-properties": "^6.24.1", + "babel-plugin-transform-export-extensions": "^6.22.0", + "babel-plugin-transform-object-assign": "^6.8.0", + "babel-plugin-transform-object-rest-spread": "^6.26.0", + "babel-preset-env": "^1.6.0", + "babel-preset-es2015": "^6.24.1", + "babel-preset-react": "^6.24.1", + "babel-preset-stage-1": "^6.24.1" + }, + "engines": { + "node": ">= 6.9.1", + "npm": ">= 3.10.3", + "yarn": ">= 0.20.1" + } +}