diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/public/themes/default/default-theme.css b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/public/themes/default/default-theme.css index 3aef9f76752..97927374644 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/public/themes/default/default-theme.css +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/public/themes/default/default-theme.css @@ -211,6 +211,10 @@ body { height: 300px; } +#form-error { + color: red; +} + .application-create-banner-dropzone { width: 300px; height: 150px; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/common/validator.js b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/common/validator.js new file mode 100644 index 00000000000..11654012f0f --- /dev/null +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/common/validator.js @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved. + * + * WSO2 Inc. licenses this file to you under the Apache License, + * Version 2.0 (the "License"); you may not use this file except + * in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +'use strict'; + +/** + * This Utility class will contain basic methods for form validation. + * */ +export const validateURL = (value) => { + +}; + +export const validateNull = (value) => { + return !value; +}; + +export const validateEmpty = (array) => { + return array.length > 0; +}; + +export const validateEmptyObject = (object) => { + return Object.keys(object).length > 0; +}; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/ApplicationCreate.jsx b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/ApplicationCreate.jsx index 38620bf8f20..42112f11251 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/ApplicationCreate.jsx +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/ApplicationCreate.jsx @@ -126,7 +126,7 @@ class ApplicationCreate extends Component { * @param data: The form data of the step. * */ setStepData(step, data) { - console.log(step, data, this.state.stepData); //TODO: Remove this + console.log(step, data, this.state); //TODO: Remove this switch (step) { case "generalInfo": { this.setState({generalInfo: data}, this.onNextClick()); diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step1.jsx b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step1.jsx index 9f011fdf675..bffa63b599a 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step1.jsx +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step1.jsx @@ -18,9 +18,9 @@ import PropTypes from 'prop-types'; import React, {Component} from 'react'; -import {Badge, FormGroup, Input, Label} from 'reactstrap'; import {FormattedMessage} from 'react-intl'; -import {Badge, Button, Form, FormGroup, Input, Label, ModalFooter} from 'reactstrap'; +import {Badge, Button, Form, FormFeedback, FormGroup, Input, Label, ModalFooter} from 'reactstrap'; +import * as validator from '../../../../common/validator'; /** * The Second step of application create wizard. @@ -49,6 +49,7 @@ class Step1 extends Component { this.onVisibilityChange = this.onVisibilityChange.bind(this); this.onVisibilityItemSelect = this.onVisibilityItemSelect.bind(this); this.handleRequestDelete = this.handleRequestDelete.bind(this); + this.validate = this.validate.bind(this); this.state = { tags: [], name: "", @@ -63,7 +64,7 @@ class Step1 extends Component { componentWillMount() { const defaultVals = this.props.defaultData; - if(defaultVals) { + if (defaultVals) { this.setState(defaultVals); } @@ -114,19 +115,49 @@ class Step1 extends Component { tags: tags, visibility: visibility }; - this.props.setStepData("generalInfo", stepData); + + let {errorCount, errors} = this.validate(); + + if (errorCount !== 0) { + this.setState({errors: errors}); + } else { + this.props.setStepData("generalInfo", stepData); + } }; onCancelClick() { this.props.close(); } + /** + * Validate the form fields. + * */ + validate() { + const {name, description, tags} = this.state; + let errorCount = 0; + let errors = {}; + if (validator.validateNull(name)) { + errorCount++; + errors.name = "Application Title is Required!"; + } + + if (validator.validateNull(description)) { + errorCount++; + errors.description = "Description is Required!" + } + + if (!validator.validateEmpty(tags)) { + errorCount++; + errors.tags = "You need to enter at least one tag!" + } + return {errorCount, errors}; + } + /** * Set text field values to state. * */ onTextFieldChange(event) { let field = event.target.name; - console.log(field, event.target.value); switch (field) { case "appName": { this.setState({name: event.target.value}); @@ -166,7 +197,7 @@ class Step1 extends Component { onChange={this.onVisibilityItemSelect} > - + @@ -192,7 +223,7 @@ class Step1 extends Component { }; return ( -
+
@@ -207,6 +238,7 @@ class Step1 extends Component { value={this.state.name} onChange={this.onTextFieldChange} /> + {this.state.errors.name}
@@ -293,8 +329,7 @@ class Step1 extends Component { Step1.prototypes = { handleNext: PropTypes.func, handlePrev: PropTypes.func, - setData: PropTypes.func, - removeData: PropTypes.func + setData: PropTypes.func }; export default Step1; diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step2.jsx b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step2.jsx index 3143b2eb856..d6d627cee04 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step2.jsx +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step2.jsx @@ -20,8 +20,9 @@ import PropTypes from 'prop-types'; import React, {Component} from 'react'; import AuthHandler from "../../../../api/authHandler"; import PlatformMgtApi from "../../../../api/platformMgtApi"; -import {Button, FormGroup, Input, Label, ModalFooter} from 'reactstrap'; +import {Button, FormFeedback, FormGroup, Input, Label, ModalFooter} from 'reactstrap'; import {FormattedMessage} from 'react-intl'; +import * as validator from '../../../../common/validator'; /** * The first step of the application creation wizard. @@ -43,11 +44,13 @@ class Step2 extends Component { this.setStepData = this.setStepData.bind(this); this.onCancelClick = this.onCancelClick.bind(this); this.onBackClick = this.onBackClick.bind(this); + this.validate = this.validate.bind(this); this.platforms = []; this.state = { + errors: {}, store: 1, platformSelectedIndex: 0, - platform: "", + platform: {}, platforms: [] }; } @@ -80,7 +83,7 @@ class Step2 extends Component { platform = platforms[index]; tmpPlatforms.push(platform); } - this.setState({platforms: tmpPlatforms, platformSelectedIndex: 0, platform: tmpPlatforms[0].name}) + this.setState({platforms: tmpPlatforms, platformSelectedIndex: 0}) } /** @@ -92,7 +95,14 @@ class Step2 extends Component { store: store, platform: platform[0] }; - this.props.setStepData("platform", data); + + const {errorCount, errors} = this.validate(); + + if (errorCount > 0) { + this.setState({errors: errors}) + } else { + this.props.setStepData("platform", data); + } } onCancelClick() { @@ -103,6 +113,17 @@ class Step2 extends Component { this.props.handlePrev(); } + validate() { + const {store, platform} = this.state; + let errors = {}; + let errorCount = 0; + if (!validator.validateEmptyObject(platform)) { + errorCount++; + errors.platform = "You must select an application platform!" + } + return {errorCount, errors}; + } + /** * Triggers when changing the Platform selection. * */ @@ -149,6 +170,7 @@ class Step2 extends Component { ) }) : } + {this.state.errors.platform} diff --git a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step3.jsx b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step3.jsx index 61b14509d33..76384d2214e 100644 --- a/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step3.jsx +++ b/components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/src/components/Application/Create/CreateSteps/Step3.jsx @@ -19,7 +19,8 @@ import PropTypes from 'prop-types'; import Dropzone from 'react-dropzone'; import React, {Component} from 'react'; -import {Button, FormGroup, Label, ModalFooter} from 'reactstrap'; +import * as validator from '../../../../common/validator'; +import {Button, FormFeedback, FormGroup, Label, ModalFooter} from 'reactstrap'; import AppImage from "../../../UIComponents/AppImage/AppImage"; import {FormattedMessage} from 'react-intl'; @@ -42,6 +43,7 @@ class Step3 extends Component { super(); this.setStepData = this.setStepData.bind(this); this.onBackClick = this.onBackClick.bind(this); + this.validate = this.validate.bind(this); this.onCancelClick = this.onCancelClick.bind(this); this.state = { icon: [], @@ -57,18 +59,6 @@ class Step3 extends Component { this.setState(defaultData); } - /** - * Handles Chip delete function. - * Removes the tag from state.tags - * */ - handleRequestDelete(event) { - this.chipData = this.state.tags; - console.log(event.target); //TODO: Remove Console log. - const chipToDelete = this.chipData.map((chip) => chip.value).indexOf(event.target.value); - this.chipData.splice(chipToDelete, 1); - this.setState({tags: this.chipData}); - }; - /** * Creates an object with the current step data and persist in the parent. * */ @@ -82,7 +72,14 @@ class Step3 extends Component { screenshots: screenshots }; - this.props.setStepData("screenshots", stepData); + const {errorCount, errors} = this.validate(); + + if (errorCount > 0) { + this.setState({errors: errors}) + } else { + this.props.setStepData("screenshots", stepData); + } + }; onCancelClick() { @@ -93,6 +90,28 @@ class Step3 extends Component { this.props.handlePrev(); } + validate() { + const {icon, banner, screenshots} = this.state; + let errors = {}, errorCount = 0; + + if (!validator.validateEmpty(icon)) { + errorCount++; + errors.icon = "You must upload an icon image!" + } + + if (!validator.validateEmpty(banner)) { + errorCount++; + errors.banner = "You must upload a banner image!" + } + + if (!validator.validateEmpty(screenshots)) { + errorCount++; + errors.screenshots = "You must upload at least one screenshot image!" + } + + return {errorCount, errors}; + } + /** * Removed user uploaded banner. * */ @@ -146,6 +165,7 @@ class Step3 extends Component { :
}
+ {this.state.errors.screenshots}
@@ -173,6 +193,7 @@ class Step3 extends Component { :
}
+ {this.state.errors.icon}
@@ -199,6 +220,7 @@ class Step3 extends Component { :
}
+ {this.state.errors.banner}