Authentication handling initial impl and code formatting according to https://github.com/airbnb/javascript/tree/master/react#basic-rules.

feature/appm-store/pbac
Menaka Jayawardena 7 years ago
parent b3d2abf99e
commit 7ff5823e6d

@ -18,6 +18,7 @@
import './App.scss';
import React, {Component} from 'react';
import AuthHandler from './api/authHandler';
import createHistory from 'history/createBrowserHistory';
import {BrowserRouter as Router, Redirect, Route, Switch} from 'react-router-dom'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
@ -54,12 +55,19 @@ class Base extends Component {
constructor() {
super();
this.state = {
user: "s"
user: null
}
}
componentWillMount() {
let user = AuthHandler.getUser();
if (user) {
if (!AuthHandler.isTokenExpired()) {
this.setState({user: user});
}
}
}
componentDidMount() {
@ -67,7 +75,7 @@ class Base extends Component {
}
render() {
if (this.state.user) {
if (this.state.user !== null) {
console.log("Have User.");
return (
<div className="container">

@ -1,45 +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.
*/
'use strict';
import Axios from 'axios';
/**
* Handles all tasks related to Authentication and Authorization.
* Generate access tokens, verify the user has necessary permissions etc.
* */
class AuthHandler {
/**
* Generate client id and client secret to generate access tokens.
* */
login(userName, password) {
Axios.post("https://localhost:9443/auth/application-mgt/v1.0/auth/tokens?userName=admin&password=admin").then()
}
isLoggedIn() {
}
getloggedInUser() {
}
}

@ -1,120 +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.
*/
'use strict';
import Helper from './helpers/AppMgtApiHelpers';
/**
* Application related apis
* */
export default class Endpoint{
/**
* Api for create an application.
* @param: applicationData: The application data object. This contains an object array of each step data from
* application creation wizard.
*
* From that data array, the proper application object is created and send it to the api.
* */
static createApplication(applicationData) {
console.log("In application create application", applicationData);
Helper.buildApplication(applicationData);
}
/**
* Method to handle application release process.
* */
static releaseApplication() {
}
/**
* Edit created application.
* @param applicationData: The modified application data.
* */
static editApplication(applicationData) {
}
/**
* Get all the created applications for the user.
* */
static getApplications() {
}
/**
* Get specific application.
* @param appId : The application Id.
* */
static getApplication(appId) {
}
/**
* Delete specified application.
* @param appId: The id of the application which is to be deleted.
* */
static deleteApplication(appId) {
}
/**
* Platform related apis
* */
/**
* Create a new Platform
* @param platformData: The platform data object.
* */
static createPlatform(platformData) {
// /api/application-mgt/v1.0/platforms/1.0.0/
// {
// identifier: "${platform_identifier}",
// name: "New Platform",
// description : "New Platform"
// }
}
/**
* Get available platforms
* */
static getPlatforms() {
}
/**
* Get the user specified platform
* @param platformId: The identifier of the platform
* */
static getPlatform(platformId) {
}
/**
* Delete specified platform
* @param platformId: The id of the platform which is to be deleted.
* */
static deletePlatform(platformId) {
}
}

@ -0,0 +1,106 @@
/*
* 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';
import Axios from 'axios';
import User from './data/user';
import Utils from './data/utils';
import Constants from "../common/constants";
/**
* Handles all tasks related to Authentication and Authorization.
* Generate access tokens, verify the user has necessary permissions etc.
* */
class AuthHandler {
/**
* Sends a request to the auth handler endpoint (auth/application-mgt/v1.0/auth/login) and generate token pair.
* @param userName: The user name of the user.
* @param password: The user password.
* @return Object: The response object from the axios post.
* */
static login(userName, password) {
const headers = {"Content-type": "application/json"};
let login_promise = Axios.post("https://localhost:9443/auth/application-mgt/v1.0/auth/login?userName=admin&password=admin",
null, {headers: headers});
login_promise.then(response => {
console.log(response);
const userName = response.data.userName;
const validityPeriod = response.data.expires_in; // In seconds
const WSO2_IOT_TOKEN = response.data.access_token;
const refreshToken = response.data.refresh_token;
const clientId = response.data.application_info[0].consumerKey;
const clientSecret = response.data.application_info[0].consumerSecret;
const user = new User(userName, clientId, clientSecret, validityPeriod);
console.log(user);
user.setAuthToken(WSO2_IOT_TOKEN, validityPeriod);
AuthHandler.setUser(user);
}
);
return login_promise;
};
/**
* Persists the user object in browser's local storage.
* @param user: The user object.
* */
static setUser(user) {
if (!user instanceof User) {
throw "Invalid user object";
}
localStorage.setItem(Constants.userConstants.WSO2_USER, JSON.stringify(user.toJson()));
/* TODO: IMHO it's better to get this key (`wso2_user`) from configs */
}
/**
* Get the logged in user.
* @return User: The logged in user object.
* */
static getUser() {
const userData = localStorage.getItem(Constants.userConstants.WSO2_USER);
const partialToken = Utils.getCookie(Constants.userConstants.PARTIAL_TOKEN);
if (!(userData && partialToken)) {
return null;
}
return User.fromJson(JSON.parse(userData));
}
isLoggedIn() {
}
logout() {
}
/**
* Checks whether the access token is expired.
* @return boolean: True if expired. False otherwise.
* */
static isTokenExpired() {
const userData = AuthHandler.getUser().getAuthToken();
return (Date.now() - userData._createdTime) > userData._expires;
}
}
export default AuthHandler;

@ -0,0 +1,112 @@
/*
* 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";
import Utils from './utils'
import Constants from '../../common/constants';
/**
* Represent an user logged in to the application, There will be allays one user per session and
* this user details will be persist in browser localstorage.
*/
export default class User {
constructor(name, clientId, clientSecret, validityPeriod) {
if (User._instance) {
return User._instance;
}
this._userName = name;
this._clientId = clientId;
this._clientSecret = clientSecret;
this._expires = validityPeriod;
this._createdTime = Date.now();
User._instance = this;
}
/**
* OAuth scopes which are available for use by this user
* @returns {Array} : An array of scopes
*/
get scopes() {
return this._scopes;
}
/**
* Set OAuth scopes available to be used by this user
* @param {Array} newScopes : An array of scopes
*/
set scopes(newScopes) {
Object.assign(this.scopes, newScopes);
}
/**
* Get the JS accessible access token fragment from cookie storage.
* @returns {String|null}
*/
getAuthToken() {
return Utils.getCookie(Constants.userConstants.PARTIAL_TOKEN);
}
/**
* Store the JavaScript accessible access token segment in cookie storage
* @param {String} newToken : Part of the access token which needs when accessing REST API
* @param {Number} validityPeriod : Validity period of the cookie in seconds
*/
setAuthToken(newToken, validityPeriod) {
Utils.delete_cookie(Constants.userConstants.PARTIAL_TOKEN);
Utils.setCookie(Constants.userConstants.PARTIAL_TOKEN, newToken, validityPeriod);
}
/**
*
* @param type
*/
checkPermission(type) {
throw ("Not implemented!");
}
/**
* Provide user data in JSON structure.
* @returns {JSON} : JSON representation of the user object
*/
toJson() {
return {
name: this._userName,
clientId: this._clientId,
clientSecret: this._clientSecret,
expires: this._expires
};
}
/**
* User utility method to create an user from JSON object.
* @param {JSON} userJson : Need to provide user information in JSON structure to create an user object
* @returns {User} : An instance of User(this) class.
*/
static fromJson(userJson) {
const _user = new User(userJson.name);
_user._clientId = userJson.clientId;
_user._clientSecret = userJson.clientSecret;
_user._expires = userJson.expires;
console.log(_user);
return _user;
}
}
User._instance = null; // A private class variable to preserve the single instance of a swaggerClient

@ -0,0 +1,94 @@
/*
* 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.
*/
/**
* Utility class for Publisher application
*/
class PublisherUtils {
/**
* TODO: Remove this method one the initial phase is done, This is used to continue the API class until the login page is create
* @returns {promise}
*/
// static autoLogin() {
// let auth = new AuthManager();
// return auth.authenticateUser('admin', 'admin');
// }
/**
* Get JavaScript accessible cookies saved in browser, by giving the cooke name.
* @param {String} name : Name of the cookie which need to be retrived
* @returns {String|null} : If found a cookie with given name , return its value,Else null value is returned
*/
static getCookie(name) {
let pairs = document.cookie.split(";");
let cookie = null;
for (let pair of pairs) {
pair = pair.split("=");
let cookie_name = pair[0].trim();
let value = encodeURIComponent(pair[1]);
if (cookie_name === name) {
cookie = value;
break;
}
}
return cookie;
}
/**
* Delete a browser cookie given its name
* @param {String} name : Name of the cookie which need to be deleted
*/
static delete_cookie(name) {
document.cookie = name + '=; Path=' + "/" + '; Expires=Thu, 01 Jan 1970 00:00:01 GMT;';
}
/**
* Set a cookie with given name and value assigned to it. Cookies can be only set to the same origin,
* which the script is running
* @param {String} name : Name of the cookie which need to be set
* @param {String} value : Value of the cookie, expect it to be URLEncoded
* @param {number} validityPeriod : (Optional) Validity period of the cookie in seconds
* @param {String} path : Path which needs to set the given cookie
* @param {boolean} secured : secured parameter is set
*/
static setCookie(name, value, validityPeriod, path = "/", secured = true) {
let expires = "";
const securedDirective = secured ? "; Secure" : "";
if (validityPeriod) {
const date = new Date();
date.setTime(date.getTime() + validityPeriod * 1000);
expires = "; expires=" + date.toUTCString();
}
document.cookie = name + "=" + value + expires + "; path=" + path + securedDirective + validityPeriod
}
/**
* Given an object returns whether the object is empty or not
* @param {Object} object : Any JSON object
* @returns {boolean}
*/
static isEmptyObject(object) {
return Object.keys(object).length === 0 && object.constructor === Object
}
}
export default PublisherUtils;

@ -0,0 +1,183 @@
/*
* 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';
import Axios from 'axios';
import AuthHandler from './authHandler';
import Constants from '../common/constants';
import Helper from './helpers/appMgtApiHelpers';
export default class Endpoint {
/* =================================================================
* Application related apis
* */
/**
* Api for create an application.
* @param: applicationData: The application data object. This contains an object array of each step data from
* application creation wizard.
*
* From applicationData, the proper application object will be created and send it to the api.
* */
static createApplication(applicationData) {
let app = Helper.buildApplication(applicationData).application;
let user = AuthHandler.getUser();
console.log(user.idToken);
const headers = {
"Authorization": 'Bearer ' + user.getAuthToken(),
"Content-Type": "application/json",
};
Axios.post(Constants.appManagerEndpoints.CREATE_APP, app, {headers: headers}).then(
function (response) {
console.log(response);
}
).catch(function (err) {
console.log(err);
});
}
/**
* Method to handle application release process.
* */
static releaseApplication() {
}
/**
* Promote the current state of the application.
* @param appId: The uuid of the application which the state should be updated.
* */
static updateState(appId) {
}
/**
* Get the next possible state, which the application can be promoted to.
* @param appId: The application uuid.
*/
static getNextState(appId) {
}
/**
* Edit created application.
* @param applicationData: The modified application data.
* */
static editApplication(applicationData) {
}
/**
* Get all the created applications for the user.
* @return Object: The response object from the axios post.
* */
static getApplications() {
let user = AuthHandler.getUser();
console.log("Get all applications", user.getAuthToken());
const headers = {
"Authorization": 'Bearer ' + user.getAuthToken(),
'Accept': 'application/json',
"Content-Type": "application/json",
};
return Axios.get(Constants.appManagerEndpoints.GET_ALL_APPS, {headers: headers});
}
/**
* Get specific application.
* @param appId: The application Id.
* */
static getApplication(appId) {
}
/**
* Delete specified application.
* @param appId: The id of the application which is to be deleted.
* */
static deleteApplication(appId) {
}
/*
* End of Application management apis.
* =================================================================
* */
/*
* =================================================================
* Platform related apis
* */
/**
* Create a new Platform
* @param platformData: The platform data object.
* */
static createPlatform(platformData) {
const headers = {
"Authorization": 'Bearer ' + AuthHandler.getUser().getAuthToken(),
'Accept': 'application/json',
"Content-Type": "application/json",
};
Axios.post(Constants.platformManagerEndpoints.CREATE_PLATFORM, platformData, {headers: headers}).then(
function (response) {
console.log(response);
}
).catch(function (err) {
console.log(err);
});
}
/**
* Get available platforms
* */
static getPlatforms() {
}
/**
* Get the user specified platform
* @param platformId: The identifier of the platform
* */
static getPlatform(platformId) {
}
/**
* Delete specified platform
* @param platformId: The id of the platform which is to be deleted.
* */
static deletePlatform(platformId) {
}
/*
* End of Platform management apis.
* =================================================================
* */
}

@ -26,24 +26,31 @@ export default class Helper {
/**
* Generate application object from form data passed.
* @param appData: Application data from the application creation form.
* @return {Object, Object}: The application object and the set of images related to the application.
* */
static buildApplication(appData) {
let application = {};
let images = {};
for (var step in appData) {
for (let step in appData) {
let tmpData = appData[step].data.step;
for (var prop in tmpData) {
for (let prop in tmpData) {
if (prop === 'banner' || prop === 'screenshots' || prop === 'icon') {
images[prop] = tmpData[prop];
} else if(prop === 'tags') {
let tags = [];
let tagsFromStep = tmpData[prop];
for (let tag in tagsFromStep) {
console.log(tag);
tags.push(tagsFromStep[tag].value);
}
application[prop] = tags;
} else {
application[prop] = tmpData[prop];
}
}
}
console.log(application, images);
return {application, images};
}
}

@ -16,16 +16,30 @@
* under the License.
*/
scopes = 'perm:application:get perm:application:create perm:application:update perm:application-mgt:login' +
' perm:application:delete perm:platform:add perm:platform:remove perm:roles:view perm:devices:view';
export default class Constants {
TOKEN_ENDPOINT = '/token';
DYNAMIC_CLIENT_REGISTER_ENDPOINT = '/api-application-registration/register';
static scopes = 'perm:application:get perm:application:create perm:application:update perm:application-mgt:login' +
' perm:application:delete perm:platform:add perm:platform:remove perm:roles:view perm:devices:view';
static TOKEN_ENDPOINT = '/token';
static DYNAMIC_CLIENT_REGISTER_ENDPOINT = '/api-application-registration/register';
static appManagerEndpoints = {
GET_ALL_APPS: 'https://localhost:8243/api/application-mgt/v1.0/applications/1.0.0/',
CREATE_APP: 'https://localhost:8243/api/application-mgt/v1.0/applications/1.0.0/',
UPLOAD_IMAGES: '/api/application-mgt/v1.0/applications/1.0.0/upload-image-artifacts/', //+appId
};
static platformManagerEndpoints = {
CREATE_PLATFORM: 'https://localhost:8243/api/application-mgt/v1.0/platforms/1.0.0/'
}
static userConstants = {
WSO2_USER: 'wso2_user',
PARTIAL_TOKEN: 'WSO2_IOT_TOKEN'
}
}
appManagerEndpoints = {
GET_ALL_APPS: '/api/application-mgt/v1.0/applications/1.0.0/',
CREATE_APP: '/api/application-mgt/v1.0/applications/1.0.0/',
UPLOAD_IMAGES: '/api/application-mgt/v1.0/applications/1.0.0/upload-image-artifacts/', //+appId
};

@ -18,7 +18,7 @@
import React, {Component} from 'react';
import Dialog from 'material-ui/Dialog';
import Endpoint from '../../api/Endpoints';
import Endpoint from '../../api/endpoints';
import {withRouter} from 'react-router-dom';
import FlatButton from 'material-ui/FlatButton';
import {Step1, Step2, Step3} from './CreateSteps';
@ -67,7 +67,7 @@ class ApplicationCreate extends Component {
/**
* Handles next button click event.
* */
handleNext = () => {
handleNext() {
console.log("Handle Next");
const {stepIndex} = this.state;
this.setState({
@ -79,7 +79,7 @@ class ApplicationCreate extends Component {
/**
* Handles form submit.
* */
handleSubmit = () => {
handleSubmit() {
console.log(this.state.stepData);
Endpoint.createApplication(this.state.stepData);
@ -89,7 +89,7 @@ class ApplicationCreate extends Component {
* Handles cancel button click event.
* This will show a confirmation dialog to cancel the application creation process.
* */
handleCancel = () => {
handleCancel() {
this.setState({isDialogOpen: true});
};
@ -97,7 +97,7 @@ class ApplicationCreate extends Component {
* Handled [ < Prev ] button click.
* This clears the data in the current step and returns to the previous step.
* */
handlePrev = () => {
handlePrev() {
const {stepIndex} = this.state;
if (stepIndex > 0) {
this.removeStepData();
@ -108,7 +108,7 @@ class ApplicationCreate extends Component {
/**
* Saves form data in each step in to the state.
* */
setStepData = (step, data) => {
setStepData(step, data) {
console.log(step, data, this.state.stepData);
let tmpStepData = this.state.stepData;
tmpStepData.push({step: step, data: data});
@ -119,7 +119,7 @@ class ApplicationCreate extends Component {
/**
* Remove the last data point
* */
removeStepData = () => {
removeStepData() {
let tempData = this.state.stepData;
tempData.pop();
this.setState({stepData: tempData});
@ -129,7 +129,7 @@ class ApplicationCreate extends Component {
* Handles the Yes button in app creation cancellation dialog.
* Clears all the form data and reset the wizard.
* */
handleYes = () => {
handleYes() {
this.setState({finished: false, stepIndex: 0, stepData: [], isDialogOpen: false});
};
@ -137,7 +137,7 @@ class ApplicationCreate extends Component {
* Handles No button in app creation cancellation dialog.
* Returns to the same step.
* */
handleNo = () => {
handleNo() {
this.setState({isDialogOpen: false});
};
@ -153,21 +153,27 @@ class ApplicationCreate extends Component {
getStepContent(stepIndex) {
switch (stepIndex) {
case 0:
return <Step1 handleNext={this.handleNext}
setData={this.setStepData}
removeData={this.removeStepData}/>;
return <Step1
handleNext={this.handleNext}
setData={this.setStepData}
removeData={this.removeStepData}
/>;
case 1:
return <Step2 handleNext={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}/>;
return <Step2
handleNext={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}
/>;
case 2:
return <Step3 handleFinish={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}/>;
return <Step3
handleFinish={this.handleNext}
handlePrev={this.handlePrev}
setData={this.setStepData}
removeData={this.removeStepData}
/>;
default:
return <div></div>;
return <div/>;
}
}

@ -17,6 +17,7 @@
*/
import React, {Component} from 'react';
import EndPoint from '../../api/endpoints';
import {withRouter} from 'react-router-dom';
import TextField from 'material-ui/TextField';
import DataTable from '../UIComponents/DataTable';
@ -44,37 +45,37 @@ class ApplicationListing extends Component {
data = [
{
id: Math.random(),
applicationName:"Cne",
platform:'Android',
category:"Public",
applicationName: "Cne",
platform: 'Android',
category: "Public",
status: "Created"
},
{
id: Math.random(),
applicationName:"Gone",
platform:'IOS',
category:"Public",
applicationName: "Gone",
platform: 'IOS',
category: "Public",
status: "Created"
},
{
id: Math.random(),
applicationName:"Ane",
platform:'Android',
category:"Public",
applicationName: "Ane",
platform: 'Android',
category: "Public",
status: "Created"
},
{
id: Math.random(),
applicationName:"one",
platform:'Android',
category:"Public",
applicationName: "one",
platform: 'Android',
category: "Public",
status: "Created"
},
{
id: Math.random(),
applicationName:"one",
platform:'Android',
category:"Public",
applicationName: "one",
platform: 'Android',
category: "Public",
status: "Created"
},
];
@ -84,19 +85,21 @@ class ApplicationListing extends Component {
data_id: "image",
data_type: "image",
sortable: false,
label: ""},
label: ""
},
{
data_id: "applicationName",
data_type: "string",
sortable: true,
label: "Application Name",
sort: this._sortData.bind(this)
sort: this.sortData.bind(this)
},
{
data_id: "platform",
data_type: "image_array",
sortable: false,
label: "Platform"},
label: "Platform"
},
{
data_id: "category",
data_type: "string",
@ -125,36 +128,41 @@ class ApplicationListing extends Component {
Theme.removeThemingScripts(this.scriptId);
}
componentDidMount() {
let getApps = EndPoint.getApplications();
getApps.then(response => {
console.log(response);
})
}
/**
* Handles the search action.
* When typing in the search bar, this method will be invoked.
* */
_searchApplications(event, word) {
searchApplications(event, word) {
let searchedData;
if (word){
searchedData = this.data.filter((dataItem) => {
return dataItem.applicationName.includes(word);
});
} else {
searchedData = this.data;
}
if (word) {
searchedData = this.data.filter((dataItem) => {
return dataItem.applicationName.includes(word);
});
} else {
searchedData = this.data;
}
this.setState({data: searchedData}, console.log("Searched data ", this.state.data));
}
/**
* Handles sort data function and toggles the asc state.
* asc: true : sort in ascending order.
* */
_sortData() {
sortData() {
let isAsc = this.state.asc;
let datas = isAsc?this.data.sort(this._compare):this.data.reverse();
let datas = isAsc ? this.data.sort(this.compare) : this.data.reverse();
this.setState({data: datas, asc: !isAsc});
}
_compare(a, b) {
compare(a, b) {
if (a.applicationName < b.applicationName)
return -1;
if (a.applicationName > b.applicationName)
@ -162,8 +170,8 @@ class ApplicationListing extends Component {
return 0;
}
_onRowClick(id) {
this.props.history.push("apps/"+id);
onRowClick(id) {
this.props.history.push("apps/" + id);
}
render() {
@ -171,18 +179,17 @@ class ApplicationListing extends Component {
<div className="middle applicationListingMiddle">
<Card className="applicationListingCard">
<TextField hintText="Search" className="applicationListingSearch"
onChange={this._searchApplications.bind(this)}/>
onChange={this.searchApplications.bind(this)}/>
<CardTitle title="Applications" className="applicationListTitle"/>
<CardActions>
</CardActions>
<DataTable headers={this.headers}
data={this.state.data}
handleRowClick={this._onRowClick.bind(this)}
noDataMessage={{type: 'button', text: 'Create Application'}}/>
<DataTable
headers={this.headers}
data={this.state.data}
handleRowClick={this.onRowClick.bind(this)}
noDataMessage={{type: 'button', text: 'Create Application'}}
/>
</Card>
</div>);
</div>
);
}
}

@ -39,11 +39,13 @@ import Theme from '../../../theme';
class Step1 extends Component {
constructor() {
super();
this.platforms = [{identifier: 1}, {identifier: 2}, {identifier: 3}];
this.stores = [{identifier: 5}, {identifier: 2}, {identifier: 3}];
this.state = {
finished: false,
stepIndex: 0,
store: 1,
platform: 1,
platform: 0,
stepData: [],
title: "",
titleError: ""
@ -65,17 +67,17 @@ class Step1 extends Component {
/**
* Invokes the handleNext function in Create component.
* */
_handleNext = () => {
handleNext() {
this.props.handleNext();
};
/**
* Persist the current form data to the state.
* */
_setStepData() {
var step = {
setStepData() {
let step = {
store: this.state.store,
platform: this.state.platform
platform: this.platforms[this.state.platform]
};
this.props.setData("step1", {step: step});
}
@ -86,14 +88,14 @@ class Step1 extends Component {
* Sets the data to the state.
* Invokes the handleNext method of Create component.
* */
_handleClick() {
this._setStepData();
handleClick() {
this.setStepData();
}
/**
* Triggers when changing the Platform selection.
* */
_onChangePlatform = (event, index, value) => {
onChangePlatform(event, index, value) {
console.log(value);
this.setState({platform: value});
};
@ -101,17 +103,10 @@ class Step1 extends Component {
/**
* Triggers when changing the Store selection.
* */
_onChangeStore = (event, index, value) => {
onChangeStore(event, index, value) {
this.setState({store: value});
};
/**
* Triggers when user types on Title text field.
* */
_onChangeTitle = (event, value) => {
this.setState({title: value});
};
render() {
return (
<div>
@ -122,30 +117,30 @@ class Step1 extends Component {
floatingLabelText="Store Type*"
value={this.state.store}
floatingLabelFixed={true}
onChange={this._onChangeStore.bind(this)}
onChange={this.onChangeStore.bind(this)}
>
<MenuItem value={1} primaryText="Enterprise"/>
<MenuItem value={2} primaryText="Public"/>
</SelectField> <br/>
<MenuItem value={0} primaryText="Enterprise"/>
<MenuItem value={1} primaryText="Public"/>
</SelectField>
<br/>
<SelectField
floatingLabelText="Platform*"
value={this.state.platform}
floatingLabelFixed={true}
onChange={this._onChangePlatform.bind(this)}
onChange={this.onChangePlatform.bind(this)}
>
<MenuItem value={1} primaryText="Android"/>
<MenuItem value={2} primaryText="iOS"/>
<MenuItem value={{name: "Web", id:3}} primaryText="Web"/>
<MenuItem value={0} primaryText="Android"/>
<MenuItem value={1} primaryText="iOS"/>
<MenuItem value={2} primaryText="Web"/>
</SelectField>
</div>
<br/>
<br/>
<div className="nextButton">
<RaisedButton
label="Next >"
primary={true}
onClick={this._handleClick.bind(this)}
onClick={this.handleClick.bind(this)}
/>
</div>
</div>

@ -65,6 +65,7 @@ class Step2 extends Component {
visibility: 0,
description: "",
screenshots: [],
identifier: "",
shortDescription: ""
};
this.scriptId = "application-create-step2";
@ -86,19 +87,19 @@ class Step2 extends Component {
* Clears the tags text field.
* Chip gets two parameters: Key and value.
* */
_addTags(event) {
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: ""});
this.setState({tags, defValue: ""}, console.log(tags));
}
}
/**
* Set the value for tag.
* */
_handleTagChange(event) {
handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
@ -107,21 +108,21 @@ class Step2 extends Component {
/**
* Invokes the handleNext function in Create component.
* */
_handleNext() {
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: "Identifier", value: this.state.identifier},
{name: "Icon", value: this.state.icon}];
this._validate(fields);
// this.props.handleNext();
this.validate(fields);
}
/**
* Invokes the handlePrev function in Create component.
* */
_handlePrev() {
handlePrev() {
this.props.handlePrev();
}
@ -129,7 +130,7 @@ class Step2 extends Component {
* Handles Chip delete function.
* Removes the tag from state.tags
* */
_handleRequestDelete = (key) => {
handleRequestDelete(key) {
this.chipData = this.state.tags;
const chipToDelete = this.chipData.map((chip) => chip.key).indexOf(key);
this.chipData.splice(chipToDelete, 1);
@ -139,18 +140,18 @@ class Step2 extends Component {
/**
* Creates Chip array from state.tags.
* */
_renderChip(data) {
renderChip(data) {
return (
<Chip
key={data.key}
onRequestDelete={() => this._handleRequestDelete(data.key)}
onRequestDelete={() => this.handleRequestDelete(data.key)}
className="applicationCreateChip">
{data.value}
</Chip>
);
}
_onVisibilitySelect = (event, index, value) => {
onVisibilitySelect(event, index, value) {
console.log(value);
let comp = <SelectField> <MenuItem value={0} primaryText="Public"/>
<MenuItem value={1} primaryText="Roles"/>
@ -167,7 +168,7 @@ class Step2 extends Component {
/**
* Validate the form.
* */
_validate(fields) {
validate(fields) {
let errors = {};
let errorsPresent = false;
fields.forEach(function (field) {
@ -181,6 +182,15 @@ class Step2 extends Component {
}
break;
}
case 'Identifier': {
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!";
@ -219,7 +229,7 @@ class Step2 extends Component {
}
case 'Screenshots': {
if (field.value.length < 3) {
errors[field.name] = "3 " +field.name + " are required!";
errors[field.name] = "3 " + field.name + " are required!";
errorsPresent = true;
} else {
errorsPresent = false;
@ -229,41 +239,40 @@ class Step2 extends Component {
}
});
console.log(errorsPresent);
if (!errorsPresent) {
this._setStepData();
this.setStepData();
} else {
this.setState({errors: errors}, console.log(errors));
}
}
/**
* Creates an object with the current step data and persist in the parent.
* */
_setStepData() {
setStepData() {
let stepData = {
tags: this.state.tags,
icon: this.state.icon,
title: this.state.title,
name: this.state.name,
tags: this.state.tags,
banner: this.state.banner,
category: this.state.category,
category: this.categories[this.state.category],
identifier: this.state.identifier,
screenshots: this.state.screenshots,
description: this.state.description,
shortDescription: this.state.shortDescription
};
this.props.setData("step2", {step: stepData});
}
};
/**
* Set text field values to state.
* */
_onTextFieldChange(event, value) {
onTextFieldChange(event, value) {
let field = event.target.id;
switch (field) {
case "title": {
this.setState({title: value});
case "name": {
this.setState({name: value});
break;
}
case "shortDescription": {
@ -274,30 +283,34 @@ class Step2 extends Component {
this.setState({description: value});
break;
}
case "identifier": {
this.setState({identifier: value});
break;
}
}
}
};
/**
* Removed user uploaded banner.
* */
_removeBanner(event, d) {
removeBanner(event, d) {
console.log(event, d);
this.setState({banner: []});
}
};
/**
* Removes uploaded icon.
* */
_removeIcon(event) {
removeIcon(event) {
this.setState({icon: []});
}
};
/**
* Removes selected screenshot.
* */
_removeScreenshot(event) {
removeScreenshot(event) {
console.log(event.target)
}
};
render() {
console.log(this.state.visibilityComponent);
@ -306,13 +319,23 @@ class Step2 extends Component {
<div>
<div>
<TextField
id="title"
hintText="Enter a title for your application."
id="name"
hintText="Enter a name for your application."
errorText={this.state.errors["Title"]}
floatingLabelText="Title*"
floatingLabelText="Name*"
floatingLabelFixed={true}
onChange={this.onTextFieldChange.bind(this)}
/>
<br/>
<TextField
id="identifier"
hintText="Unique Identifier for Application."
errorText={this.state.errors["Identifier"]}
floatingLabelText="Identifier*"
floatingLabelFixed={true}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
onChange={this.onTextFieldChange.bind(this)}
/>
<br/>
<TextField
id="shortDescription"
hintText="Enter a short description for your application."
@ -321,9 +344,9 @@ class Step2 extends Component {
floatingLabelFixed={true}
multiLine={true}
rows={2}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
onChange={this.onTextFieldChange.bind(this)}
/>
<br/>
<TextField
id="description"
errorText={this.state.errors["Description"]}
@ -332,18 +355,20 @@ class Step2 extends Component {
floatingLabelFixed={true}
multiLine={true}
rows={4}
onChange={this._onTextFieldChange.bind(this)}
/><br/>
onChange={this.onTextFieldChange.bind(this)}
/>
<br/>
<SelectField
floatingLabelText="Visibility*"
value={this.state.visibility}
floatingLabelFixed={true}
onChange={this._onVisibilitySelect.bind(this)}
onChange={this.onVisibilitySelect.bind(this)}
>
<MenuItem value={0} primaryText="Public"/>
<MenuItem value={1} primaryText="Roles"/>
<MenuItem value={2} primaryText="Devices"/>
</SelectField><br/>
</SelectField>
<br/>
<TextField
id="tags"
errorText={this.state.errors["tags"]}
@ -351,11 +376,12 @@ class Step2 extends Component {
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={this.state.defValue}
onChange={this._handleTagChange.bind(this)}
onKeyPress={this._addTags.bind(this)}
/><br/>
<div className="applicationCreateWrapper">
{this.state.tags.map(this._renderChip, this)}
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
@ -364,7 +390,8 @@ class Step2 extends Component {
floatingLabelFixed={true}
>
<MenuItem value={0} primaryText="Business"/>
</SelectField> <br/>
</SelectField>
<br/>
{/*Platform Specific Properties.*/}
<div className="platformSpecificPropertyDiv">
<p className="platformSpecificPropertyP">Platform Specific Properties</p>
@ -375,50 +402,58 @@ class Step2 extends Component {
<p className="applicationCreateBannerTitle">Banner*:</p>
<GridList className="applicationCreateGrid" 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>
<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 className="applicationCreateBannerDropZone" accept="image/jpeg, image/png"
onDrop={(banner, rejected) => {
this.setState({banner, rejected});
}}>
<p className="applicationCreateBannerp">+</p>
</Dropzone> : <div />}
<Dropzone
className="applicationCreateBannerDropZone"
accept="image/jpeg, image/png"
onDrop={(banner, rejected) => {
this.setState({banner, rejected});
}}
>
<p className="applicationCreateBannerp">+</p>
</Dropzone> : <div/>
}
</GridList>
</div>
<br/>
<div>
<p className="applicationCreateScreenshotError">{this.state.errors["Screenshots"]}</p>
<p className="applicationCreateScreenshotTitle">Screenshots*:</p>
<GridList className = "applicationCreateScreenshotGrid" cols={1.1}>
<GridList className="applicationCreateScreenshotGrid" 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>}>
<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 className="applicationCreateScreenshotDropZone"
accept="image/jpeg, image/png"
onDrop={(screenshots, rejected) => {
let tmpScreenshots = this.state.screenshots;
tmpScreenshots.push(screenshots);
this.setState({
screenshots: tmpScreenshots});
}}>
<p className="applicationCreateScreenshotp">+</p>
</Dropzone> : <div />}
<Dropzone
className="applicationCreateScreenshotDropZone"
accept="image/jpeg, image/png"
onDrop={(screenshots, rejected) => {
let tmpScreenshots = this.state.screenshots;
tmpScreenshots.push(screenshots);
this.setState({
screenshots: tmpScreenshots
});
}}
>
<p className="applicationCreateScreenshotp">+</p>
</Dropzone> : <div/>}
</GridList>
</div>
<br/>
@ -427,38 +462,43 @@ class Step2 extends Component {
<p className="applicationCreateIconTitle">Icon*:</p>
<GridList className="applicationCreateIconGrid" 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>
<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 className="applicationCreateIconDropZone"
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected});}}>
<p className="applicationCreateIconp">+</p>
</Dropzone> : <div />}
<Dropzone
className="applicationCreateIconDropZone"
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {
this.setState({icon, rejected});
}}
>
<p className="applicationCreateIconp">+</p>
</Dropzone> : <div/>}
</GridList>
</div>
<br/>
</div>
<br/>
<br/>
<div className="applicationCreateBackAndNext">
<FlatButton
label="< Back"
disabled={false}
onClick={this._handlePrev.bind(this)}
className="applicationCreateBack"
onClick={this.handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton
label="Next >"
primary={true}
onClick={this._handleNext.bind(this)}
onClick={this.handleNext.bind(this)}
/>
</div>
</div>

@ -63,7 +63,7 @@ class Step3 extends Component {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
@ -74,21 +74,21 @@ class Step3 extends Component {
* Handles finish button click.
* This invokes handleNext function in parent component.
* */
_handleFinish() {
handleFinish() {
this.props.handleFinish();
}
/**
* Invokes Prev button click.
* */
_handlePrev() {
handlePrev() {
this.props.handlePrev();
}
/**
* Handles release application selection.
* */
_handleToggle() {
handleToggle() {
let hide = this.state.showForm;
this.setState({showForm: !hide});
}
@ -100,36 +100,42 @@ class Step3 extends Component {
<Toggle
label="Release the Application"
labelPosition="right"
onToggle={this._handleToggle.bind(this)}
onToggle={this.handleToggle.bind(this)}
defaultToggled={this.state.showForm}
/>
{/*If toggle is true, the release form will be shown.*/}
{!this.state.showForm ? <div/> : <div>
<SelectField
floatingLabelText="Select Release Channel*"
value={this.state.releaseChannel}
floatingLabelFixed={true}
>
<MenuItem value={1} primaryText="Alpha"/>
<MenuItem value={2} primaryText="Beta"/>
<MenuItem value={3} primaryText="GA"/>
</SelectField> <br/>
<TextField
hintText="1.0.0"
floatingLabelText="Version*"
errorText={this.state.errors["title"]}
floatingLabelFixed={true}
/><br/>
</div>}
{!this.state.showForm ? <div/> :
<div>
<SelectField
floatingLabelText="Select Release Channel*"
value={this.state.releaseChannel}
floatingLabelFixed={true}
>
<MenuItem value={1} primaryText="Alpha"/>
<MenuItem value={2} primaryText="Beta"/>
<MenuItem value={3} primaryText="GA"/>
</SelectField>
<br/>
<TextField
hintText="1.0.0"
floatingLabelText="Version*"
errorText={this.state.errors["title"]}
floatingLabelFixed={true}
/><br/>
</div>}
<div className="applicationCreateBackAndFinish">
<FlatButton label="< Back" disabled={false} onClick={this._handlePrev.bind(this)}
className="applicationCreateFinish"/>
<FlatButton
label="< Back"
disabled={false}
onClick={this.handlePrev.bind(this)}
className="applicationCreateFinish"/>
<RaisedButton
label="Finish"
primary={true}
onClick={this._handleFinish.bind(this)}
onClick={this.handleFinish.bind(this)}
/>
</div>
</div>
</div>

@ -97,67 +97,74 @@ class BaseLayout extends Component {
return (
<div>
<AppBar title="App Publisher"
iconElementRight={
<div>
<Badge
badgeContent={this.state.notifications}
secondary={true}
badgeStyle={{top: 12, right: 12}}
>
<IconButton tooltip="Notifications">
<NotificationsIcon/>
</IconButton>
</Badge>
<IconButton onClick={() => {
console.log("Clicked")
}}>
<ActionAccountCircle/>
<AppBar
title="App Publisher"
iconElementRight={
<div>
<Badge
badgeContent={this.state.notifications}
secondary={true}
badgeStyle={{top: 12, right: 12}}
>
<IconButton tooltip="Notifications">
<NotificationsIcon/>
</IconButton>
</div>
}
</Badge>
<IconButton onClick={() => {
console.log("Clicked")
}}>
<ActionAccountCircle/>
</IconButton>
</div>
}
/>
<div>
<Drawer containerStyle={{height: 'calc(100% - 64px)', width: '15%', top: '10%'}} open={true}>
<List>
<ListItem primaryText="Applications"
leftIcon={<Apps/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handleApplicationClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handleApplicationCreateClick.bind(this)}
leftIcon={<Add/>}
/>]}
<ListItem
primaryText="Applications"
leftIcon={<Apps/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handleApplicationClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handleApplicationCreateClick.bind(this)}
leftIcon={<Add/>}
/>
]}
/>
<ListItem primaryText="Platforms"
leftIcon={<DevicesOther/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handlePlatformClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handlePlatformCreateClick.bind(this)}
leftIcon={<Add/>}
/>]}
<ListItem
primaryText="Platforms"
leftIcon={<DevicesOther/>}
initiallyOpen={false}
primaryTogglesNestedList={true}
onClick={this.handlePlatformClick.bind(this)}
nestedItems={[
<ListItem
key={1}
primaryText="Create"
onClick={this.handlePlatformCreateClick.bind(this)}
leftIcon={<Add/>}
/>
]}
/>
<ListItem
primaryText="Reviews"
onClick={this.handleReviewClick.bind(this)}
leftIcon={<Feedback/>}
/>
<ListItem primaryText="Reviews"
onClick={this.handleReviewClick.bind(this)}
leftIcon={<Feedback/>}/>
</List>
</Drawer>
</div>
<div className="basicLayoutDiv">
{this.props.children}
</div>
</div>);
</div>
);
}
}
BaseLayout.propTypes = {

@ -17,7 +17,6 @@
*/
import PropTypes from 'prop-types';
import Axios from 'axios';
import Chip from 'material-ui/Chip';
import Dropzone from 'react-dropzone';
import React, {Component} from 'react';
@ -34,6 +33,7 @@ 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';
import Theme from '../../theme';
import Endpoint from '../../api/endpoints';
/**
* Platform Create component.
@ -61,6 +61,7 @@ class PlatformCreate extends Component {
description: "",
property: "",
icon: [],
identifier: "",
propertyTypes: [
{key: 0, value: 'String'},
{key: 1, value: 'Number'},
@ -74,7 +75,7 @@ class PlatformCreate extends Component {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
@ -85,7 +86,7 @@ class PlatformCreate extends Component {
* Handles toggle button actions.
* One method is used for all the toggle buttons and, each toggle is identified by the id.
* */
_handleToggle(event) {
handleToggle(event) {
switch (event.target.id) {
case "enabled" : {
let enabled = this.state.enabled;
@ -103,28 +104,28 @@ class PlatformCreate extends Component {
/**
* Triggers the onChange action on property type selection.
* */
_onPropertySelect = (event, index, value) => {
onPropertySelect(event, index, value) {
console.log(this.state.propertyTypes[value]);
this.setState({selectedProperty: value});
};
}
/**
* Handles Chip delete function.
* Removes the tag from state.tags
* */
_handleTagDelete = (key) => {
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});
};
}
/**
* 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) {
addTags(event) {
let tags = this.state.tags;
if (event.charCode === 13) {
event.preventDefault();
@ -136,11 +137,11 @@ class PlatformCreate extends Component {
/**
* Creates Chip array from state.tags.
* */
_renderChip(data) {
renderChip(data) {
return (
<Chip
key={data.key}
onRequestDelete={() => this._handleTagDelete(data.key)}
onRequestDelete={() => this.handleTagDelete(data.key)}
style={this.styles.chip}
>
{data.value}
@ -151,7 +152,7 @@ class PlatformCreate extends Component {
/**
* Set the value for tag.
* */
_handleTagChange(event) {
handleTagChange(event) {
let defaultValue = this.state.defValue;
defaultValue = event.target.value;
this.setState({defValue: defaultValue})
@ -160,7 +161,7 @@ class PlatformCreate extends Component {
/**
* Remove the selected property from the property list.
* */
_removeProperty(property) {
removeProperty(property) {
let properties = this.state.platformProperties;
properties.splice(properties.indexOf(property), 1);
this.setState({platformProperties: properties});
@ -169,28 +170,31 @@ class PlatformCreate extends Component {
/**
* Add a new platform property.
* */
_addProperty() {
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
}]),
this.setState({
platformProperties:
this.state.platformProperties.concat([
{
key: property,
value: this.state.propertyTypes[selected].value
}]),
property: "",
selectedProperty: 0});
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) => {
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": {
@ -210,13 +214,26 @@ class PlatformCreate extends Component {
this.setState({property: property});
break;
}
case "identifier": {
identifier = value;
this.setState({identifier: identifier});
}
}
};
_onCreatePlatform() {
onCreatePlatform() {
//Call the platform create api.
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;
Endpoint.createPlatform(platform);
}
@ -224,22 +241,24 @@ class PlatformCreate extends Component {
/**
* Remove the uploaded icon.
* */
_removeIcon(event) {
removeIcon(event) {
this.setState({icon: []});
}
/**
* Clears the user entered values in the form.
* */
_clearForm() {
this.setState({enabled: true,
clearForm() {
this.setState({
enabled: true,
allTenants: false,
files: [],
platformProperties: [],
selectedProperty: 0,
name: "",
description: "",
property: "",})
property: "",
})
}
render() {
@ -253,24 +272,35 @@ class PlatformCreate extends Component {
tags,
defValue,
description,
property} = this.state;
identifier,
property
} = this.state;
return (
<div className="middle createplatformmiddle">
<Card>
<CardTitle title="Create Platform"/>
<CardActions>
<div className="createplatformcardaction">
<form>
<TextField
hintText="Unique Identifier for Platform."
id="identifier"
floatingLabelText="Identifier*"
floatingLabelFixed={true}
value={identifier}
onChange={this.onTextChange.bind(this)}
/>
<br/>
<TextField
hintText="Enter the Platform Name."
id="name"
floatingLabelText="Name*"
floatingLabelFixed={true}
value={name}
onChange={this._onTextChange.bind(this)}
/><br/>
onChange={this.onTextChange.bind(this)}
/>
<br/>
<TextField
id="description"
hintText="Enter the Platform Description."
@ -279,33 +309,38 @@ class PlatformCreate extends Component {
multiLine={true}
rows={2}
value={description}
onChange={this._onTextChange.bind(this)}
/><br/><br/>
onChange={this.onTextChange.bind(this)}
/>
<br/>
<br/>
<Toggle
id="tenant"
label="Shared with all Tenants"
labelPosition="right"
onToggle={this._handleToggle.bind(this)}
onToggle={this.handleToggle.bind(this)}
toggled={allTenants}
/> <br/>
/>
<br/>
<Toggle
id="enabled"
label="Enabled"
labelPosition="right"
onToggle={this._handleToggle.bind(this)}
onToggle={this.handleToggle.bind(this)}
toggled={enabled}
/> <br/>
/>
<br/>
<TextField
id="tags"
hintText="Enter Platform tags.."
floatingLabelText="Tags*"
floatingLabelFixed={true}
value={defValue}
onChange={this._handleTagChange.bind(this)}
onKeyPress={this._addTags.bind(this)}
/><br/>
onChange={this.handleTagChange.bind(this)}
onKeyPress={this.addTags.bind(this)}
/>
<br/>
<div style={this.styles.wrapper}>
{tags.map(this._renderChip, this)}
{tags.map(this.renderChip, this)}
</div>
<br/>
<div>
@ -313,7 +348,7 @@ class PlatformCreate extends Component {
<div id="property-container">
{platformProperties.map((p) => {
return <div key={p.key}>{p.key} : {p.value}
<IconButton onClick={this._removeProperty.bind(this, p)}>
<IconButton onClick={this.removeProperty.bind(this, p)}>
<Close className="createplatformpropertyclose"/>
</IconButton>
</div>
@ -326,21 +361,21 @@ class PlatformCreate extends Component {
floatingLabelText="Platform Property*"
floatingLabelFixed={true}
value={this.state.property}
onChange={this._onTextChange.bind(this)}
onChange={this.onTextChange.bind(this)}
/> <em/>
<SelectField
className="createplatformpropertyselect"
floatingLabelText="Property Type"
value={selectedProperty}
floatingLabelFixed={true}
onChange={this._onPropertySelect.bind(this)}>
onChange={this.onPropertySelect.bind(this)}>
{propertyTypes.map((type) => {
return <MenuItem key={type.key}
value={type.key}
primaryText={type.value}/>
return <MenuItem key={type.key}
value={type.key}
primaryText={type.value}/>
})}
</SelectField>
<IconButton onClick={this._addProperty.bind(this)}>
<IconButton onClick={this.addProperty.bind(this)}>
<AddCircleOutline/>
</IconButton>
<br/>
@ -350,27 +385,33 @@ class PlatformCreate extends Component {
<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.bind(this)}>
<Clear />
</IconButton>}>
<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 className="createplatformdropzone"
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected})}}>
<Dropzone
className="createplatformdropzone"
accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {
this.setState({icon, rejected})
}}
>
<p className="createplatformdropzonep">+</p>
</Dropzone> : <div />}
</Dropzone> : <div/>}
</GridList>
</div>
<br/>
<RaisedButton primary={true} label="Create"
onClick={this._onCreatePlatform.bind(this)}/>
<FlatButton label="Cancel" onClick={this._clearForm.bind(this)}/>
<RaisedButton
primary={true} label="Create"
onClick={this.onCreatePlatform.bind(this)}/>
<FlatButton label="Cancel" onClick={this.clearForm.bind(this)}/>
</form>
</div>
</CardActions>
@ -380,7 +421,6 @@ class PlatformCreate extends Component {
}
}
PlatformCreate.prototypes = {
};
PlatformCreate.prototypes = {};
export default PlatformCreate;

@ -56,7 +56,7 @@ class PlatformListing extends Component {
* Handles the search action.
* When typing in the search bar, this method will be invoked.
* */
_searchApplications(word) {
searchApplications(word) {
let searchedData = [];
}
@ -64,13 +64,13 @@ class PlatformListing extends Component {
* Handles sort data function and toggles the asc state.
* asc: true : sort in ascending order.
* */
_sortData() {
sortData() {
let isAsc = this.state.asc;
let datas = isAsc?this.data.sort(this._compare):this.data.reverse();
let datas = isAsc ? this.data.sort(this.compare) : this.data.reverse();
this.setState({data: datas, asc: !isAsc});
}
_compare(a, b) {
compare(a, b) {
if (a.applicationName < b.applicationName)
return -1;
if (a.applicationName > b.applicationName)
@ -78,24 +78,25 @@ class PlatformListing extends Component {
return 0;
}
_onRowClick(id) {
onRowClick(id) {
console.log(id)
}
render() {
return (
<div className= 'middle listingplatformmiddle'>
<div className='middle listingplatformmiddle'>
<Card className='listingplatformcard'>
<TextField hintText="Search" onChange={this._searchApplications.bind(this)}
<TextField hintText="Search" onChange={this.searchApplications.bind(this)}
className='listingplatformsearch'/>
<CardTitle title="Platforms" className='listingplatformTitle'/>
<CardActions>
</CardActions>
<DataTable headers={this.headers}
data={this.data}
handleRowClick={this._onRowClick.bind(this)}
noDataMessage={{type: 'button', text: 'Create Platform'}}/>
<DataTable
headers={this.headers}
data={this.data}
handleRowClick={this.onRowClick.bind(this)}
noDataMessage={{type: 'button', text: 'Create Platform'}}/>
</Card>
</div>
);

@ -83,7 +83,7 @@ class DataTable extends Component {
* Triggers when user click on table row.
* This method invokes the parent method handleRowClick, which is passed via props.
* */
_handleRowClick(id) {
handleRowClick(id) {
this.props.handleRowClick(id);
}
@ -100,22 +100,29 @@ class DataTable extends Component {
if (data) {
return (<Table
selectable={ false }>
<TableHeader displaySelectAll={ false }
adjustForCheckbox={ false }>
selectable={false}>
<TableHeader displaySelectAll={false} adjustForCheckbox={false}>
<TableRow>
{headers.map((header) => {
return (<DataTableHeader key={header.data_id} className="datatableRowColumn"
header={header}/>)
}
return (
<DataTableHeader
key={header.data_id}
className="datatableRowColumn"
header={header}
/>
)}
)}
</TableRow>
</TableHeader>
<TableBody>
{data.map((dataItem) =>{
return (<DataTableRow key={dataItem.id}
dataItem={dataItem}
handleClick={this._handleRowClick.bind(this)}/>)
{data.map((dataItem) => {
return (
<DataTableRow
key={dataItem.id}
dataItem={dataItem}
handleClick={this.handleRowClick.bind(this)}
/>
)
})}
</TableBody>
</Table>)

@ -48,7 +48,7 @@ class DataTableHeader extends Component {
* The onClick function of the table header.
* Invokes the function passed in the header object.
* */
_tableHeaderClick() {
tableHeaderClick() {
this.props.header.sort();
}
@ -60,14 +60,18 @@ class DataTableHeader extends Component {
* else create a span element with label as the table header.
* */
if (this.props.header.sortable) {
headerCell = <FlatButton label={this.props.header.label}
onClick={this._tableHeaderClick.bind(this)} className="sortableHeaderCell"/>;
headerCell =
<FlatButton
label={this.props.header.label}
onClick={this.tableHeaderClick.bind(this)}
className="sortableHeaderCell"
/>;
} else {
headerCell = <span className="notsortableHeaderCell">{this.props.header.label}</span>;
}
return (
<TableHeaderColumn key={this.props.header.id} className="datatableHeaderColumn" >
<TableHeaderColumn key={this.props.header.id} className="datatableHeaderColumn">
{headerCell}
</TableHeaderColumn>
);

@ -41,7 +41,7 @@ class DataTableRow extends Component {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
@ -51,24 +51,32 @@ class DataTableRow extends Component {
/**
* Triggers the click event on the data table row.
* */
_handleClick() {
handleClick() {
this.props.handleClick(this.state.dataItem.id);
}
render() {
const {dataItem} = this.state;
return (
<TableRow key={this.props.key} onClick={this._handleClick.bind(this)} >
{Object.keys(dataItem).map((key) => {
if (key !== 'id') {
return <TableRowColumn className = "datatableRowColumn"
key={key}>{dataItem[key]}</TableRowColumn>
} else {
return <TableRowColumn key={key}/>
}
<TableRow
key={this.props.key}
onClick={this.handleClick.bind(this)}
>
{Object.keys(dataItem).map((key) => {
if (key !== 'id') {
return (
<TableRowColumn
className="datatableRowColumn"
key={key}
>
{dataItem[key]}
</TableRowColumn>)
} else {
return <TableRowColumn key={key}/>
}
} )}
</TableRow>
})}
</TableRow>
);
}
}

@ -22,6 +22,7 @@ import React, {Component} from 'react';
import Checkbox from 'material-ui/Checkbox';
import TextField from 'material-ui/TextField';
import {Redirect, Switch} from 'react-router-dom';
import AuthHandler from '../../../api/authHandler';
import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardTitle} from 'material-ui/Card';
@ -65,15 +66,15 @@ class Login extends Component {
// }
}
_handleLogin(event) {
handleLogin(event) {
event.preventDefault();
this._validateForm();
this.validateForm();
}
/**
* Handles the username field change event.
* */
_onUserNameChange(event, value) {
onUserNameChange(event, value) {
this.setState(
{
userName: value
@ -84,7 +85,7 @@ class Login extends Component {
/**
* Handles the password field change event.
* */
_onPasswordChange(event, value) {
onPasswordChange(event, value) {
this.setState(
{
password: value
@ -95,7 +96,7 @@ class Login extends Component {
/**
* Handles the remember me check.
* */
_handleRememberMe() {
handleRememberMe() {
this.setState(
{
rememberMe: !this.state.rememberMe
@ -106,17 +107,32 @@ class Login extends Component {
/**
* Validate the login form.
* */
_validateForm() {
validateForm() {
let errors = {};
let validationFailed = true;
if (!this.state.password) {
errors["passwordError"] = "Password is Required";
validationFailed = true;
} else {
validationFailed = false;
}
if (!this.state.userName) {
errors["userNameError"] = "User Name is Required";
validationFailed = true;
} else {
validationFailed = false;
}
this.setState({errors: errors}, console.log(errors));
if (validationFailed) {
this.setState({errors: errors}, console.log(errors));
} else {
let loginPromis = AuthHandler.login(this.state.userName, this.state.password);
loginPromis.then(response => {
console.log(AuthHandler.getUser());
this.setState({isLoggedIn: AuthHandler.getUser()});
})
}
}
render() {
@ -124,13 +140,12 @@ class Login extends Component {
if (!this.state.isLoggedIn) {
return (
<div>
{/*TODO: Style the components.*/}
<Card>
<CardTitle title="WSO2 IoT App Publisher"/>
<CardActions>
<form onSubmit={this._handleLogin.bind(this)}>
<form onSubmit={this.handleLogin.bind(this)}>
<TextField
hintText="Enter the User Name."
id="username"
@ -138,8 +153,9 @@ class Login extends Component {
floatingLabelText="User Name*"
floatingLabelFixed={true}
value={this.state.userName}
onChange={this._onUserNameChange.bind(this)}
/><br/>
onChange={this.onUserNameChange.bind(this)}
/>
<br/>
<TextField
hintText="Enter the Password."
id="password"
@ -148,11 +164,14 @@ class Login extends Component {
floatingLabelText="Password*"
floatingLabelFixed={true}
value={this.state.password}
onChange={this._onPasswordChange.bind(this)}
/><br/>
<Checkbox label="Remember me."
onCheck={this._handleRememberMe.bind(this)}
checked={this.state.rememberMe}/>
onChange={this.onPasswordChange.bind(this)}
/>
<br/>
<Checkbox
label="Remember me."
onCheck={this.handleRememberMe.bind(this)}
checked={this.state.rememberMe}
/>
<br/>
<RaisedButton type="submit" label="Login"/>
</form>

@ -21,7 +21,6 @@ import NotFound from './Error/NotFound';
import BaseLayout from './Base/BaseLayout';
import PlatformCreate from './Platform/PlatformCreate';
import PlatformListing from './Platform/PlatformListing';
import PublisherOverview from './Overview/PublisherOverview';
import ApplicationCreate from './Application/ApplicationCreate';
import ApplicationListing from './Application/ApplicationListing';
@ -29,5 +28,4 @@ import ApplicationListing from './Application/ApplicationListing';
* Contains all UI components related to Application, Login and Platform
*/
export {Login, BaseLayout, ApplicationCreate, ApplicationListing, PlatformListing, NotFound, PublisherOverview,
PlatformCreate};
export {Login, BaseLayout, ApplicationCreate, ApplicationListing, PlatformListing, NotFound, PlatformCreate};

Loading…
Cancel
Save