Added form validation and image visualization to application and platform create. Removed hash router and used browser router.

feature/appm-store/pbac
Menaka Jayawardena 7 years ago
parent 89b4e6dc10
commit b70bf91f3a

@ -25,8 +25,8 @@
manifest.json provides metadata used when your web app is added to the manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/ homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
--> -->
<link rel="manifest" href="%PUBLIC_URL%/publisher/manifest.json"> <link rel="manifest" href="manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/publisher/images/favicon.png"> <link rel="shortcut icon" href="images/favicon.png">
<!-- <!--
Notice the use of %PUBLIC_URL% in the tags above. Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build. It will be replaced with the URL of the `public` folder during the build.
@ -39,6 +39,7 @@
<title>WSO2 IoT App Publisher</title> <title>WSO2 IoT App Publisher</title>
</head> </head>
<body> <body>
<script src='./dist/index.js'></script>
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>

@ -18,8 +18,8 @@
import './App.css'; import './App.css';
import React, {Component} from 'react'; import React, {Component} from 'react';
import createHistory from 'history/createHashHistory'; import createHistory from 'history/createBrowserHistory';
import {HashRouter as Router, Redirect, Route, Switch} from 'react-router-dom' import {BrowserRouter as Router, Redirect, Route, Switch} from 'react-router-dom'
import { import {
ApplicationCreate, ApplicationCreate,
ApplicationListing, ApplicationListing,
@ -41,6 +41,9 @@ const history = createHistory({basename: '/publisher'});
* The Router and Route is used for navigation. * The Router and Route is used for navigation.
* We specify the component which needs to be rendered for an URL. * We specify the component which needs to be rendered for an URL.
* Ex: When navigate to publisher/overview, the overview component will be rendered inside the main layout. * Ex: When navigate to publisher/overview, the overview component will be rendered inside the main layout.
*
* HashRouter is used because the other router types need the server to serve those urls. In hashRouter, server does
* not want to serve the URL.
* */ * */
class Base extends Component { class Base extends Component {
@ -63,9 +66,9 @@ class Base extends Component {
<Route exact path={"/assets/platforms"} component={PlatformListing}/> <Route exact path={"/assets/platforms"} component={PlatformListing}/>
<Route exact path={"/assets/platforms/create"} component={PlatformCreate}/> <Route exact path={"/assets/platforms/create"} component={PlatformCreate}/>
<Route exact path={"/assets/apps/:app"} /> <Route exact path={"/assets/apps/:app"} />
<Route exact path={"/assets/apps/edit/:app"} /> <Route exact path={"/assets/apps/:app/edit"} />
<Route exact path={"/assets/platforms/:platform"}/> <Route exact path={"/assets/platforms/:platform"}/>
<Route exact path={"/assets/platforms/edit/:platform"}/> <Route exact path={"/assets/platforms/:platform/edit"}/>
<Route exact path={"/assets/reviews"}/> <Route exact path={"/assets/reviews"}/>
<Route exact path={"/assets/reviews/:review"}/> <Route exact path={"/assets/reviews/:review"}/>
<Route component={NotFound}/> <Route component={NotFound}/>
@ -80,6 +83,9 @@ class Base extends Component {
/** /**
* This component is referred by the index.js to initiate the application. * This component is referred by the index.js to initiate the application.
* TODO: Currently the URL shows like https://localhost:9443/publisher/#/publisher/assets/apps/create. this needs to
* be fixed as https://localhost:9443/publisher/#/assets/apps/create
*
* */ * */
class Publisher extends Component { class Publisher extends Component {
render() { render() {

@ -16,12 +16,11 @@
* under the License. * under the License.
*/ */
import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import Dialog from 'material-ui/Dialog'; import Dialog from 'material-ui/Dialog';
import {withRouter} from 'react-router-dom'; import {withRouter} from 'react-router-dom';
import {Step1, Step2, Step3} from './Forms';
import FlatButton from 'material-ui/FlatButton'; import FlatButton from 'material-ui/FlatButton';
import {Step1, Step2, Step3} from './CreateSteps';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import {Step, StepLabel, Stepper,} from 'material-ui/Stepper'; import {Step, StepLabel, Stepper,} from 'material-ui/Stepper';
@ -56,6 +55,7 @@ class ApplicationCreate extends Component {
* Handles next button click event. * Handles next button click event.
* */ * */
handleNext = () => { handleNext = () => {
console.log("Handle Next");
const {stepIndex} = this.state; const {stepIndex} = this.state;
this.setState({ this.setState({
stepIndex: stepIndex + 1, stepIndex: stepIndex + 1,
@ -98,7 +98,7 @@ class ApplicationCreate extends Component {
let tmpStepData = this.state.stepData; let tmpStepData = this.state.stepData;
tmpStepData.push({step: step, data: data}); tmpStepData.push({step: step, data: data});
this.setState({stepData: tmpStepData}) this.setState({stepData: tmpStepData}, this.handleNext())
}; };
/** /**
@ -180,7 +180,7 @@ class ApplicationCreate extends Component {
return ( return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}> <div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}>
<Card> <Card style={{maxHeight: '700px', overflow: 'auto'}}>
<CardTitle title="Create Application"/> <CardTitle title="Create Application"/>
{/** {/**

@ -125,8 +125,6 @@ class ApplicationListing extends Component {
return dataItem.applicationName.includes(word); return dataItem.applicationName.includes(word);
}); });
} else { } else {
console.log("no")
console.log(this.data)
searchedData = this.data; searchedData = this.data;
} }
@ -153,7 +151,7 @@ class ApplicationListing extends Component {
} }
_onRowClick(id) { _onRowClick(id) {
console.log(id) this.props.history.push("apps/"+id);
} }
render() { render() {

@ -44,10 +44,16 @@ class Step1 extends Component {
stepIndex: 0, stepIndex: 0,
store: 1, store: 1,
platform: 1, platform: 1,
stepData: [] stepData: [],
title: "",
titleError: ""
}; };
} }
componentWillMount() {
//Get the list of available platforms and set to the state.
}
/** /**
* Invokes the handleNext function in Create component. * Invokes the handleNext function in Create component.
* */ * */
@ -59,8 +65,11 @@ class Step1 extends Component {
* Persist the current form data to the state. * Persist the current form data to the state.
* */ * */
_setStepData() { _setStepData() {
this.props.setData("step1", {step: "Dfds"}); var step = {
this._handleNext.bind(this); store: this.state.store,
platform: this.state.platform
};
this.props.setData("step1", {step: step});
} }
/** /**
@ -71,13 +80,13 @@ class Step1 extends Component {
* */ * */
_handleClick() { _handleClick() {
this._setStepData(); this._setStepData();
this._handleNext();
} }
/** /**
* Triggers when changing the Platform selection. * Triggers when changing the Platform selection.
* */ * */
_onChangePlatform = (event, index, value) => { _onChangePlatform = (event, index, value) => {
console.log(value);
this.setState({platform: value}); this.setState({platform: value});
}; };
@ -88,6 +97,13 @@ class Step1 extends Component {
this.setState({store: value}); this.setState({store: value});
}; };
/**
* Triggers when user types on Title text field.
* */
_onChangeTitle = (event, value) => {
this.setState({title: value});
};
render() { render() {
const contentStyle = {margin: '0 16px'}; const contentStyle = {margin: '0 16px'};
return ( return (
@ -95,11 +111,6 @@ class Step1 extends Component {
<div style={contentStyle}> <div style={contentStyle}>
<div> <div>
<div> <div>
<TextField
hintText="Enter a title for your application."
floatingLabelText="Title*"
floatingLabelFixed={true}
/><br/>
<SelectField <SelectField
floatingLabelText="Store Type*" floatingLabelText="Store Type*"
value={this.state.store} value={this.state.store}
@ -117,7 +128,7 @@ class Step1 extends Component {
> >
<MenuItem value={1} primaryText="Android"/> <MenuItem value={1} primaryText="Android"/>
<MenuItem value={2} primaryText="iOS"/> <MenuItem value={2} primaryText="iOS"/>
<MenuItem value={3} primaryText="Web"/> <MenuItem value={{name: "Web", id:3}} primaryText="Web"/>
</SelectField> </SelectField>
</div> </div>

@ -0,0 +1,489 @@
/*
* 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.
*/
import PropTypes from 'prop-types';
import Chip from 'material-ui/Chip';
import Dropzone from 'react-dropzone';
import React, {Component} from 'react';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton';
import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton';
import Clear from 'material-ui/svg-icons/content/clear';
import {GridList, GridTile} from 'material-ui/GridList';
/**
* The Second step of application create wizard.
* This contains following components.
* * App Title
* * Short Description
* * Application Description
* * Application Visibility
* * Application Tags : {Used Material UI Chip component}
* * Application Category.
* * Platform Specific properties.
* * Screenshots
* * Banner
* * Icon
*
* Parent Component: Create
* Props:
* * handleNext : {type: function, Invokes handleNext function in Parent.}
* * handlePrev : {type: function, Invokes handlePrev function in Parent}
* * setData : {type: function, Invokes setStepData function in Parent}
* * removeData : {type: Invokes removeStepData function in Parent}
* */
class Step2 extends Component {
constructor() {
super();
this.state = {
tags: [],
defValue: "",
category: 0,
visibility: 0,
errors: {},
title: "",
shortDescription: "",
description: "",
banner: [],
screenshots: [],
icon: []
};
this.styles = {
chip: {
margin: 4,
},
wrapper: {
display: 'flex',
flexWrap: 'wrap',
},
};
}
/**
* Create a tag on Enter key press and set it to the state.
* Clears the tags text field.
* Chip gets two parameters: Key and value.
* */
_addTags(event) {
let tags = this.state.tags;
if (event.charCode === 13) {
event.preventDefault();
tags.push({key: Math.floor(Math.random() * 1000), value: event.target.value});
this.setState({tags, defValue: ""});
}
}
/**
* Set the value for tag.
* */
_handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
}
/**
* Invokes the handleNext function in Create component.
* */
_handleNext() {
let fields = [{name: "Title", value: this.state.title},
{name: "Short Description", value: this.state.shortDescription},
{name: "Description", value: this.state.description},
{name: "Banner", value: this.state.banner},
{name: "Screenshots", value: this.state.screenshots},
{name: "Icon", value: this.state.icon}];
this._validate(fields);
// this.props.handleNext();
}
/**
* Invokes the handlePrev function in Create component.
* */
_handlePrev() {
this.props.handlePrev();
}
/**
* Handles Chip delete function.
* Removes the tag from state.tags
* */
_handleRequestDelete = (key) => {
this.chipData = this.state.tags;
const chipToDelete = this.chipData.map((chip) => chip.key).indexOf(key);
this.chipData.splice(chipToDelete, 1);
this.setState({tags: this.chipData});
};
/**
* Creates Chip array from state.tags.
* */
_renderChip(data) {
return (
<Chip
key={data.key}
onRequestDelete={() => this._handleRequestDelete(data.key)}
style={this.styles.chip}
>
{data.value}
</Chip>
);
}
_onVisibilitySelect = (event, index, value) => {
console.log(value);
let comp = <SelectField> <MenuItem value={0} primaryText="Public"/>
<MenuItem value={1} primaryText="Roles"/>
<MenuItem value={2} primaryText="Devices"/> </SelectField>;
if (value === 1) {
this.setState({visibilityComponent: comp});
} else if (value === 2) {
} else {
}
};
/**
* Validate the form.
* */
_validate(fields) {
let errors = {};
let errorsPresent = false;
fields.forEach(function (field) {
switch (field.name) {
case 'Title': {
if (field.value === "") {
errors[field.name] = field.name + " is required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
case 'Short Description': {
if (field.value === "") {
errors[field.name] = field.name + " is required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
case 'Description': {
if (field.value === "") {
errors[field.name] = field.name + " is required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
case 'Banner': {
if (field.value.length === 0) {
errors[field.name] = field.name + " is required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
case 'Icon': {
if (field.value.length === 0) {
errors[field.name] = field.name + " is required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
case 'Screenshots': {
if (field.value.length < 3) {
errors[field.name] = "3 " +field.name + " are required!";
errorsPresent = true;
} else {
errorsPresent = false;
}
break;
}
}
});
console.log(errorsPresent);
if (!errorsPresent) {
this._setStepData();
} else {
this.setState({errors: errors}, console.log(errors));
}
}
/**
* Creates an object with the current step data and persist in the parent.
* */
_setStepData() {
let stepData = {
title: this.state.title,
description: this.state.description,
shortDescription: this.state.shortDescription,
tags: this.state.tags,
banner: this.state.banner,
screenshots: this.state.screenshots,
icon: this.state.icon
};
this.props.setData("step2", {step: stepData});
}
/**
* Set text field values to state.
* */
_onTextFieldChange(event, value) {
let field = event.target.id;
switch (field) {
case "title": {
this.setState({title: value});
break;
}
case "shortDescription": {
this.setState({shortDescription: value});
break;
}
case "description": {
this.setState({description: value});
break;
}
}
}
/**
* Removed user uploaded banner.
* */
_removeBanner(event, d) {
console.log(event, d);
this.setState({banner: []});
}
/**
* Removes uploaded icon.
* */
_removeIcon(event) {
this.setState({icon: []});
}
/**
* Removes selected screenshot.
* */
_removeScreenshot(event) {
console.log(event.target)
}
render() {
console.log(this.state.visibilityComponent);
const contentStyle = {margin: '0 16px'};
return (
<div style={contentStyle}>
<div>
<div>
<TextField
id="title"
hintText="Enter a title for your application."
errorText={this.state.errors["Title"]}
floatingLabelText="Title*"
floatingLabelFixed={true}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
<TextField
id="shortDescription"
hintText="Enter a short description for your application."
errorText={this.state.errors["Short Description"]}
floatingLabelText="Short Description*"
floatingLabelFixed={true}
multiLine={true}
rows={2}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
<TextField
id="description"
errorText={this.state.errors["Description"]}
hintText="Enter the description."
floatingLabelText="Description*"
floatingLabelFixed={true}
multiLine={true}
rows={4}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
<SelectField
floatingLabelText="Visibility*"
value={this.state.visibility}
floatingLabelFixed={true}
onChange={this._onVisibilitySelect.bind(this)}
>
<MenuItem value={0} primaryText="Public"/>
<MenuItem value={1} primaryText="Roles"/>
<MenuItem value={2} primaryText="Devices"/>
</SelectField><br/>
<TextField
id="tags"
errorText={this.state.errors["tags"]}
hintText="Enter application tags.."
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={this.state.defValue}
onChange={this._handleTagChange.bind(this)}
onKeyPress={this._addTags.bind(this)}
/><br/>
<div style={this.styles.wrapper}>
{this.state.tags.map(this._renderChip, this)}
</div>
<br/>
<SelectField
floatingLabelText="Category*"
value={this.state.category}
floatingLabelFixed={true}
>
<MenuItem value={0} primaryText="Business"/>
</SelectField> <br/>
{/*Platform Specific Properties.*/}
<div style={{border: 'solid #BDBDBD 1px'}}>
<p style={{color: '#BDBDBD'}}>Platform Specific Properties</p>
</div>
<br/>
<div>
<p style={{color: '#f44336'}}>{this.state.errors["Banner"]}</p>
<p style={{color: '#BDBDBD'}}>Banner*:</p>
<GridList style={{
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.banner.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name}
actionIcon={
<IconButton onClick={this._removeBanner.bind(this)}>
<Clear />
</IconButton>}>
<img src={tile.preview}/></GridTile>
))}
{this.state.banner.length === 0 ?
<Dropzone style={{width: '300px', height: '150px', border: 'dashed #BDBDBD 1px'}}
accept="image/jpeg, image/png"
onDrop={(banner, rejected) => {
this.setState({banner, rejected});
}}>
<p style={{margin: '70px 40px 40px 150px'}}>+</p>
</Dropzone> : <div />}
</GridList>
</div>
<br/>
<div>
<p style={{color: '#f44336'}}>{this.state.errors["Screenshots"]}</p>
<p style={{color: '#BDBDBD'}}>Screenshots*:</p>
<GridList style={{
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.screenshots.map((file) => (
<GridTile key={Math.floor(Math.random() * 1000)}
title={file[0].name}
actionIcon={
<IconButton onClick={this._removeScreenshot.bind(this)}>
<Clear/>
</IconButton>}>
<img src={file[0].preview}/></GridTile>
))}
{this.state.screenshots.length < 3 ?
<Dropzone style={{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}}
accept="image/jpeg, image/png"
onDrop={(screenshots, rejected) => {
let tmpScreenshots = this.state.screenshots;
tmpScreenshots.push(screenshots);
this.setState({
screenshots: tmpScreenshots});
}}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p>
</Dropzone> : <div />}
</GridList>
</div>
<br/>
<div>
<p style={{color: '#f44336'}}>{this.state.errors["Icon"]}</p>
<p style={{color: '#BDBDBD'}}>Icon*:</p>
<GridList style={{
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.icon.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name}
actionIcon={
<IconButton onClick={this._removeIcon.bind(this)}>
<Clear />
</IconButton>}>
<img src={tile.preview}/></GridTile>
))}
{this.state.icon.length === 0 ?
<Dropzone style={{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}}
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected});}}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p>
</Dropzone> : <div />}
</GridList>
</div>
<br/>
</div>
<br/>
<br/>
<div style={{marginTop: 12}}>
<FlatButton
label="< Back"
disabled={false}
onClick={this._handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton
label="Next >"
primary={true}
onClick={this._handleNext.bind(this)}
/>
</div>
</div>
</div>
);
}
}
Step2.prototypes = {
handleNext: PropTypes.func,
handlePrev: PropTypes.func,
setData: PropTypes.func,
removeData: PropTypes.func
};
export default Step2;

@ -1,240 +0,0 @@
/*
* 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.
*/
import PropTypes from 'prop-types';
import Chip from 'material-ui/Chip';
import Dropzone from 'react-dropzone';
import React, {Component} from 'react';
import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton';
/**
* The Second step of application create wizard.
* This contains following components.
* * App Title
* * Short Description
* * Application Description
* * Application Visibility
* * Application Tags : {Used Material UI Chip component}
* * Application Category.
* * Platform Specific properties.
* * Screenshots
* * Banner
* * Icon
*
* Parent Component: Create
* Props:
* * handleNext : {type: function, Invokes handleNext function in Parent.}
* * handlePrev : {type: function, Invokes handlePrev function in Parent}
* * setData : {type: function, Invokes setStepData function in Parent}
* * removeData : {type: Invokes removeStepData function in Parent}
* */
class Step2 extends Component {
constructor() {
super();
this.state = {
tags: [],
defValue: "",
category: 1,
errors: {}
};
this.styles = {
chip: {
margin: 4,
},
wrapper: {
display: 'flex',
flexWrap: 'wrap',
},
};
}
/**
* Create a tag on Enter key press and set it to the state.
* Clears the tags text field.
* Chip gets two parameters: Key and value.
* */
_addTags(event) {
let tags = this.state.tags;
if (event.charCode === 13) {
event.preventDefault();
tags.push({key: Math.floor(Math.random() * 1000), value: event.target.value});
this.setState({tags, defValue: ""});
}
}
/**
* Set the value for tag.
* */
_handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
}
/**
* Invokes the handleNext function in Create component.
* */
_handleNext() {
this.props.handleNext();
}
/**
* Invokes the handlePrev function in Create component.
* */
_handlePrev() {
this.props.handlePrev();
}
/**
* Handles Chip delete function.
* Removes the tag from state.tags
* */
_handleRequestDelete = (key) => {
this.chipData = this.state.tags;
const chipToDelete = this.chipData.map((chip) => chip.key).indexOf(key);
this.chipData.splice(chipToDelete, 1);
this.setState({tags: this.chipData});
};
/**
* Creates Chip array from state.tags.
* */
_renderChip(data) {
return (
<Chip
key={data.key}
onRequestDelete={() => this._handleRequestDelete(data.key)}
style={this.styles.chip}
>
{data.value}
</Chip>
);
}
render() {
const contentStyle = {margin: '0 16px'};
return (
<div style={contentStyle}>
<div>
<div>
<TextField
hintText="Enter a title for your application."
errorText={this.state.errors["title"]}
floatingLabelText="Title*"
floatingLabelFixed={true}
/><br/>
<TextField
hintText="Enter a short description for your application."
errorText={this.state.errors["shortDesc"]}
floatingLabelText="Short Description*"
floatingLabelFixed={true}
multiLine={true}
rows={2}
/><br/>
<TextField
errorText={this.state.errors["description"]}
hintText="Enter the description."
floatingLabelText="Description*"
floatingLabelFixed={true}
multiLine={true}
rows={4}
/><br/>
<TextField
hintText="Select the application visibility"
floatingLabelText="Visibility"
floatingLabelFixed={true}
/><br/>
<TextField
errorText={this.state.errors["tags"]}
hintText="Enter application tags.."
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={this.state.defValue}
onChange={this._handleTagChange.bind(this)}
onKeyPress={this._addTags.bind(this)}
/><br/>
<div style={this.styles.wrapper}>
{this.state.tags.map(this._renderChip, this)}
</div>
<br/>
<SelectField
floatingLabelText="Category*"
value={this.state.category}
floatingLabelFixed={true}
>
<MenuItem value={1} primaryText="Business"/>
</SelectField> <br/>
{/*Platform Specific Properties.*/}
<div style={{border: 'solid #BDBDBD 1px'}}>
<p style={{color:'#BDBDBD'}}>Platform Specific Properties</p>
</div><br/>
<div>
<p style={{color:'#BDBDBD'}}>Screenshots*:</p>
<Dropzone style={{width:'100px', height:'100px', border: 'dashed #BDBDBD 1px'}}>
<p style={{margin: '40px 40px 40px 50px'}}>+</p>
</Dropzone>
</div><br/>
<div>
<p style={{color:'#BDBDBD'}}>Banner*:</p>
<Dropzone style={{width:'100px', height:'100px', border: 'dashed #BDBDBD 1px'}}>
<p style={{margin: '40px 40px 40px 50px'}}>+</p>
</Dropzone>
</div><br/>
<div>
<p style={{color:'#BDBDBD'}}>Icon*:</p>
<Dropzone style={{width:'100px', height:'100px', border: 'dashed #BDBDBD 1px'}}>
<p style={{margin: '40px 40px 40px 50px'}}>+</p>
</Dropzone>
</div><br/>
</div>
<br />
<br />
<div style={{marginTop: 12}}>
<FlatButton
label="< Back"
disabled={false}
onClick={this._handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton
label="Next >"
primary={true}
onClick={this._handleNext.bind(this)}
/>
</div>
</div>
</div>
);
}
}
Step2.prototypes = {
handleNext: PropTypes.func,
handlePrev: PropTypes.func,
setData: PropTypes.func,
removeData: PropTypes.func
};
export default Step2;

@ -26,6 +26,8 @@ import FlatButton from 'material-ui/FlatButton';
import IconButton from 'material-ui/IconButton'; import IconButton from 'material-ui/IconButton';
import SelectField from 'material-ui/SelectField'; import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import Clear from 'material-ui/svg-icons/content/clear';
import {GridList, GridTile} from 'material-ui/GridList';
import Close from 'material-ui/svg-icons/navigation/close'; import Close from 'material-ui/svg-icons/navigation/close';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import AddCircleOutline from 'material-ui/svg-icons/content/add-circle-outline'; import AddCircleOutline from 'material-ui/svg-icons/content/add-circle-outline';
@ -53,6 +55,7 @@ class PlatformCreate extends Component {
name: "", name: "",
description: "", description: "",
property: "", property: "",
icon: [],
propertyTypes: [ propertyTypes: [
{key: 0, value: 'String'}, {key: 0, value: 'String'},
{key: 1, value: 'Number'}, {key: 1, value: 'Number'},
@ -148,6 +151,16 @@ class PlatformCreate extends Component {
} }
/**
* Remove the uploaded icon.
* */
_removeIcon(event) {
this.setState({icon: []});
}
/**
* Clears the user entered values in the form.
* */
_clearForm() { _clearForm() {
this.setState({enabled: true, this.setState({enabled: true,
allTenants: false, allTenants: false,
@ -249,10 +262,32 @@ class PlatformCreate extends Component {
</div> </div>
</div> </div>
<div> <div>
{/*<p style={{color: '#f44336'}}>{this.state.errors["Icon"]}</p>*/}
<p style={{color: '#BDBDBD'}}>Platform Icon*:</p> <p style={{color: '#BDBDBD'}}>Platform Icon*:</p>
<Dropzone style={{width: '100px', height: '100px', border: 'dashed #BDBDBD 1px'}}> <GridList style={{
<p style={{margin: '40px 40px 40px 50px', color: '#BDBDBD'}}>+</p> display: 'flex',
</Dropzone> flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.icon.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name}
actionIcon={
<IconButton onClick={this._removeIcon.bind(this)}>
<Clear />
</IconButton>}>
<img src={tile.preview}/>
</GridTile>
))}
{this.state.icon.length === 0 ?
<Dropzone style={
{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}
}
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected})}}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p>
</Dropzone> : <div />}
</GridList>
</div> </div>
<br/> <br/>
<RaisedButton primary={true} label="Create" <RaisedButton primary={true} label="Create"
@ -268,11 +303,6 @@ class PlatformCreate extends Component {
} }
PlatformCreate.prototypes = { PlatformCreate.prototypes = {
enabled: PropTypes.bool,
allTenants: PropTypes.bool,
files: PropTypes.array,
platformProperties: PropTypes.object,
handleToggle: PropTypes.func
}; };
export default PlatformCreate; export default PlatformCreate;

Loading…
Cancel
Save