Api integration: Application Create steps.

merge-requests/7/head
Menaka Jayawardena 7 years ago
parent 4cdb1fc4c9
commit 7fa3c886fb

@ -10,18 +10,18 @@
"license": "Apache License 2.0", "license": "Apache License 2.0",
"dependencies": { "dependencies": {
"axios": "^0.16.2", "axios": "^0.16.2",
"bootstrap": "^4.0.0-alpha.6", "bootstrap": "^4.0.0-beta",
"flux": "^3.1.3", "flux": "^3.1.3",
"history": "^4.7.2", "history": "^4.7.2",
"latest-version": "^3.1.0", "latest-version": "^3.1.0",
"material-ui": "^0.19.1", "material-ui": "^0.19.3",
"prop-types": "^15.5.10", "prop-types": "^15.6.0",
"qs": "^6.5.0", "qs": "^6.5.1",
"react": "^15.6.1", "react": "^15.6.2",
"react-addons-css-transition-group": "^15.6.0", "react-addons-css-transition-group": "^15.6.2",
"react-addons-transition-group": "^15.6.0", "react-addons-transition-group": "^15.6.2",
"react-dom": "^15.6.1", "react-dom": "^15.6.2",
"react-dropzone": "^4.1.2", "react-dropzone": "^4.1.3",
"react-images-uploader": "^1.1.0", "react-images-uploader": "^1.1.0",
"react-material-ui-form-validator": "^0.5.1", "react-material-ui-form-validator": "^0.5.1",
"react-modal": "^2.3.2", "react-modal": "^2.3.2",
@ -43,8 +43,8 @@
"css-loader": "^0.28.7", "css-loader": "^0.28.7",
"less": "^2.7.2", "less": "^2.7.2",
"less-loader": "^4.0.4", "less-loader": "^4.0.4",
"mocha": "^3.4.1", "mocha": "^3.5.3",
"mock-local-storage": "^1.0.2", "mock-local-storage": "^1.0.5",
"node-sass": "^4.5.3", "node-sass": "^4.5.3",
"react-intl": "^2.4.0", "react-intl": "^2.4.0",
"sass-loader": "^6.0.6", "sass-loader": "^6.0.6",

@ -39,13 +39,16 @@ body {
} }
#login-container { #login-container {
width: 50%;
margin: 0 auto
} }
#login-card { #login-card {
width: 20%;
height: 50%;
margin: 10% auto;
padding: 10px;
border-radius: 0; border-radius: 0;
background-color: #BaBaBa; background-color: #ffffff;
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
} }
/* Base layout container */ /* Base layout container */
@ -130,7 +133,7 @@ body {
float: right; float: right;
top: 75px; top: 75px;
left: 150px; left: 150px;
margin-right: 16px; margin-right: 40px;
} }
#search { #search {
@ -148,14 +151,13 @@ body {
/* Application Add button */ /* Application Add button */
#add-btn-container { #add-btn-container {
position: absolute; position: absolute;
left: 12%; left: 11%;
top: 100px; top: 100px;
} }
#app-main-content { #app-main-content {
height: 100%; margin-top: 140px;
position: inherit; max-width: 98%;
top: 125px;
} }
/* Holds the app publisher pages. */ /* Holds the app publisher pages. */
@ -163,8 +165,8 @@ body {
height: auto; height: auto;
width: 80%; width: 80%;
margin: 20px auto; margin: 20px auto;
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19); box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
padding: 10px 10px 10px 10px; padding: 0 10px 10px 10px;
} }
.stepper-header { .stepper-header {
@ -183,10 +185,17 @@ body {
} }
#application-list { #application-list {
margin-top: 20px;
transition: margin-right .5s; transition: margin-right .5s;
} }
.app-list-table-header {
height: 100px;
}
#app-visibility-default {
display: none;
}
#app-image-screenshot { #app-image-screenshot {
width: 300px; width: 300px;
height: 300px; height: 300px;
@ -207,7 +216,6 @@ body {
height: 150px; height: 150px;
border-radius: 5%; border-radius: 5%;
position: relative; position: relative;
background-color: rgba(157, 159, 157, 0.53);
border: dashed #888888 2px; border: dashed #888888 2px;
} }
@ -223,7 +231,6 @@ body {
margin: 0 5px 0 5px; margin: 0 5px 0 5px;
border-radius: 10%; border-radius: 10%;
position: relative; position: relative;
background-color: rgba(157, 159, 157, 0.53);
border: dashed #888888 2px; border: dashed #888888 2px;
} }
@ -238,7 +245,6 @@ body {
height: 150px; height: 150px;
border-radius: 10%; border-radius: 10%;
position: relative; position: relative;
background-color: rgba(157, 159, 157, 0.53);
border: dashed #888888 2px; border: dashed #888888 2px;
} }
@ -249,6 +255,7 @@ body {
} }
#screenshot-container { #screenshot-container {
max-width: 600px;
display: flex; display: flex;
overflow-x: auto; overflow-x: auto;
height: 200px; height: 200px;
@ -266,12 +273,13 @@ body {
#secondary-button { #secondary-button {
float: right; float: right;
color: #979797;
background-color: transparent; background-color: transparent;
border: none; border: none;
} }
#secondary-button:hover { #secondary-button:hover {
background-color: #e9e9e9; background-color: #d8d8d8;
outline: none; outline: none;
cursor: pointer; cursor: pointer;
} }
@ -327,12 +335,12 @@ body {
} }
/* Application View */ /* Application View */
#application-view-content { #application-view-content {
width: 100%; width: 100%;
} }
#application-view-row { #application-view-row {
margin: 10px 10px 20px 20px; margin: 10px 10px 0 20px;
} }
#app-icon { #app-icon {
@ -366,14 +374,14 @@ body {
} }
/* Application Edit Base Layout */ /* Application Edit Base Layout */
#application-edit-header { #application-edit-header {
height: 50px; height: 40px;
width: 100%; width: 100%;
margin: 0; margin-top: 20px;
font-size: 20px; margin-bottom: 20px;
border-bottom: solid 1px #d8d8d8; font-size: 25px;
} }
.application-header-text { .application-header-text {
margin: 10px 0px 0px 10px; margin: 10px 0px 0px 10px;
} }
@ -399,13 +407,14 @@ body {
} }
/*Tab styling*/ /*Tab styling*/
div.tab { div.tab {
float: left; float: left;
border-right: 1px solid #d8d8d8; border-right: 1px solid #d8d8d8;
height: 100%; height: 100%;
} }
/* Style the tab buttons */ /* Style the tab buttons */
div.tab button { div.tab button {
display: block; display: block;
background-color: inherit; background-color: inherit;
@ -418,24 +427,23 @@ div.tab button {
cursor: pointer; cursor: pointer;
transition: 0.3s; transition: 0.3s;
} }
/* Change background color of buttons on hover */ /* Change background color of buttons on hover */
div.tab button:hover { div.tab button:hover {
background-color: #ddd6d7; background-color: #ddd6d7;
cursor: pointer; cursor: pointer;
} }
/* Create an active/current "tab button" class */ /* Create an active/current "tab button" class */
div.tab button.active { div.tab button.active {
background-color: #1b3bcc; background-color: #1b3bcc;
color: white; color: white;
} }
#application-edit-main-container { #application-edit-main-container {
display: flex; display: flex;
} }
#application-edit-outer-content { #application-edit-outer-content {
height: auto; height: auto;
width: 100%; width: 100%;
@ -453,13 +461,13 @@ div.tab button.active {
.back-to-app { .back-to-app {
position: absolute; position: absolute;
height: 40px; height: 50px;
width: 40px; width: 50px;
border-radius: 50%; border-radius: 50%;
} }
.back-to-app i { .back-to-app i {
padding: 10px 10px 10px 10px; padding: 12px 10px 10px 12px;
} }
.back-to-app:hover { .back-to-app:hover {
@ -469,11 +477,11 @@ div.tab button.active {
} }
/* Create Release and Release management */ /* Create Release and Release management */
.release-header { .release-header {
margin-top: 20px; margin-top: 20px;
margin-bottom: 20px; margin-bottom: 20px;
} }
.release-create { .release-create {
height: 150px; height: 150px;
margin-bottom: 20px; margin-bottom: 20px;
@ -523,12 +531,39 @@ div.tab button.active {
} }
/* Application Edit General Info */ /* Application Edit General Info */
.app-edit-general-info { .app-edit-general-info {
margin-top: 20px; margin-top: 20px;
max-width: 100%; max-width: 100%;
} }
.save-info { .save-info {
float: right; float: right;
margin-bottom: 10px; margin-bottom: 10px;
} }
/* Platform Specific Styles. */
#platform-listing {
margin: 10px;
}
.create-platform {
padding-left: 90%;
}
#platform-list {
margin-top: 20px;
display: flex;
flex-flow: wrap;
}
#platform-content {
width: 200px;
height: 300px;
margin: 10px;
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
}
#platform-content:hover {
background-color: #f2f2f2;
cursor: pointer;
}

