Merge pull request #961 from sinthuja/application-mgt

Adding some store UI changes.
feature/appm-store/pbac
sinthuja 7 years ago committed by GitHub
commit 611eb78554

@ -34,32 +34,6 @@
<build>
<plugins>
<plugin>
<groupId>org.wso2.maven</groupId>
<artifactId>carbon-p2-plugin</artifactId>
<version>${carbon.p2.plugin.version}</version>
<executions>
<execution>
<id>4-p2-feature-generation</id>
<phase>package</phase>
<goals>
<goal>p2-feature-gen</goal>
</goals>
<configuration>
<id>org.wso2.carbon.device.application.mgt.store</id>
<propertiesFile>../../etc/feature.properties</propertiesFile>
<adviceFile>
<properties>
<propertyDef>org.wso2.carbon.p2.category.type:server
</propertyDef>
<propertyDef>org.eclipse.equinox.p2.type.group:false
</propertyDef>
</properties>
</adviceFile>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
@ -86,7 +60,7 @@
</goals>
<phase>compile</phase>
<configuration>
<workingDirectory>${basedir}/src/main/resources/publisher</workingDirectory>
<workingDirectory>${basedir}/src/main/resources/store</workingDirectory>
<executable>${npm.executable}</executable>
<arguments>
<argument>run</argument>

@ -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 "
}
}

@ -0,0 +1,115 @@
/*
* 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, Redirect, 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);
} else {
let customTheme = require("./themes/" + theme.custom);
muiTheme = getMuiTheme(customTheme.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 {
constructor() {
super();
this.state = {};
}
render() {
this.setState();
return (
<div className="container">
<BaseLayout state={this.state}>
<Switch>
<Route component={NotFound}/>
</Switch>
</BaseLayout>
</div>
)
}
setState() {
if (this.props.location.state){
this.state = this.props.location.state;
} else {
this.state = {};
}
}
}
/**
* 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();
}
render() {
return (
<div className="App">
<MuiThemeProvider muiTheme={muiTheme}>
<Router basename="store" history={history}>
<Switch>
<Route path="/login" component={Login}/>
<Route path="/logout" component={Login}/>
<Route component={Base}/>
</Switch>
</Router>
</MuiThemeProvider>
</div>
);
}
}
export default Store;

@ -0,0 +1,144 @@
/*
* 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 } from 'react-router-dom';
/**
* Base Layout:
* App bar
* Left Navigation
* Middle content.
* */
class BaseLayout extends Component {
constructor(props) {
super(props);
this.state = this.props.state;
}
componentWillMount() {
}
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.state.user) {
return (
<IconButton tooltip={this.state.user}>
<ActionAccountCircle/>
</IconButton>
);
} else {
return (
<Link to='/login'> Login</Link>
);
}
}
handleNotification() {
if (this.state.user) {
return (
<Badge
badgeContent={this.state.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
BaseLayout;

@ -0,0 +1,164 @@
/*
* 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();
//TODO: send authentication request.
let location = {
pathname: this.state.referrer,
state: {
notifications: 0,
user: this.state.userName
}
};
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,51 @@
body {
font: 14px "Century Gothic", Futura, sans-serif;
margin: 20px;
}
ol, ul {
padding-left: 30px;
}
.board-row:after {
clear: both;
content: "";
display: table;
}
.status {
margin-bottom: 10px;
}
.square {
background: #fff;
border: 1px solid #999;
float: left;
font-size: 24px;
font-weight: bold;
line-height: 34px;
height: 34px;
margin-right: -1px;
margin-top: -1px;
padding: 0;
text-align: center;
width: 34px;
}
.square:focus {
outline: none;
}
.kbd-navigation .square:focus {
background: #ddd;
}
.game {
display: flex;
flex-direction: row;
}
.game-info {
margin-left: 20px;
}

@ -0,0 +1,8 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Store from './App';
import './index.css';
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…
Cancel
Save