forked from community/device-mgt-core
commit
ddbaa0e6b0
@ -0,0 +1,49 @@
|
||||
{
|
||||
"name": "store",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"axios": "^0.16.2",
|
||||
"flux": "^3.1.3",
|
||||
"history": "^4.6.3",
|
||||
"latest-version": "^3.1.0",
|
||||
"material-ui": "^0.19.0",
|
||||
"prop-types": "^15.5.10",
|
||||
"qs": "^6.5.0",
|
||||
"react": "^15.6.1",
|
||||
"react-dom": "^15.6.1",
|
||||
"react-dropzone": "^4.1.0",
|
||||
"react-images-uploader": "^1.1.0",
|
||||
"react-material-ui-form-validator": "^0.5.0",
|
||||
"react-modal": "^2.2.2",
|
||||
"react-router": "^4.1.2",
|
||||
"react-router-dom": "^4.1.2",
|
||||
"react-scripts": "1.0.10",
|
||||
"react-sliding-pane": "^1.2.3",
|
||||
"react-tap-event-plugin": "^2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.24.1",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-plugin-transform-class-properties": "^6.24.1",
|
||||
"babel-preset-es2015": "^6.24.1",
|
||||
"babel-preset-react": "^6.24.1",
|
||||
"babel-register": "^6.24.1",
|
||||
"chai": "^4.0.2",
|
||||
"css-loader": "^0.28.7",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.4",
|
||||
"mocha": "^3.4.1",
|
||||
"mock-local-storage": "^1.0.2",
|
||||
"style-loader": "^0.18.1",
|
||||
"webpack": "^2.7.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
"build": "react-scripts build",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject",
|
||||
"build_prod": "NODE_ENV=production webpack -p --progress --colors --config webpack.config.js",
|
||||
"build_dev": "NODE_ENV=development webpack -d --config webpack.config.js --watch "
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 3.8 KiB |
@ -0,0 +1,40 @@
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
||||
<meta name="theme-color" content="#000000">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
Only files inside the `public` folder can be referenced from the HTML.
|
||||
|
||||
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
<title>React App</title>
|
||||
</head>
|
||||
<body>
|
||||
<noscript>
|
||||
You need to enable JavaScript to run this app.
|
||||
</noscript>
|
||||
<div id="root"></div>
|
||||
<!--
|
||||
This HTML file is a template.
|
||||
If you open it directly in the browser, you will see an empty page.
|
||||
|
||||
You can add webfonts, meta tags, or analytics to this file.
|
||||
The build step will place the bundled scripts into the <body> tag.
|
||||
|
||||
To begin the development, run `npm start` or `yarn start`.
|
||||
To create a production bundle, use `npm run build` or `yarn build`.
|
||||
-->
|
||||
</body>
|
||||
</html>
|
@ -0,0 +1,15 @@
|
||||
{
|
||||
"short_name": "React App",
|
||||
"name": "Create React App Sample",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#000000",
|
||||
"background_color": "#ffffff"
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import React, {Component} from 'react';
|
||||
import createHistory from 'history/createBrowserHistory';
|
||||
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom'
|
||||
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider';
|
||||
import getMuiTheme from 'material-ui/styles/getMuiTheme';
|
||||
import Login from './components/Login';
|
||||
import BaseLayout from './components/BaseLayout';
|
||||
import NotFound from './components/NotFound';
|
||||
|
||||
const history = createHistory({basename: '/store'});
|
||||
|
||||
/**
|
||||
* User can define the themes in the config.json. The themes will be loaded based on the user preference.
|
||||
*/
|
||||
const theme = require("./config.json").theme;
|
||||
//
|
||||
let muiTheme = null;
|
||||
if (theme.current === "default") {
|
||||
let defaultTheme = require("material-ui/styles/baseThemes/" + theme.default);
|
||||
muiTheme = getMuiTheme(defaultTheme.default);
|
||||
}
|
||||
|
||||
/**
|
||||
* This component defines the layout and the routes for the app.
|
||||
* All the content will be loaded inside the Base component.
|
||||
* The base component includes the Core layout and the routers according to which the content will be displayed.
|
||||
*
|
||||
* The Router and Route components.
|
||||
* The Router and Route is used for navigation.
|
||||
* We specify the component which needs to be rendered for an URL.
|
||||
* Ex: When navigate to publisher/overview, the overview component will be rendered inside the main layout.
|
||||
*
|
||||
* HashRouter is used because the other router types need the server to serve those urls. In hashRouter, server does
|
||||
* not want to serve the URL.
|
||||
* */
|
||||
class Base extends Component {
|
||||
render() {
|
||||
return (
|
||||
<div className="container">
|
||||
<BaseLayout state={this.props.state} updateState={this.props.updateState}>
|
||||
<Switch>
|
||||
<Route component={NotFound}/>
|
||||
</Switch>
|
||||
</BaseLayout>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Base.propTypes = {
|
||||
updateState: React.PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
/**
|
||||
* This component is referred by the index.js to initiate the application.
|
||||
* TODO: Currently the URL shows like https://localhost:9443/publisher/#/publisher/assets/apps/create. this needs to
|
||||
* be fixed as https://localhost:9443/publisher/#/assets/apps/create
|
||||
*
|
||||
* */
|
||||
class Store extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
if (!this.state) {
|
||||
this.state = {};
|
||||
this.state.store = {};
|
||||
}
|
||||
this.updateState = this.updateState.bind(this);
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="App">
|
||||
<MuiThemeProvider muiTheme={muiTheme}>
|
||||
<Router basename="store" history={history}>
|
||||
<Switch>
|
||||
<Route path="/login"
|
||||
render={routeProps => <Login {...routeProps} updateState={this.updateState} state={this.state}/>}/>
|
||||
<Route path="/logout"
|
||||
render={routeProps => <Base {...routeProps} updateState={this.updateState} state={this.state}/>}/>
|
||||
<Route
|
||||
render={routeProps => <Base {...routeProps} updateState={this.updateState} state={this.state}/>}/>
|
||||
</Switch>
|
||||
</Router>
|
||||
</MuiThemeProvider>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
updateState(data) {
|
||||
this.setState(data);
|
||||
}
|
||||
}
|
||||
|
||||
export default Store;
|
@ -0,0 +1,132 @@
|
||||
/*
|
||||
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import PropTypes from 'prop-types';
|
||||
import Badge from 'material-ui/Badge';
|
||||
import React, {Component} from 'react';
|
||||
import AppBar from 'material-ui/AppBar';
|
||||
import Drawer from 'material-ui/Drawer';
|
||||
import IconButton from 'material-ui/IconButton';
|
||||
import {List, ListItem} from 'material-ui/List';
|
||||
import Apps from 'material-ui/svg-icons/navigation/apps';
|
||||
import NotificationsIcon from 'material-ui/svg-icons/social/notifications';
|
||||
import ActionAccountCircle from 'material-ui/svg-icons/action/account-circle';
|
||||
import {Link, withRouter} from 'react-router-dom';
|
||||
|
||||
/**
|
||||
* Base Layout:
|
||||
* App bar
|
||||
* Left Navigation
|
||||
* Middle content.
|
||||
* */
|
||||
class BaseLayout extends Component {
|
||||
|
||||
handleApplicationClick() {
|
||||
this.handleHistory('/assets/apps');
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The method to update the history.
|
||||
* to: The URL to route.
|
||||
* */
|
||||
handleHistory(to) {
|
||||
this.props.history.push(to);
|
||||
}
|
||||
|
||||
handleUserLogin() {
|
||||
if (this.props.state.store.user) {
|
||||
return (
|
||||
<IconButton tooltip={this.props.state.store.user}>
|
||||
<ActionAccountCircle/>
|
||||
</IconButton>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Link to='/login'> Login</Link>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
handleNotification() {
|
||||
if (this.props.state.store.user) {
|
||||
return (
|
||||
<Badge
|
||||
badgeContent={this.props.state.store.notifications}
|
||||
secondary={true}
|
||||
badgeStyle={{top: 12, right: 12}}>
|
||||
<IconButton tooltip="Notifications">
|
||||
<NotificationsIcon/>
|
||||
</IconButton>
|
||||
</Badge>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
<AppBar title="App Store"
|
||||
iconElementRight={
|
||||
<div>
|
||||
{this.handleNotification()}
|
||||
{this.handleUserLogin()}
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<div>
|
||||
<Drawer containerStyle={{height: 'calc(100% - 64px)', width: '15%', top: '13%', left: '1%'}}
|
||||
open={true}>
|
||||
<List>
|
||||
<ListItem primaryText="Applications"
|
||||
leftIcon={<Apps/>}
|
||||
initiallyOpen={false}
|
||||
primaryTogglesNestedList={true}
|
||||
onClick={this.handleApplicationClick.bind(this)}
|
||||
nestedItems={[
|
||||
<ListItem
|
||||
key={1}
|
||||
primaryText="Business" //TODO: categoryies ...
|
||||
leftIcon={<List/>}
|
||||
/>]}
|
||||
/>
|
||||
</List>
|
||||
</Drawer>
|
||||
</div>
|
||||
<div style=
|
||||
{
|
||||
{
|
||||
height: 'calc(100% - 64px)',
|
||||
marginLeft: '16%',
|
||||
width: 'calc(100%-15%)',
|
||||
top: 64,
|
||||
left: "-100px"
|
||||
}
|
||||
}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
BaseLayout.propTypes = {
|
||||
children: PropTypes.element
|
||||
};
|
||||
|
||||
export default withRouter(BaseLayout);
|
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
|
||||
import qs from 'qs';
|
||||
import React, {Component} from 'react';
|
||||
import Checkbox from 'material-ui/Checkbox';
|
||||
import {Redirect, Route} from 'react-router-dom';
|
||||
import RaisedButton from 'material-ui/RaisedButton';
|
||||
import {Card, CardActions, CardTitle} from 'material-ui/Card';
|
||||
import {TextValidator, ValidatorForm} from 'react-material-ui-form-validator';
|
||||
import Store from '../App';
|
||||
|
||||
|
||||
//todo: remove the {TextValidator, ValidatorForm} and implement it manually.
|
||||
|
||||
|
||||
/**
|
||||
* The Login Component.
|
||||
*
|
||||
* This component contains the Login form and methods to handle field change events.
|
||||
* The user name and password will be set to the state and sent to the api.
|
||||
*
|
||||
* If the user is already logged in, it will redirect to the last point where the user was.
|
||||
* */
|
||||
class Login extends Component {
|
||||
constructor() {
|
||||
super();
|
||||
this.state = {
|
||||
isLoggedIn: false,
|
||||
referrer: "/",
|
||||
userName: "",
|
||||
rememberMe: true
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
let queryString = this.props.location.search;
|
||||
console.log(queryString);
|
||||
queryString = queryString.replace(/^\?/, '');
|
||||
/* With QS version up we can directly use {ignoreQueryPrefix: true} option */
|
||||
let params = qs.parse(queryString);
|
||||
if (params.referrer) {
|
||||
this.setState({referrer: params.referrer});
|
||||
}
|
||||
}
|
||||
|
||||
handleLogin(event) {
|
||||
event.preventDefault();
|
||||
console.log(this.props);
|
||||
//TODO: send authentication request.
|
||||
let location = {
|
||||
pathname: this.state.referrer
|
||||
};
|
||||
let storeState = {
|
||||
store : {
|
||||
user: this.state.userName,
|
||||
notifications: 0
|
||||
}
|
||||
};
|
||||
this.props.updateState(storeState);
|
||||
this.props.history.push(location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the username field change event.
|
||||
* */
|
||||
onUserNameChange(event) {
|
||||
this.setState(
|
||||
{
|
||||
userName: event.target.value
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the password field change event.
|
||||
* */
|
||||
onPasswordChange(event) {
|
||||
this.setState(
|
||||
{
|
||||
password: event.target.value
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the remember me check.
|
||||
* */
|
||||
handleRememberMe() {
|
||||
this.setState(
|
||||
{
|
||||
rememberMe: !this.state.rememberMe
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
handleSuccessfulLogin() {
|
||||
return (
|
||||
<Redirect to='/store'/>
|
||||
);
|
||||
}
|
||||
|
||||
render() {
|
||||
if (!(this.state.isLoggedIn && this.state.userName)) {
|
||||
return (
|
||||
<div>
|
||||
|
||||
{/*TODO: Style the components.*/}
|
||||
|
||||
<Card>
|
||||
<CardTitle title="WSO2 IoT App Store"/>
|
||||
<CardActions>
|
||||
<ValidatorForm
|
||||
ref="form"
|
||||
onSubmit={this.handleLogin.bind(this)}
|
||||
onError={errors => console.log(errors)}>
|
||||
<TextValidator
|
||||
floatingLabelText="User Name"
|
||||
floatingLabelFixed={true}
|
||||
onChange={this.onUserNameChange.bind(this)}
|
||||
name="userName"
|
||||
validators={['required']}
|
||||
errorMessages={['User Name is required']}
|
||||
value={this.state.userName}
|
||||
/>
|
||||
<br/>
|
||||
<TextValidator
|
||||
floatingLabelText="Password"
|
||||
floatingLabelFixed={true}
|
||||
onChange={this.onPasswordChange.bind(this)}
|
||||
name="password"
|
||||
type="password"
|
||||
value={this.state.password}
|
||||
validators={['required']}
|
||||
errorMessages={['Password is required']}
|
||||
/>
|
||||
<br/>
|
||||
<Checkbox label="Remember me."
|
||||
onCheck={this.handleRememberMe.bind(this)}
|
||||
checked={this.state.rememberMe}/>
|
||||
<br/>
|
||||
<RaisedButton type="submit" label="Login"/>
|
||||
</ValidatorForm>
|
||||
</CardActions>
|
||||
</Card>
|
||||
</div>);
|
||||
} else {
|
||||
this.handleSuccessfulLogin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Login;
|
@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (c) 2017, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
|
||||
*
|
||||
* WSO2 Inc. licenses this file to you under the Apache License,
|
||||
* Version 2.0 (the "License"); you may not use this file except
|
||||
* in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
import React, {Component} from 'react';
|
||||
|
||||
/**
|
||||
* Error page.
|
||||
* */
|
||||
class Error extends Component {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div>
|
||||
404 not found
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Error;
|
@ -0,0 +1,7 @@
|
||||
{
|
||||
"theme" : {
|
||||
"current" : "default",
|
||||
"default" : "lightBaseTheme",
|
||||
"custom" : "custom-theme"
|
||||
}
|
||||
}
|
@ -0,0 +1,6 @@
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Store from './App';
|
||||
|
||||
ReactDOM.render(<Store />, document.getElementById('root'));
|
||||
|
@ -0,0 +1,72 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
var webpack = require('webpack');
|
||||
var path = require('path');
|
||||
|
||||
var BUILD_DIR = path.resolve(__dirname, 'public/dist');
|
||||
var APP_DIR = path.resolve(__dirname, 'src');
|
||||
|
||||
const config = {
|
||||
entry: {
|
||||
index: APP_DIR+ '/index.js'
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, BUILD_DIR),
|
||||
filename: 'index.js'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['*', '.jsx', '.js']
|
||||
},
|
||||
devtool: "source-map",
|
||||
plugins: [],
|
||||
watch: false,
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.(js|jsx)$/,
|
||||
include: APP_DIR,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
presets: ['es2015', 'react'],
|
||||
plugins: ['transform-class-properties']
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ['style-loader', 'css-loader']
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: [{
|
||||
loader: "style-loader" // creates style nodes from JS strings
|
||||
}, {
|
||||
loader: "css-loader" // translates CSS into CommonJS
|
||||
}, {
|
||||
loader: "less-loader" // compiles Less to CSS
|
||||
}]
|
||||
}
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = config;
|
Loading…
Reference in new issue