@ -76,7 +76,7 @@ class BaseLayout extends Component {
render() { render() {
return ( return (
<Container fluid id="container"> <div>
<div id="header-content"> <div id="header-content">
<div id="header"> <div id="header">
<span id="header-text"> <span id="header-text">
@ -104,24 +104,27 @@ class BaseLayout extends Component {
/> />
</div> </div>
</div> </div>
<div id="app-main-content" style={this.state.style}> <Container fluid>
<Row> <div id="app-main-content" style={this.state.style}>
<div className="platform-link-placeholder"> <Row>
<Button id="secondary-button" onClick={this.onClickPlatforms}><i className="fw fw-settings"></i> Platforms</Button> <div className="platform-link-placeholder">
</div> <Button id="secondary-button" onClick={this.onClickPlatforms}>
</Row> <i className="fw fw-settings"></i> Platforms</Button>
<Row> </div>
<div id="application-content"> </Row>
<Row> <Row>
<Col> <div id="application-content">
{this.props.children} <Row>
</Col> <Col>
</Row> {this.props.children}
</div> </Col>
</Row> </Row>
</div> </div>
</Row>
</div>
</Container>
<ApplicationCreate open={this.state.openModal} close={this.closeModal}/> <ApplicationCreate open={this.state.openModal} close={this.closeModal}/>
</Container> </div>
); );
} }
} }

@ -22,6 +22,8 @@ import {Button, Col, Row, Table} from 'reactstrap';
import Drawer from '../UIComponents/Drawer/Drawer'; import Drawer from '../UIComponents/Drawer/Drawer';
import ApplicationView from './View/ApplicationView'; import ApplicationView from './View/ApplicationView';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import ApplicationMgtApi from "../../api/applicationMgtApi";
import AuthHandler from "../../api/authHandler";
/** /**
* The App Create Component. * The App Create Component.
@ -36,10 +38,10 @@ class ApplicationListing extends Component {
super(); super();
this.searchApplications = this.searchApplications.bind(this); this.searchApplications = this.searchApplications.bind(this);
this.onRowClick = this.onRowClick.bind(this); this.onRowClick = this.onRowClick.bind(this);
this.setData = this.setData.bind(this);
this.sortData = this.sortData.bind(this); this.sortData = this.sortData.bind(this);
this.compare = this.compare.bind(this); this.compare = this.compare.bind(this);
this.handleButtonClick = this.handleButtonClick.bind(this); this.onAppEditClick = this.onAppEditClick.bind(this);
this.getSelectedApplication = this.getSelectedApplication.bind(this);
this.state = { this.state = {
searchedApplications: [], searchedApplications: [],
applications: [], applications: [],
@ -57,7 +59,6 @@ class ApplicationListing extends Component {
}; };
} }
applications = [ applications = [
{ {
id: "3242342ffww3423", id: "3242342ffww3423",
@ -84,35 +85,57 @@ class ApplicationListing extends Component {
}, },
]; ];
componentWillMount() { headers = [
{
data_id: "image",
data_type: "image",
sortable: false,
label: ""
},
{
data_id: "applicationName",
data_type: "string",
sortable: true,
label: "Application Name",
sort: this.sortData
},
{
data_id: "platform",
data_type: "image_array",
sortable: false,
label: "Platform"
},
{
data_id: "category",
data_type: "string",
sortable: false,
label: "Category"
},
{
data_id: "status",
data_type: "string",
sortable: false,
label: "Status"
},
{
data_id: "edit",
data_type: "button",
sortable: false,
label: ""
}
];
// let getApps = ApplicationMgtApi.getApplications();
// getApps.then(response => {
// let apps = this.setData(response.data.applications);
// console.log(apps); //TODO: Remove this.
// this.setState({searchedApplications: apps});
// // console.log(this.setState({data: response.data}), console.log(this.state));
// }).catch(err => {
// AuthHandler.unauthorizedErrorHandler(err);
// });
}
/** componentWillMount() {
* Extract application from application list and update the state.
* */
setData(applications) {
let apps = [];
for (let app in applications) {
let application = {};
application.id = applications[app].uuid;
application.applicationName = applications[app].name;
application.platform = applications[app].platform.name;
application.category = applications[app].category.id;
application.status = applications[app].currentLifecycle.lifecycleState.name;
apps.push(application);
}
this.setState({searchedApplications: apps}); let getApps = ApplicationMgtApi.getApplications();
getApps.then(response => {
console.log(response.data.applications);
this.setState({searchedApplications: response.data.applications});
// console.log(this.setState({data: response.data}), console.log(this.state));
}).catch(err => {
AuthHandler.unauthorizedErrorHandler(err);
});
} }
/** /**
@ -154,34 +177,22 @@ class ApplicationListing extends Component {
return 0; return 0;
} }
onRowClick() { onRowClick(uuid) {
let selectedApp = this.getSelectedApplication(uuid);
let style = { let style = {
width: '500px', width: '550px',
marginLeft: '500px' marginLeft: '550px'
}; };
let appListStyle = { let appListStyle = {
marginRight: '500px', marginRight: '550px',
}; };
this.setState({drawer: style, appListStyle: appListStyle}); this.setState({drawer: style, appListStyle: appListStyle, application: selectedApp[0]});
}
handleButtonClick() {
console.log("Application Listing");
this.props.history.push("apps/edit/fdsfdsf343");
} }
remove(imageId) { onAppEditClick(uuid) {
let tmp = this.state.image; this.props.history.push("apps/edit/" + uuid);
console.log(imageId);
let rem = tmp.filter((image) => {
return image.id !== imageId
});
this.setState({image: rem});
} }
closeDrawer() { closeDrawer() {
@ -196,6 +207,12 @@ class ApplicationListing extends Component {
this.setState({drawer: style, appListStyle: appListStyle}); this.setState({drawer: style, appListStyle: appListStyle});
} }
getSelectedApplication(uuid) {
return this.state.searchedApplications.filter(application => {
return application.uuid === uuid;
});
}
render() { render() {
return ( return (
@ -213,7 +230,7 @@ class ApplicationListing extends Component {
<Col> <Col>
<Table striped hover> <Table striped hover>
<thead> <thead>
<tr> <tr className="app-list-table-header">
<th></th> <th></th>
{/* TODO: Remove console.log and add sort method. */} {/* TODO: Remove console.log and add sort method. */}
<th onClick={() => { <th onClick={() => {
@ -228,25 +245,24 @@ class ApplicationListing extends Component {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{this.applications.map( {this.state.searchedApplications.map(
(application) => { (application) => {
return ( return (
<tr key={application.id} onClick={this.onRowClick}> <tr key={application.uuid} onClick={() => this.onRowClick(application.uuid)}>
<td> <td data={application.uuid}>
{/* TODO: Move this styles to css. */} {/* TODO: Move this styles to css. */}
<img <img
src={application.icon}
height='50px' height='50px'
width='50px' width='50px'
style={{border: 'solid 1px black', borderRadius: "100%"}} style={{border: 'solid 1px black', borderRadius: "100%"}}
/> />
</td> </td>
<td>{application.applicationName}</td> <td>{application.name}</td>
<td>{application.category}</td> <td>{application.category.name}</td>
<td>{application.platform}</td> <td>{application.platform.name}</td>
<td>{application.status}</td> <td>{application.currentLifecycle.lifecycleState.name}</td>
<td> <td>
<Button id="secondary-button" onClick={this.handleButtonClick}> <Button id="secondary-button" onClick={() => this.onAppEditClick(application.uuid)}>
<i className="fw fw-edit"></i> <i className="fw fw-edit"></i>
</Button> </Button>
</td> </td>
@ -259,7 +275,7 @@ class ApplicationListing extends Component {
</Col> </Col>
</Row> </Row>
<Drawer onClose={this.closeDrawer.bind(this)} style={this.state.drawer}> <Drawer onClose={this.closeDrawer.bind(this)} style={this.state.drawer}>
<ApplicationView/> <ApplicationView application={this.state.application}/>
</Drawer> </Drawer>
</div> </div>
); );

@ -21,7 +21,7 @@ import {withRouter} from 'react-router-dom';
import AuthHandler from "../../../api/authHandler"; import AuthHandler from "../../../api/authHandler";
import {Step1, Step2, Step3, Step4} from './CreateSteps/index'; import {Step1, Step2, Step3, Step4} from './CreateSteps/index';
import ApplicationMgtApi from '../../../api/applicationMgtApi'; import ApplicationMgtApi from '../../../api/applicationMgtApi';
import {Button, Col, Modal, ModalBody, ModalFooter, ModalHeader, Row} from 'reactstrap'; import {Col, Modal, ModalBody, ModalHeader, Row} from 'reactstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
/** /**
@ -49,7 +49,11 @@ class ApplicationCreate extends Component {
finished: false, finished: false,
stepIndex: 0, stepIndex: 0,
stepData: [], stepData: [],
isDialogOpen: false isDialogOpen: false,
generalInfo: {},
platform: {},
screenshots: {},
release: {}
}; };
} }
@ -61,10 +65,11 @@ class ApplicationCreate extends Component {
this.setState({open: this.props.open}); this.setState({open: this.props.open});
} }
/**
* Resets the form and closes the modal.
* */
onClose() { onClose() {
this.setState({stepIndex: 0}, this.props.close()); this.setState({stepIndex: 0, generalInfo: {}, platform: {}, screenshots: {}, release: {}}, this.props.close());
} }
/** /**
@ -111,7 +116,6 @@ class ApplicationCreate extends Component {
console.log(this.state.stepIndex); console.log(this.state.stepIndex);
const {stepIndex} = this.state; const {stepIndex} = this.state;
if (stepIndex > 0) { if (stepIndex > 0) {
this.removeStepData();
this.setState({stepIndex: stepIndex - 1, finished: false}); this.setState({stepIndex: stepIndex - 1, finished: false});
} }
}; };
@ -123,10 +127,24 @@ class ApplicationCreate extends Component {
* */ * */
setStepData(step, data) { setStepData(step, data) {
console.log(step, data, this.state.stepData); //TODO: Remove this console.log(step, data, this.state.stepData); //TODO: Remove this
let tmpStepData = this.state.stepData; switch (step) {
tmpStepData.push({step: step, data: data}); case "generalInfo": {
this.setState({generalInfo: data}, this.onNextClick());
this.setState({stepData: tmpStepData}, this.onNextClick()) break;
}
case "platform": {
this.setState({platform: data}, this.onNextClick());
break;
}
case "screenshots": {
this.setState({screenshots: data}, this.onNextClick());
break;
}
case "release": {
this.setState({release: data}, this.onNextClick());
break;
}
}
}; };
/** /**
@ -135,9 +153,10 @@ class ApplicationCreate extends Component {
removeStepData() { removeStepData() {
let tempData = this.state.stepData; let tempData = this.state.stepData;
tempData.pop(); tempData.pop();
this.setState({stepData: tempData}); this.setState({stepData: tempData, stepIndex: 0});
}; };
/* ----------------- Deprecated ----------------- */
/** /**
* Handles the Yes button in app creation cancellation dialog. * Handles the Yes button in app creation cancellation dialog.
* Clears all the form data and reset the wizard. * Clears all the form data and reset the wizard.
@ -154,6 +173,8 @@ class ApplicationCreate extends Component {
this.setState({isDialogOpen: false}); this.setState({isDialogOpen: false});
}; };
/* ---------------------------------------------- */
/** /**
* Defines all the Steps in the stepper. (Wizard) * Defines all the Steps in the stepper. (Wizard)
* *
@ -168,35 +189,36 @@ class ApplicationCreate extends Component {
case 0: case 0:
return ( return (
<Step1 <Step1
handleNext={this.onNextClick} defaultData={this.state.generalInfo}
setData={this.setStepData} setStepData={this.setStepData}
removeData={this.removeStepData} close={this.onClose}
/> />
); );
case 1: case 1:
return ( return (
<Step2 <Step2
handleNext={this.onNextClick} defaultData={this.state.platform}
handlePrev={this.onPrevClick} handlePrev={this.onPrevClick}
setData={this.setStepData} setStepData={this.setStepData}
removeData={this.removeStepData} close={this.onClose}
/> />
); );
case 2: case 2:
return ( return (
<Step3 <Step3
handleFinish={this.onNextClick} defaultData={this.state.screenshots}
handlePrev={this.onPrevClick} handlePrev={this.onPrevClick}
setData={this.setStepData} setStepData={this.setStepData}
removeData={this.removeStepData} close={this.onClose}
/> />
); );
case 3: { case 3: {
return ( return (
<Step4 <Step4
handleNext={this.onNextClick} defaultData={this.state.release}
setData={this.setStepData} handlePrev={this.onPrevClick}
removeData={this.removeStepData} setStepData={this.setStepData}
close={this.onClose}
/> />
) )
} }
@ -252,22 +274,6 @@ class ApplicationCreate extends Component {
</Col> </Col>
</Row> </Row>
</ModalBody> </ModalBody>
<ModalFooter>
{stepIndex === 0 ? <div/> :
<Button color="primary" onClick={this.onPrevClick}>
<FormattedMessage id="Back" defaultMessage="Back"/>
</Button>}
<Button color="secondary" onClick={this.onClose}>
<FormattedMessage id="Cancel" defaultMessage="Cancel"/>
</Button>
{finished ?
<Button color="primary" onClick={this.onSubmit}>
<FormattedMessage id="Finish" defaultMessage="Finish" />
</Button> :
<Button color="primary" onClick={this.onNextClick}>
<FormattedMessage id="Continue" defaultMessage="Continue"/>
</Button>}
</ModalFooter>
</Modal> </Modal>
</div>); </div>);
} }

@ -20,6 +20,7 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Badge, FormGroup, Input, Label} from 'reactstrap'; import {Badge, FormGroup, Input, Label} from 'reactstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
import {Badge, Button, Form, FormGroup, Input, Label, ModalFooter} from 'reactstrap';
/** /**
* The Second step of application create wizard. * The Second step of application create wizard.
@ -42,22 +43,32 @@ import {FormattedMessage} from 'react-intl';
class Step1 extends Component { class Step1 extends Component {
constructor() { constructor() {
super(); super();
this.onTextFieldChange = this.onTextFieldChange.bind(this);
this.setStepData = this.setStepData.bind(this);
this.onCancelClick = this.onCancelClick.bind(this);
this.onVisibilityChange = this.onVisibilityChange.bind(this);
this.onVisibilityItemSelect = this.onVisibilityItemSelect.bind(this);
this.handleRequestDelete = this.handleRequestDelete.bind(this);
this.state = { this.state = {
tags: [], tags: [],
icon: [], name: "",
title: "",
errors: {}, errors: {},
banner: [],
defValue: "", defValue: "",
category: 0, category: 0,
visibility: 0, visibility: "",
description: "", description: ""
screenshots: [],
identifier: "",
shortDescription: ""
}; };
} }
componentWillMount() {
const defaultVals = this.props.defaultData;
if(defaultVals) {
this.setState(defaultVals);
}
}
/** /**
* Create a tag on Enter key press and set it to the state. * Create a tag on Enter key press and set it to the state.
* Clears the tags text field. * Clears the tags text field.
@ -85,48 +96,101 @@ class Step1 extends Component {
* Handles Chip delete function. * Handles Chip delete function.
* Removes the tag from state.tags * Removes the tag from state.tags
* */ * */
handleRequestDelete(event) { handleRequestDelete(key) {
this.chipData = this.state.tags; let chipData = this.state.tags;
console.log(event.target); const chipToDelete = chipData.map((chip) => chip.key).indexOf(key);
const chipToDelete = this.chipData.map((chip) => chip.value).indexOf(event.target.value); chipData.splice(chipToDelete, 1);
this.chipData.splice(chipToDelete, 1); this.setState({tags: chipData});
this.setState({tags: this.chipData});
}; };
/** /**
* Creates an object with the current step data and persist in the parent. * Creates an object with the current step data and persist in the parent.
* */ * */
setStepData() { setStepData() {
let stepData = {}; const {name, description, tags, visibility} = this.state;
this.props.setData("step1", {step: stepData}); let stepData = {
name: name,
description: description,
tags: tags,
visibility: visibility
};
this.props.setStepData("generalInfo", stepData);
}; };
onCancelClick() {
this.props.close();
}
/** /**
* Set text field values to state. * Set text field values to state.
* */ * */
onTextFieldChange(event, value) { onTextFieldChange(event) {
let field = event.target.id; let field = event.target.name;
console.log(field, event.target.value);
switch (field) { switch (field) {
case "name": { case "appName": {
this.setState({name: value}); this.setState({name: event.target.value});
break; break;
} }
case "shortDescription": { case "appDescription": {
this.setState({shortDescription: value}); this.setState({description: event.target.value});
break;
}
case "description": {
this.setState({description: value});
break;
}
case "identifier": {
this.setState({identifier: value});
break; break;
} }
} }
}; };
onVisibilityChange(event) {
console.log(event.target.value);
this.setState({visibility: event.target.value});
}
onVisibilityItemSelect(event) {
}
render() { render() {
const {visibility} = this.state;
let visibilityItem = () => {
switch (visibility) {
case("public"): {
return <div/>
}
case("roles"): {
return <FormGroup>
<Input
type="select"
name="visibility-item"
id="app-visibility-item"
onChange={this.onVisibilityItemSelect}
>
<option id="app-visibility-default" disabled selected>Select the Roles.</option>
<option><Input type="checkbox" />Role1</option>
<option>Role2</option>
</Input>
</FormGroup>
}
case ("groups"): {
return <FormGroup>
<Input
type="select"
name="visibility-item"
id="app-visibility-item"
onChange={this.onVisibilityItemSelect}
>
<option id="app-visibility-default" disabled selected>Select the Groups.</option>
<option>Group1</option>
<option>Group2</option>
</Input>
</FormGroup>
}
default: {
return <div/>
}
}
};
return ( return (
<div className="createStep2Content"> <div className="createStep2Content">
<div> <div>
@ -135,13 +199,27 @@ class Step1 extends Component {
<Label for="app-title"> <Label for="app-title">
<FormattedMessage id='Title' defaultMessage='Title'/>* <FormattedMessage id='Title' defaultMessage='Title'/>*
</Label> </Label>
<Input required type="text" name="appName" id="app-title"/> <Input
required
type="text"
name="appName"
id="app-title"
value={this.state.name}
onChange={this.onTextFieldChange}
/>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="app-description"> <Label for="app-description">
<FormattedMessage id='Description' defaultMessage='Description'/>* <FormattedMessage id='Description' defaultMessage='Description'/>*
</Label> </Label>
<Input required type="textarea" name="appDescription" id="app-description"/> <Input
required
type="textarea"
name="appDescription"
id="app-description"
value={this.state.description}
onChange={this.onTextFieldChange}
/>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="app-category"> <Label for="app-category">
@ -155,11 +233,24 @@ class Step1 extends Component {
<Label for="app-visibility"> <Label for="app-visibility">
<FormattedMessage id='Visibility' defaultMessage='Visibility'/> <FormattedMessage id='Visibility' defaultMessage='Visibility'/>
</Label> </Label>
<Input type="select" name="visibility" id="app-visibility"> <Form inline>
<option><FormattedMessage id='Devices' defaultMessage='Devices'/></option> <FormGroup>
<option><FormattedMessage id='Roles' defaultMessage='Roles'/></option> <Input
<option><FormattedMessage id='Groups' defaultMessage='Groups'/></option> type="select"
</Input> name="visibility"
id="app-visibility"
onChange={this.onVisibilityChange}
>
<option id="app-visibility-default" disabled selected>Select the App Visibility
Option.
</option>
<option key={1}><FormattedMessage id='Devices' defaultMessage='Devices'/></option>
<option key={2}><FormattedMessage id='Roles' defaultMessage='Roles'/></option>
<option key={3}><FormattedMessage id='Groups' defaultMessage='Groups'/></option>
</Input>
</FormGroup>
{visibilityItem()}
</Form>
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="app-tags"><FormattedMessage id='Tags' defaultMessage='Tags'/>*</Label> <Label for="app-tags"><FormattedMessage id='Tags' defaultMessage='Tags'/>*</Label>
@ -176,9 +267,10 @@ class Step1 extends Component {
{this.state.tags.map(tag => { {this.state.tags.map(tag => {
return ( return (
<Badge <Badge
style={{margin: '0 2px 0 2px'}} style={{margin: '0 2px 0 2px', backgroundColor: 'blue', height: '20px'}}
value={tag.value} value={tag.key}
onClick={this.handleRequestDelete.bind(this)} key={tag.key}
onClick={() => this.handleRequestDelete(tag.key)}
> >
{tag.value} {tag.value}
</Badge> </Badge>
@ -189,6 +281,10 @@ class Step1 extends Component {
</FormGroup> </FormGroup>
</div> </div>
</div> </div>
<ModalFooter>
<Button color="danger" onClick={this.onCancelClick}>Cancel</Button>
<Button color="primary" onClick={this.setStepData}>Continue</Button>
</ModalFooter>
</div> </div>
); );
} }

@ -20,7 +20,7 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import AuthHandler from "../../../../api/authHandler"; import AuthHandler from "../../../../api/authHandler";
import PlatformMgtApi from "../../../../api/platformMgtApi"; import PlatformMgtApi from "../../../../api/platformMgtApi";
import {FormGroup, Input, Label} from 'reactstrap'; import {Button, FormGroup, Input, Label, ModalFooter} from 'reactstrap';
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
/** /**
@ -41,24 +41,28 @@ class Step2 extends Component {
super(); super();
this.setPlatforms = this.setPlatforms.bind(this); this.setPlatforms = this.setPlatforms.bind(this);
this.setStepData = this.setStepData.bind(this); this.setStepData = this.setStepData.bind(this);
this.onCancelClick = this.onCancelClick.bind(this);
this.onBackClick = this.onBackClick.bind(this);
this.platforms = []; this.platforms = [];
this.state = { this.state = {
finished: false,
stepIndex: 0,
store: 1, store: 1,
platformSelectedIndex: 0, platformSelectedIndex: 0,
platform: "", platform: "",
platforms: [], platforms: []
stepData: [],
title: "",
titleError: ""
}; };
} }
componentWillMount() {
const {defaultData} = this.props;
if (defaultData) {
this.setState(defaultData);
}
}
componentDidMount() { componentDidMount() {
//Get the list of available platforms and set to the state. //Get the list of available platforms and set to the state.
PlatformMgtApi.getPlatforms().then(response => { PlatformMgtApi.getPlatforms().then(response => {
console.log(response);
this.setPlatforms(response.data); this.setPlatforms(response.data);
}).catch(err => { }).catch(err => {
AuthHandler.unauthorizedErrorHandler(err); AuthHandler.unauthorizedErrorHandler(err);
@ -83,18 +87,26 @@ class Step2 extends Component {
* Persist the current form data to the state. * Persist the current form data to the state.
* */ * */
setStepData() { setStepData() {
let step = { const {store, platform} = this.state;
store: this.state.store, let data = {
platform: this.state.platforms[this.state.platformSelectedIndex] store: store,
platform: platform[0]
}; };
this.props.setData("step2", {step: step}); this.props.setStepData("platform", data);
}
onCancelClick() {
this.props.close();
}
onBackClick() {
this.props.handlePrev();
} }
/** /**
* Triggers when changing the Platform selection. * Triggers when changing the Platform selection.
* */ * */
onChangePlatform(event) { onChangePlatform(event) {
console.log(event.target.value, this.state.platforms);
let id = event.target.value; let id = event.target.value;
let selectedPlatform = this.state.platforms.filter((platform) => { let selectedPlatform = this.state.platforms.filter((platform) => {
return platform.identifier === id; return platform.identifier === id;
@ -122,16 +134,27 @@ class Step2 extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<Label for="store"><FormattedMessage id='Platform' defaultMessage='Platform'/></Label> <Label for="store"><FormattedMessage id='Platform' defaultMessage='Platform'/></Label>
<Input type="select" name="store" onChange={this.onChangePlatform.bind(this)}> <Input
required
type="select"
name="store"
onChange={this.onChangePlatform.bind(this)}
>
<option id="app-visibility-default" disabled selected>Select the Application Platform</option>
{this.state.platforms.length > 0 ? this.state.platforms.map(platform => { {this.state.platforms.length > 0 ? this.state.platforms.map(platform => {
return ( return (
<option value={platform.identifier}> <option value={platform.identifier} key={platform.identifier}>
{platform.name} {platform.name}
</option> </option>
) )
}) : <option><FormattedMessage id='No.Platform' defaultMessage='No Platforms'/></option>} }) : <option><FormattedMessage id='No.Platform' defaultMessage='No Platforms'/></option>}
</Input> </Input>
</FormGroup> </FormGroup>
<ModalFooter>
<Button color="primary" onClick={this.onBackClick}>Back</Button>
<Button color="danger" onClick={this.onCancelClick}>Cancel</Button>
<Button color="primary" onClick={this.setStepData}>Continue</Button>
</ModalFooter>
</div> </div>
); );
} }

@ -19,7 +19,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import Dropzone from 'react-dropzone'; import Dropzone from 'react-dropzone';
import React, {Component} from 'react'; import React, {Component} from 'react';
import {FormGroup, Label} from 'reactstrap'; import {Button, FormGroup, Label, ModalFooter} from 'reactstrap';
import AppImage from "../../../UIComponents/AppImage/AppImage"; import AppImage from "../../../UIComponents/AppImage/AppImage";
import {FormattedMessage} from 'react-intl'; import {FormattedMessage} from 'react-intl';
@ -40,22 +40,23 @@ import {FormattedMessage} from 'react-intl';
class Step3 extends Component { class Step3 extends Component {
constructor() { constructor() {
super(); super();
this.setStepData = this.setStepData.bind(this);
this.onBackClick = this.onBackClick.bind(this);
this.onCancelClick = this.onCancelClick.bind(this);
this.state = { this.state = {
tags: [],
icon: [], icon: [],
title: "",
errors: {}, errors: {},
banner: [], banner: [],
defValue: "",
category: 0,
visibility: 0,
description: "",
screenshots: [], screenshots: [],
identifier: "",
shortDescription: ""
}; };
} }
componentWillMount() {
const {defaultData} = this.props;
this.setState(defaultData);
}
/** /**
* Handles Chip delete function. * Handles Chip delete function.
* Removes the tag from state.tags * Removes the tag from state.tags
@ -72,15 +73,26 @@ class Step3 extends Component {
* Creates an object with the current step data and persist in the parent. * Creates an object with the current step data and persist in the parent.
* */ * */
setStepData() { setStepData() {
const {icon, banner, screenshots} = this.state;
let stepData = { let stepData = {
icon: this.state.icon, icon: icon,
banner: this.state.banner, banner: banner,
screenshots: this.state.screenshots screenshots: screenshots
}; };
this.props.setData("step2", {step: stepData}); this.props.setStepData("screenshots", stepData);
}; };
onCancelClick() {
this.props.close();
}
onBackClick() {
this.props.handlePrev();
}
/** /**
* Removed user uploaded banner. * Removed user uploaded banner.
* */ * */
@ -126,7 +138,6 @@ class Step3 extends Component {
onDrop={(screenshots, rejected) => { onDrop={(screenshots, rejected) => {
let tmpScreenshots = this.state.screenshots; let tmpScreenshots = this.state.screenshots;
tmpScreenshots.push(screenshots); tmpScreenshots.push(screenshots);
console.log(screenshots); //TODO: Remove this
this.setState({ this.setState({
screenshots: tmpScreenshots screenshots: tmpScreenshots
}); });
@ -191,6 +202,11 @@ class Step3 extends Component {
</FormGroup> </FormGroup>
</div> </div>
</div> </div>
<ModalFooter>
<Button color="primary" onClick={this.onBackClick}>Back</Button>
<Button color="danger" onClick={this.onCancelClick}>Cancel</Button>
<Button color="primary" onClick={this.setStepData}>Continue</Button>
</ModalFooter>
</div> </div>
); );
} }

@ -18,7 +18,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Collapse, FormGroup, Input, Label, FormText} from 'reactstrap'; import {Button, Collapse, FormGroup, FormText, Input, Label, ModalFooter} from 'reactstrap';
import Switch from '../../../UIComponents/Switch/Switch' import Switch from '../../../UIComponents/Switch/Switch'
/** /**
@ -47,8 +47,8 @@ class Step4 extends Component {
constructor() { constructor() {
super(); super();
this.handleToggle = this.handleToggle.bind(this); this.handleToggle = this.handleToggle.bind(this);
this.handlePrev = this.handlePrev.bind(this); this.onCancelClick = this.onCancelClick.bind(this);
this.handleToggle = this.handleToggle.bind(this); this.onBackClick = this.onBackClick.bind(this);
this.handleFinish = this.handleFinish.bind(this); this.handleFinish = this.handleFinish.bind(this);
this.state = { this.state = {
showForm: false, showForm: false,
@ -66,13 +66,18 @@ class Step4 extends Component {
this.props.handleFinish(); this.props.handleFinish();
} }
/** onCancelClick() {
* Invokes Prev button click. this.props.close();
* */ }
handlePrev() {
onBackClick() {
this.props.handlePrev(); this.props.handlePrev();
} }
onSubmit() {
}
/** /**
* Handles release application selection. * Handles release application selection.
* */ * */
@ -104,12 +109,12 @@ class Step4 extends Component {
</FormGroup> </FormGroup>
<br/> <br/>
<div> <div>
<FormText color="muted"> <FormText color="muted">
<i>Info: </i> <i>Info: </i>
Enabling this will create a release for the current Application. Enabling this will create a release for the current Application.
To upload the Application, please visit to the Release management section of To upload the Application, please visit to the Release management section of
Application Edit View. Application Edit View.
</FormText> </FormText>
</div> </div>
{/*If toggle is true, the release form will be shown.*/} {/*If toggle is true, the release form will be shown.*/}
<Collapse isOpen={this.state.showForm}> <Collapse isOpen={this.state.showForm}>
@ -140,6 +145,11 @@ class Step4 extends Component {
</FormGroup> </FormGroup>
</Collapse> </Collapse>
</div> </div>
<ModalFooter>
<Button color="primary" onClick={this.onBackClick}>Back</Button>
<Button color="danger" onClick={this.onCancelClick}>Cancel</Button>
<Button color="primary" onClick={this.onSubmit}>Finish</Button>
</ModalFooter>
</div> </div>
); );
} }

@ -89,6 +89,7 @@ class ApplicationEdit extends Component {
<FormattedMessage id="Application.Name" defaultMessage="Application Name"/> <FormattedMessage id="Application.Name" defaultMessage="Application Name"/>
</Col> </Col>
</Row> </Row>
<hr/>
<Row id="application-edit-main-container"> <Row id="application-edit-main-container">
<Col xs="3"> <Col xs="3">
<div className="tab"> <div className="tab">

@ -47,91 +47,95 @@ class ApplicationView extends Component {
} }
render() { render() {
const platform = this.state.application; if (this.state.application.length === 0) {
console.log(platform); return <div/>
} else {
const app = this.state.application;
console.log(app);
return (
<div id="application-view-content">
<div id="application-view-row">
<Row>
<Col>
<div id="app-icon">
</div>
</Col>
<Col>
<Row>
<span><strong>{app.name}</strong></span>
</Row>
<Row>
<span className="app-updated-date">Last updated on {app.modifiedAt}</span>
</Row>
</Col>
</Row>
</div>
<div id="application-view-row">
<Row>
<Col>
<span className="app-install-count">2k Installs</span>
</Col>
</Row>
<Row>
<Col>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
</Col>
<Col>
<p><a href="#">View in Store</a></p>
</Col>
</Row>
</div>
<hr/>
<div id="application-view-row">
<Row>
<Col>
<span><strong>
<FormattedMessage id="Description" defaultMessage="Description"/>:
</strong></span>
</Col>
<Col>
<p>{app.description}</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Tags" defaultMessage="Tags"/>:
</strong></span>
</Col>
<Col>
<p>[list of tags...]</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Release" defaultMessage="Release"/>:
</strong></span>
</Col>
<Col>
<p>Production</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Version" defaultMessage="Version"/>:
</strong></span>
</Col>
<Col>
<p>v1.0</p>
</Col>
</Row>
</div>
</div>
return ( );
<div id="application-view-content">
<div id="application-view-row">
<Row>
<Col>
<div id="app-icon">
</div> }
</Col>
<Col>
<Row>
<span><strong>Facebook</strong></span>
</Row>
<Row>
<span className="app-updated-date">Last updated on 2017-09-23</span>
</Row>
</Col>
</Row>
</div>
<div id="application-view-row">
<Row>
<Col>
<span className="app-install-count">2k Installs</span>
</Col>
</Row>
<Row>
<Col>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
<i className="fw fw-star"></i>
</Col>
<Col>
<a href="#">View in Store</a>
</Col>
</Row>
</div>
<hr/>
<div id="application-view-row">
<Row>
<Col>
<span><strong>
<FormattedMessage id="Description" defaultMessage="Description"/>:
</strong></span>
</Col>
<Col>
<p>sdfjlkdsjfsjdfjsdf sfjdslkjfdsflkjdsfslkdjfl j</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Tags" defaultMessage="Tags"/>:
</strong></span>
</Col>
<Col>
<p>[list of tags...]</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Release" defaultMessage="Release"/>:
</strong></span>
</Col>
<Col>
<p>Production</p>
</Col>
</Row>
<Row>
<Col>
<span><strong>
<FormattedMessage id="Version" defaultMessage="Version"/>:
</strong></span>
</Col>
<Col>
<p>v1.0</p>
</Col>
</Row>
</div>
</div>
);
} }
} }

@ -18,21 +18,28 @@
import React, {Component} from 'react'; import React, {Component} from 'react';
/** /**
* Platform view component. * Platform component.
* In Platform listing, this component will be displayed as cards.
* */ * */
class PlatformView extends Component { class Platform extends Component {
constructor() { constructor() {
super(); super();
} }
render() { render() {
const {platform} = this.props;
console.log(platform);
return ( return (
<div> <div id="platform-content">
Platform View <ul>
<li>Name: {platform.name}</li>
<li>Description: {platform.description}</li>
<li>Status: {platform.enabled}</li>
</ul>
</div> </div>
); );
} }
} }
export default PlatformView; export default Platform;

@ -15,416 +15,58 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * 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 React, {Component} from 'react';
import Toggle from 'material-ui/Toggle'; import {Button, FormGroup, Label, Modal, ModalBody, ModalFooter, ModalHeader, Input} from "reactstrap";
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 PlatformMgtApi from '../../api/platformMgtApi';
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 {Card, CardActions, CardTitle} from 'material-ui/Card';
import AddCircleOutline from 'material-ui/svg-icons/content/add-circle-outline';
/** /**
* Platform Create component. * Platform view component.
* Contains following components:
* * Platform Name
* * Platform Description
* * Platform Icon
* * Whether the platform needs an app to be installed.
* * Whether the platform is enabled by default.
* * Whether the platform is shared with tenants.
* */ * */
class PlatformCreate extends Component { class PlatformCreate extends Component {
constructor() { constructor() {
super(); super();
this.onCreatePlatform = this.onCreatePlatform.bind(this); this.onCancelClick = this.onCancelClick.bind(this);
this.handleToggle = this.handleToggle.bind(this);
this.addProperty = this.addProperty.bind(this);
this.addTags = this.addTags.bind(this);
this.clearForm = this.clearForm.bind(this);
this.onPropertySelect = this.onPropertySelect.bind(this);
this.handleTagChange = this.handleTagChange.bind(this);
this.removeIcon = this.removeIcon.bind(this);
this.onTextChange = this.onTextChange.bind(this);
this.renderChip = this.renderChip.bind(this);
this.removeProperty = this.removeProperty.bind(this);
this.state = { this.state = {
tags: [], open: false
defValue: "",
enabled: true,
allTenants: false,
files: [],
platformProperties: [],
selectedProperty: 0,
name: "",
description: "",
property: "",
icon: [],
identifier: "",
propertyTypes: [
{key: 0, value: 'String'},
{key: 1, value: 'Number'},
{key: 2, value: 'Boolean'},
{key: 3, value: 'File'}]
};
}
/**
* Handles toggle button actions.
* One method is used for all the toggle buttons and, each toggle is identified by the id.
* */
handleToggle(event) {
switch (event.target.id) {
case "enabled" : {
let enabled = this.state.enabled;
this.setState({enabled: !enabled});
break;
}
case "tenant" : {
let allTenants = this.state.allTenants;
this.setState({allTenants: !allTenants});
break;
}
} }
} }
/**
* Triggers the onChange action on property type selection.
* */
onPropertySelect(event, index, value) {
console.log(this.state.propertyTypes[value]);
this.setState({selectedProperty: value});
}
/** componentWillReceiveProps(props, nextprops) {
* Handles Chip delete function. this.setState({open: props.open})
* Removes the tag from state.tags
* */
handleTagDelete(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});
} }
/** componentWillMount() {
* Create a tag on Enter key press and set it to the state. this.setState({open: this.props.open});
* 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: ""});
}
} }
/** onCancelClick() {
* Creates Chip array from state.tags. this.setState({open: false})
* */
renderChip(data) {
return (
<Chip
key={data.key}
onRequestDelete={() => this.handleTagDelete(data.key)}
style={this.styles.chip}
>
{data.value}
</Chip>
);
}
/**
* Set the value for tag.
* */
handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
}
/**
* Remove the selected property from the property list.
* */
removeProperty(property) {
let properties = this.state.platformProperties;
properties.splice(properties.indexOf(property), 1);
this.setState({platformProperties: properties});
}
/**
* Add a new platform property.
* */
addProperty() {
let property = this.state.property;
let selected = this.state.selectedProperty;
this.setState({
platformProperties:
this.state.platformProperties.concat([
{
key: property,
value: this.state.propertyTypes[selected].value
}]),
property: "",
selectedProperty: 0
});
}
/**
* Triggers in onChange event of text fields.
* Text fields are identified by their ids and the value will be persisted in the component state.
* */
onTextChange(event, value) {
let property = this.state.property;
let name = this.state.name;
let description = this.state.description;
let identifier = this.state.identifier;
switch (event.target.id) {
case "name": {
name = value;
this.setState({name: name});
break;
}
case "description": {
description = value;
this.setState({description: description});
break;
}
case "property": {
property = value;
this.setState({property: property});
break;
}
case "identifier": {
identifier = value;
this.setState({identifier: identifier});
}
}
};
/**
* Create platform object and call the create platform api.
* */
onCreatePlatform(event) {
//Call the platform create api.
event.preventDefault();
let platform = {};
platform.identifier = this.state.identifier;
platform.name = this.state.name;
platform.description = this.state.description;
platform.tags = this.state.tags;
platform.properties = this.state.platformProperties;
platform.icon = this.state.icon;
platform.enabled = this.state.enabled;
platform.allTenants = this.state.allTenants;
platform.defaultTenantMapping = true;
PlatformMgtApi.createPlatform(platform);
}
/**
* Remove the uploaded icon.
* */
removeIcon(event) {
event.preventDefault();
this.setState({icon: []});
}
/**
* Clears the user entered values in the form.
* */
clearForm(event) {
event.preventDefault();
this.setState({
enabled: true,
allTenants: false,
files: [],
platformProperties: [],
selectedProperty: 0,
name: "",
description: "",
property: "",
})
} }
render() { render() {
const {
platformProperties,
allTenants,
enabled,
selectedProperty,
propertyTypes,
name,
tags,
defValue,
description,
identifier,
property
} = this.state;
return ( return (
<div className="middle createplatformmiddle"> <div>
<Card> <Modal isOpen={this.state.open} toggle={this.toggle} id="platform-create-modal" backdrop={'static'}>
<CardTitle title="Create Platform"/> <ModalHeader>Create Platform</ModalHeader>
<CardActions> <ModalBody>
<div className="createplatformcardaction"> <FormGroup>
<form> <Label for="platform-name">Name*</Label>
<TextField <Input required type="text" name="appName" id="platform-name"/>
hintText="Unique Identifier for Platform." </FormGroup>
id="identifier" <FormGroup>
floatingLabelText="Identifier*" <Label for="platform-description">Description*</Label>
floatingLabelFixed={true} <Input required type="textarea" name="appName" id="platform-description"/>
value={identifier} </FormGroup>
onChange={this.onTextChange} </ModalBody>
/> <ModalFooter>
<br/> <Button onClick={this.onCancelClick}>Cancel</Button>
<TextField <Button color="primary">Create</Button>
hintText="Enter the Platform Name." </ModalFooter>
id="name" </Modal>
floatingLabelText="Name*"
floatingLabelFixed={true}
value={name}
onChange={this.onTextChange}
/>
<br/>
<TextField
id="description"
hintText="Enter the Platform Description."
floatingLabelText="Description*"
floatingLabelFixed={true}
multiLine={true}
rows={2}
value={description}
onChange={this.onTextChange}
/>
<br/>
<br/>
<Toggle
id="tenant"
label="Shared with all Tenants"
labelPosition="right"
onToggle={this.handleToggle}
toggled={allTenants}
/>
<br/>
<Toggle
id="enabled"
label="Enabled"
labelPosition="right"
onToggle={this.handleToggle}
toggled={enabled}
/>
<br/>
<TextField
id="tags"
hintText="Enter Platform tags.."
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={defValue}
onChange={this.handleTagChange}
onKeyPress={this.addTags}
/>
<br/>
<div className="createPlatformTagWrapper">
{tags.map(this.renderChip, this)}
</div>
<br/>
<div>
<p className="createplatformproperties">Platform Properties</p>
<div id="property-container">
{platformProperties.map((p) => {
return <div key={p.key}>{p.key} : {p.value}
<IconButton onClick={this.removeProperty.bind(this, p)}>
<Close className="createplatformpropertyclose"/>
</IconButton>
</div>
})}
</div>
<div className="createplatformproperty">
<TextField
id="property"
hintText="Property Name"
floatingLabelText="Platform Property*"
floatingLabelFixed={true}
value={this.state.property}
onChange={this.onTextChange}
/> <em/>
<SelectField
className="createplatformpropertyselect"
floatingLabelText="Property Type"
value={selectedProperty}
floatingLabelFixed={true}
onChange={this.onPropertySelect}>
{propertyTypes.map((type) => {
return <MenuItem key={type.key}
value={type.key}
primaryText={type.value}/>
})}
</SelectField>
<IconButton onClick={this.addProperty}>
<AddCircleOutline/>
</IconButton>
<br/>
</div>
</div>
<div>
<p className="createplatformiconp">Platform Icon*:</p>
<GridList className="createplatformicon" cols={1.1}>
{this.state.icon.map((tile) => (
<GridTile
key={Math.floor(Math.random() * 1000)}
title={tile.name}
actionIcon={
<IconButton onClick={this.removeIcon}>
<Clear/>
</IconButton>}>
<img src={tile.preview}/>
</GridTile>
))}
{this.state.icon.length === 0 ?
<Dropzone
className="createplatformdropzone"
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {
this.setState({icon, rejected})
}}
>
<p className="createplatformdropzonep">+</p>
</Dropzone> : <div/>}
</GridList>
</div>
<br/>
<RaisedButton
primary={true} label="Create"
onClick={this.onCreatePlatform}/>
<FlatButton label="Cancel" onClick={this.clearForm}/>
</form>
</div>
</CardActions>
</Card>
</div> </div>
); );
} }
} }
PlatformCreate.prototypes = {};
export default PlatformCreate; export default PlatformCreate;

@ -15,145 +15,61 @@
* specific language governing permissions and limitations * specific language governing permissions and limitations
* under the License. * under the License.
*/ */
import React, {Component} from 'react'; import React, {Component} from 'react';
import {withRouter} from 'react-router-dom'; import {Button, Col, Row} from "reactstrap";
import TextField from 'material-ui/TextField'; import Platform from "./Platform";
import AuthHandler from "../../api/authHandler";
import DataTable from '../UIComponents/DataTable/DataTable';
import PlatformMgtApi from "../../api/platformMgtApi"; import PlatformMgtApi from "../../api/platformMgtApi";
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import AuthHandler from "../../api/authHandler";
import PlatformCreate from "./PlatformCreate";
/** /**
* The App Create Component. * Platform view component.
*
* Application creation is handled through a Wizard. (We use Material UI Stepper.)
*
* In each step, data will be set to the state separately.
* When the wizard is completed, data will be arranged and sent to the api.
* */ * */
class PlatformListing extends Component { class PlatformListing extends Component {
constructor() { constructor() {
super(); super();
this.setPlatforms = this.setPlatforms.bind(this); this.onPlatformCreateClick = this.onPlatformCreateClick.bind(this);
this.state = { this.state = {
platforms: [], platforms: [],
asc: true openModal: false
};
}
headers = [
{
data_id: "image",
data_type: "image",
sortable: false,
label: ""
},
{
data_id: "platformName",
data_type: String,
sortable: true,
label: "Platform Name",
sort: this.sortData
},
{
data_id: "enabled",
data_type: String,
sortable: false,
label: "Enabled"
},
{
data_id: "fileBased",
data_type: String,
sortable: false,
label: "File Based"
}
];
componentDidMount() {
let platformsPromise = PlatformMgtApi.getPlatforms();
platformsPromise.then(
response => {
let platforms = this.setPlatforms(response.data);
this.setState({platforms: platforms});
}
).catch(
err => {
AuthHandler.unauthorizedErrorHandler(err);
}
)
}
/**
* Create platform objects from the response which can be displayed in the table.
* */
setPlatforms(platforms) {
let tmpPlatforms = [];
for (let index in platforms) {
let platform = {};
platform.id = platforms[index].identifier;
platform.platformName = platforms[index].name;
platform.enabled = platforms[index].enabled.toString();
platform.fileBased = platforms[index].fileBased.toString();
tmpPlatforms.push(platform)
} }
return tmpPlatforms;
}
/**
* Handles the search action.
* When typing in the search bar, this method will be invoked.
* */
searchApplications(word) {
let searchedData = [];
}
/**
* Handles sort data function and toggles the asc state.
* asc: true : sort in ascending order.
* */
sortData() {
let isAsc = this.state.asc;
let datas = isAsc ? this.data.sort(this.compare) : this.data.reverse();
this.setState({data: datas, asc: !isAsc});
} }
compare(a, b) { componentWillMount() {
if (a.applicationName < b.applicationName) PlatformMgtApi.getPlatforms().then(response => {
return -1; console.log(response);
if (a.applicationName > b.applicationName) this.setState({platforms: response.data});
return 1; }).catch(err => {
return 0; AuthHandler.unauthorizedErrorHandler(err);
})
} }
onRowClick(id) { onPlatformCreateClick() {
//TODO: Remove this this.setState({openModal: true});
console.log(id)
} }
render() { render() {
return ( return (
<div className='middle listingplatformmiddle'> <div id="platform-listing">
<Card className='listingplatformcard'> <Row>
<TextField hintText="Search" onChange={this.searchApplications.bind(this)} <div className="create-platform">
className='listingplatformsearch'/> <Button id="create-platform-btn" onClick={this.onPlatformCreateClick}>Create Platform</Button>
<CardTitle title="Platforms" className='listingplatformTitle'/> </div>
<CardActions> </Row>
<Row>
</CardActions> <div id="platform-list">
<DataTable {this.state.platforms.map(platform => {
headers={this.headers} return (
data={this.state.platforms} <Platform key={platform.identifier} platform={platform}/>
handleRowClick={this.onRowClick.bind(this)} )
noDataMessage={{type: 'button', text: 'Create Platform'}}/> })}
</Card> </div>
</Row>
<PlatformCreate open={this.state.openModal}/>
</div> </div>
); );
} }
} }
PlatformListing.propTypes = {}; export default PlatformListing;
export default withRouter(PlatformListing);

@ -93,7 +93,7 @@ class DataTable extends Component {
} }
handleBtnClick(id) { handleBtnClick(id) {
this.props.handleButtonClick(id); this.props.onAppEditClick(id);
} }
render() { render() {

@ -63,7 +63,7 @@ class DataTableRow extends Component {
handleBtnClick(event) { handleBtnClick(event) {
event.stopPropagation(); event.stopPropagation();
console.log(event.target['id']) console.log(event.target['id'])
this.props.handleButtonClick(event.target['id']); this.props.onAppEditClick(event.target['id']);
} }
render() { render() {

@ -20,7 +20,7 @@ import qs from 'qs';
import React, {Component} from 'react'; import React, {Component} from 'react';
import {Redirect, Switch} from 'react-router-dom'; import {Redirect, Switch} from 'react-router-dom';
import AuthHandler from '../../../api/authHandler'; import AuthHandler from '../../../api/authHandler';
import {Button, Card, CardBlock, CardTitle, Col, Form, FormGroup, Input, Label} from 'reactstrap'; import {Button, Card, CardBlock, CardTitle, Form, FormGroup, Input, Label} from 'reactstrap';
/** /**
* The Login Component. * The Login Component.
@ -132,27 +132,32 @@ class Login extends Component {
{/*TODO: Style the components.*/} {/*TODO: Style the components.*/}
<Card id="login-card"> <Card id="login-card">
<CardBlock> <CardBlock>
<CardTitle>WSO2 IoT APP Publisher</CardTitle> <CardTitle>
WSO2 IoT APP Publisher
</CardTitle>
<hr/>
<Form onSubmit={this.handleLogin.bind(this)}> <Form onSubmit={this.handleLogin.bind(this)}>
<FormGroup row> <FormGroup>
<Label for="userName" sm={2}>User Name:</Label> <Label for="userName">User Name:</Label>
<Col sm={10}> <Input
<Input type="text" name="userName" id="userName" placeholder="User Name" type="text"
onChange={this.onUserNameChange.bind(this)}/> name="userName"
</Col> id="userName"
placeholder="User Name"
onChange={this.onUserNameChange.bind(this)}/>
</FormGroup> </FormGroup>
<FormGroup row> <FormGroup>
<Label for="password" sm={2}>Password:</Label> <Label for="password">Password:</Label>
<Col sm={10}> <Input
<Input type="password" name="text" id="password" placeholder="Password" valid={false}
onChange={this.onPasswordChange.bind(this)}/> type="password"
</Col> name="text"
id="password"
placeholder="Password"
onChange={this.onPasswordChange.bind(this)}/>
</FormGroup> </FormGroup>
<FormGroup check row> <FormGroup>
<Col sm={{size: 10, offset: 2}}> <Button type="submit" id="login-btn">Login</Button>
<Button type="submit" id="login-btn">Login</Button>
</Col>
</FormGroup> </FormGroup>
</Form> </Form>
</CardBlock> </CardBlock>

Loading…
Cancel
Save