Added responsive styling.

feature/appm-store/pbac
Menaka Jayawardena 7 years ago
parent 55f3b4d0ee
commit b3bd70ad61

1
.gitignore vendored

@ -26,3 +26,4 @@ target
hs_err_pid*
components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/node_modules/
components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/build/
components/application-mgt/org.wso2.carbon.device.application.mgt.publisher.ui/src/main/resources/publisher/package-lock.json

@ -22,7 +22,29 @@ package org.wso2.carbon.device.application.mgt.auth.handler.util;
public class Constants {
public static final String 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 perm:platform:get";
"perm:roles:view perm:devices:view perm:platform:get perm:admin:devices:view perm:roles:add " +
"perm:roles:add-users perm:roles:update perm:roles:permissions perm:roles:details perm:roles:view" +
" perm:roles:create-combined-role perm:roles:delete perm:dashboard:vulnerabilities " +
"perm:dashboard:non-compliant-count perm:dashboard:non-compliant perm:dashboard:by-groups " +
"perm:dashboard:device-counts perm:dashboard:feature-non-compliant perm:dashboard:count-overview " +
"perm:dashboard:filtered-count perm:dashboard:details perm:get-activity perm:devices:delete " +
"perm:devices:applications perm:devices:effective-policy perm:devices:compliance-data " +
"perm:devices:features perm:devices:operations perm:devices:search perm:devices:details " +
"perm:devices:update perm:devices:view perm:view-configuration perm:manage-configuration " +
"perm:policies:remove perm:policies:priorities perm:policies:deactivate perm:policies:get-policy-details" +
" perm:policies:manage perm:policies:activate perm:policies:update perm:policies:changes " +
"perm:policies:get-details perm:users:add perm:users:details perm:users:count perm:users:delete " +
"perm:users:roles perm:users:user-details perm:users:credentials perm:users:search perm:users:is-exist " +
"perm:users:update perm:users:send-invitation perm:admin-users:view perm:groups:devices perm:groups:update " +
"perm:groups:add perm:groups:device perm:groups:devices-count perm:groups:remove perm:groups:groups " +
"perm:groups:groups-view perm:groups:share perm:groups:count perm:groups:roles perm:groups:devices-remove " +
"perm:groups:devices-add perm:groups:assign perm:device-types:features perm:device-types:types " +
"perm:applications:install perm:applications:uninstall perm:admin-groups:count perm:admin-groups:view" +
" perm:notifications:mark-checked perm:notifications:view perm:admin:certificates:delete " +
"perm:admin:certificates:details perm:admin:certificates:view perm:admin:certificates:add " +
"perm:admin:certificates:verify perm:admin perm:devicetype:deployment perm:device-types:events " +
"perm:device-types:events:view perm:admin:device-type perm:device:enroll perm:geo-service:analytics-view " +
"perm:geo-service:alerts-manage";
public static final String[] TAGS = {"device_management"};
public static final String USER_NAME = "userName";

@ -23,6 +23,7 @@
<meta name="theme-color" content="#000000">
<link rel="stylesheet" type="text/css" href="/css/font-wso2.css">
<link rel="stylesheet" type="text/css" href="/themes/default/default-theme.css">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
<!--
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/

@ -16,10 +16,46 @@
* under the License.
*/
@font-face {
font-family: "Roboto-Medium";
src: url('../../fonts/Roboto-Medium.woff');
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.ttf") format("ttf");
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.woff") format("woff");
src: local("Roboto-Medium"), url("../../fonts/Roboto-Medium.woff2") format("woff2");
}
@font-face {
font-family: "Roboto-Regular";
src: url("../../fonts/Roboto-Regular.woff");
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.ttf") format("ttf");
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.woff") format("woff");
src: local("Roboto-Regular"), url("../../fonts/Roboto-Regular.woff2") format("woff2");
}
/* Body Styling */
body {
width: 100%;
font-family: Roboto sans-serif;
font-family: "Roboto-Regular" !important;
background-color: #dfdfdf !important;
}
.app-manager-title {
font-family: "Roboto-Medium";
font-size: 20px;
}
.app-manager-sub-title {
font-family: "Roboto-Regular";
font-size: 18px;
}
#app-mgt-footer {
clear: both;
position: relative;
height: 50px;
width: 100%;
color: white;
background-color: #334d88;
}
/* Login page styles*/
@ -53,16 +89,16 @@ body {
/* Base layout container */
#container {
background-color: #ffffff;
background-color: #ededed;
padding: 0;
}
/* Base layout header content*/
#header-content {
height: 125px;
height: 128px;
width: 100%;
margin: 0 10px 0 0;
background-color: #3b33bd;
background-color: #3f50b5;
position: fixed; /* Set the navbar to fixed position */
top: 0; /* Position the navbar at the top of the page */
z-index: 2;
@ -71,14 +107,15 @@ body {
/* Contains the header styles.*/
#header {
margin: 16px 16px 20px 16px;
height: 100%;
padding: 24px;
/*margin: 16px 16px 20px 16px;*/
position: relative;
}
#header-text {
color: #ffffff;
font-size: 25px;
font-size: 20px;
font-family: Roboto-Medium;
top: 10px;
margin-left: 10px;
}
@ -96,6 +133,7 @@ body {
width: 50px;
margin-right: 10px;
position: relative;
outline: none;
}
#header-button:hover {
@ -109,16 +147,20 @@ body {
left: 17px;
}
#header-button {
outline: none;
}
.btn-header {
margin-top: 15px;
margin-right: 20px;
color: white;
}
#sub-title {
font-family: Roboto-Regular;
font-size: 18px;
padding-top: 5px;
padding-left: 18px;
color: RGBA(0, 0, 0, 1);
}
/* Search box styles */
.search-icon {
position: absolute;
@ -151,22 +193,31 @@ body {
/* Application Add button */
#add-btn-container {
position: absolute;
left: 11%;
top: 100px;
top: 98px;
}
#app-main-content {
margin-top: 140px;
max-width: 98%;
margin: 0 auto;
}
#sub-title-container {
height: 100px;
padding: 50px 0 20px 0;
}
.application-container {
padding: 0 !important;
min-height: 100% !important;
margin-top: 128px !important;
}
/* Holds the app publisher pages. */
#application-content {
height: auto;
width: 80%;
margin: 20px auto;
background-color: white;
width: 100%;
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
padding: 0 10px 10px 10px;
padding: 24px;
}
.stepper-header {
@ -176,11 +227,20 @@ body {
margin-bottom: 10px;
}
#application-tag {
margin: 0 2px 0 2px;
background-color: blue;
height: 20px;
}
#application-tag:hover {
cursor: pointer;
background-color: #007bff;
}
.platform-link-placeholder {
color: #888888;
width: 80%;
float: right;
margin: 10px auto;
padding-bottom: 10px;
}
@ -276,7 +336,6 @@ body {
}
#secondary-button {
float: right;
color: #979797;
background-color: transparent;
border: none;
@ -343,6 +402,7 @@ body {
#application-view-content {
width: 100%;
}
#application-view-row {
margin: 10px 10px 0 20px;
}
@ -386,6 +446,7 @@ body {
margin-bottom: 20px;
font-size: 25px;
}
.application-header-text {
margin: 10px 0px 0px 10px;
}
@ -417,6 +478,7 @@ div.tab {
border-right: 1px solid #d8d8d8;
height: 100%;
}
/* Style the tab buttons */
div.tab button {
@ -431,31 +493,27 @@ div.tab button {
cursor: pointer;
transition: 0.3s;
}
/* Change background color of buttons on hover */
div.tab button:hover {
background-color: #ddd6d7;
cursor: pointer;
}
/* Create an active/current "tab button" class */
div.tab button.active {
background-color: #1b3bcc;
color: white;
}
#application-edit-main-container {
display: flex;
}
#application-edit-outer-content {
height: auto;
width: 100%;
}
#application-edit-content {
margin: 5px 10px 5px 10px;
width: 90%;
}
#app-edit-content {
@ -486,6 +544,7 @@ div.tab button.active {
margin-top: 20px;
margin-bottom: 20px;
}
.release-create {
height: 150px;
margin-bottom: 20px;
@ -540,6 +599,7 @@ div.tab button.active {
margin-top: 20px;
max-width: 100%;
}
.save-info {
float: right;
margin-bottom: 10px;
@ -550,8 +610,8 @@ div.tab button.active {
margin: 10px;
}
.create-platform {
padding-left: 90%;
.create-platform i {
margin-right: 10px;
}
#platform-list {

@ -35,8 +35,8 @@ export default class ApplicationMgtApi {
*
* From applicationData, the proper application object will be created and send it to the api.
* */
static createApplication(applicationData) {
let {application, images} = Helper.buildApplication(applicationData);
static createApplication(generalInfo, platform, screenshots, release) {
let {application, images} = Helper.buildApplication(generalInfo, platform, screenshots, release);
const headers = AuthHandler.createAuthenticationHeaders("application/json");
console.log(application);
console.log(images);

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

@ -35,13 +35,16 @@ class BaseLayout extends Component {
constructor() {
super();
this.logout = this.logout.bind(this);
this.closeModal = this.closeModal.bind(this);
this.onClickPlatforms = this.onClickPlatforms.bind(this);
this.state = {
notifications: 0,
user: 'Admin',
openModal: false
openModal: false,
currentPage: "Applications"
};
this.logout = this.logout.bind(this);
this.closeModal = this.closeModal.bind(this);
}
handleApplicationClick() {
@ -71,46 +74,58 @@ class BaseLayout extends Component {
}
onClickPlatforms() {
window.location.href = "/assets/platforms";
window.location.href = "/publisher/assets/platforms";
this.setState({currentPage: "Platforms"});
}
render() {
return (
<div>
<div id="header-content">
<div id="header">
<div id="header">
<span id="header-text">
WSO2 IoT <FormattedMessage id="App.Publisher" defaultMessage="Application Publisher"/>
</span>
<div id="header-btn-container">
<Button id="header-button"><i className="fw fw-notification btn-header"></i></Button>
<Button id="header-button"><i className="fw fw-user btn-header"></i></Button>
<div id="header-btn-container">
<Button id="header-button"><i className="fw fw-notification btn-header"></i></Button>
<Button id="header-button"><i className="fw fw-user btn-header"></i></Button>
</div>
<div id="search-box">
<i className="fw fw-search search-icon">
</i>
<Input
id="search"
name="search"
placeholder={'Search for Applications'}
onChange={(event) => console.log(event.target.value)} //TODO: Remove this
/>
</div>
</div>
<div id="search-box">
<i className="fw fw-search search-icon">
</i>
<Input
id="search"
name="search"
placeholder={'Search for Applications'}
onChange={(event) => console.log(event.target.value)} //TODO: Remove this
<Container>
<div id="add-btn-container">
<FloatingButton
className="add-btn small"
onClick={this.handleApplicationCreateClick.bind(this)}
/>
</div>
</div>
<div id="add-btn-container">
<FloatingButton
className="add-btn small"
onClick={this.handleApplicationCreateClick.bind(this)}
/>
</div>
</Container>
</div>
<Container fluid>
<div id="app-main-content" style={this.state.style}>
<Row>
<div className="platform-link-placeholder">
<Button id="secondary-button" onClick={this.onClickPlatforms}>
<i className="fw fw-settings"></i> Platforms</Button>
</div>
<Container className="application-container">
<div id="app-main-content">
<Row id="sub-title-container">
<Col>
<div id="sub-title">
{this.state.currentPage}
</div>
</Col>
<Col>
<div className="platform-link-placeholder">
<Button id="secondary-button" onClick={this.onClickPlatforms}>
<i className="fw fw-settings"></i> Platforms</Button>
</div>
</Col>
</Row>
<Row>
<div id="application-content">

@ -24,6 +24,7 @@ import ApplicationMgtApi from '../../../api/applicationMgtApi';
import {Col, Modal, ModalBody, ModalHeader, Row} from 'reactstrap';
import {FormattedMessage} from 'react-intl';
/**
* The App Create Component.
*
@ -88,8 +89,8 @@ class ApplicationCreate extends Component {
* Handles form submit.
* */
onSubmit() {
let stepData = this.state.stepData;
let applicationCreationPromise = ApplicationMgtApi.createApplication(stepData);
let {generalInfo, platform, screenshots, release} = this.state;
let applicationCreationPromise = ApplicationMgtApi.createApplication(generalInfo, platform, screenshots, release);
applicationCreationPromise.then(response => {
this.handleYes();
}
@ -217,7 +218,7 @@ class ApplicationCreate extends Component {
<Step4
defaultData={this.state.release}
handlePrev={this.onPrevClick}
setStepData={this.setStepData}
onSubmit={this.onSubmit}
close={this.onClose}
/>
)

@ -55,9 +55,10 @@ class Step1 extends Component {
name: "",
errors: {},
defValue: "",
category: 0,
visibility: "",
description: ""
category: {},
visibility: {type: "PUBLIC", allowedList: []},
description: "",
shortDescription: ""
};
}
@ -108,12 +109,14 @@ class Step1 extends Component {
* Creates an object with the current step data and persist in the parent.
* */
setStepData() {
const {name, description, tags, visibility} = this.state;
const {name, description, tags, visibility, shortDescription} = this.state;
let stepData = {
name: name,
description: description,
tags: tags,
visibility: visibility
visibility: visibility,
shortDescription: shortDescription,
category: {id: 1, name: "business"}
};
let {errorCount, errors} = this.validate();
@ -133,7 +136,7 @@ class Step1 extends Component {
* Validate the form fields.
* */
validate() {
const {name, description, tags} = this.state;
const {name, description, tags, shortDescription} = this.state;
let errorCount = 0;
let errors = {};
if (validator.validateNull(name)) {
@ -146,6 +149,11 @@ class Step1 extends Component {
errors.description = "Description is Required!"
}
if (validator.validateNull(shortDescription)) {
errorCount++;
errors.shortDescription = "Short Description is Required!"
}
if (!validator.validateEmpty(tags)) {
errorCount++;
errors.tags = "You need to enter at least one tag!"
@ -167,6 +175,9 @@ class Step1 extends Component {
this.setState({description: event.target.value});
break;
}
case "appShortDescription": {
this.setState({shortDescription: event.target.value});
}
}
};
@ -240,6 +251,18 @@ class Step1 extends Component {
/>
<FormFeedback id="form-error">{this.state.errors.name}</FormFeedback>
</FormGroup>
<FormGroup>
<Label for="app-short-description">Short Description*</Label>
<Input
required
type="textarea"
name="appShortDescription"
id="app-short-description"
value={this.state.shortDescription}
onChange={this.onTextFieldChange}
/>
<FormFeedback id="form-error">{this.state.errors.shortDescription}</FormFeedback>
</FormGroup>
<FormGroup>
<Label for="app-description">
<FormattedMessage id='Description' defaultMessage='Description'/>*
@ -258,8 +281,12 @@ class Step1 extends Component {
<Label for="app-category">
<FormattedMessage id='Category' defaultMessage='Category'/>
</Label>
<Input type="select" name="category" id="app-category">
<option>Business</option>
<Input
type="select"
name="category"
id="app-category"
>
<option key={0} value={{id: 0, name: "business"}}>Business</option>
</Input>
</FormGroup>
<FormGroup>
@ -302,7 +329,7 @@ class Step1 extends Component {
{this.state.tags.map(tag => {
return (
<Badge
style={{margin: '0 2px 0 2px', backgroundColor: 'blue', height: '20px'}}
id="application-tag"
value={tag.key}
key={tag.key}
onClick={() => this.handleRequestDelete(tag.key)}
@ -318,7 +345,7 @@ class Step1 extends Component {
</div>
</div>
<ModalFooter>
<Button color="danger" onClick={this.onCancelClick}>Cancel</Button>
<Button id="material-btn" onClick={this.onCancelClick}>Cancel</Button>
<Button color="primary" onClick={this.setStepData}>Continue</Button>
</ModalFooter>
</div>

@ -50,6 +50,7 @@ class Step4 extends Component {
this.onCancelClick = this.onCancelClick.bind(this);
this.onBackClick = this.onBackClick.bind(this);
this.handleFinish = this.handleFinish.bind(this);
this.onSubmit = this.onSubmit.bind(this);
this.state = {
showForm: false,
releaseChannel: 1,
@ -75,7 +76,7 @@ class Step4 extends Component {
}
onSubmit() {
this.props.onSubmit();
}
/**
@ -159,7 +160,7 @@ Step4.propTypes = {
handleFinish: PropTypes.func,
handlePrev: PropTypes.func,
setData: PropTypes.func,
removeData: PropTypes.func
onSubmit: PropTypes.func
};
export default Step4;

@ -105,17 +105,9 @@ class ApplicationEdit extends Component {
</div>
</Col>
<Col xs="9">
<div id="app-edit-content">
<Row>
<Col xs="12">
<div id="application-edit-outer-content">
{/* Application edit content */}
<div id="application-edit-content">
{this.getTabContent(this.state.activeTab)}
</div>
</div>
</Col>
</Row>
{/* Application edit content */}
<div id="application-edit-content">
{this.getTabContent(this.state.activeTab)}
</div>
</Col>
</Row>

@ -102,12 +102,14 @@ class GeneralInfo extends Component {
<span className="image-sub-title"> (600 X 800 32 bit PNG)</span>
<div id="screenshot-container">
{this.state.screenshots.map((tile) => (
<button id="img-btn-screenshot" style={{height: '210px', width: '410px'}}
<button id="img-btn-screenshot"
style={{height: '210px', width: '410px'}}
onMouseEnter={() => {
console.log("Mouse Entered")
}}>
{console.log(tile[0].preview)}
<img style={{height: '200px', width: '400px'}} src={tile[0].preview}/>
<img style={{height: '200px', width: '400px'}}
src={tile[0].preview}/>
</button>
))}
{this.state.screenshots.length < 3 ?
@ -140,7 +142,8 @@ class GeneralInfo extends Component {
<button onMouseEnter={() => {
console.log("Mouse Entered")
}}>
<img style={{height: '200px', width: '200px'}} src={tile.preview}/>
<img style={{height: '200px', width: '200px'}}
src={tile.preview}/>
</button>
))}
{this.state.icon.length === 0 ?
@ -167,7 +170,8 @@ class GeneralInfo extends Component {
<button onMouseEnter={() => {
console.log("Mouse Entered")
}}>
<img style={{height: '200px', width: '400px'}} src={tile.preview}/>
<img style={{height: '200px', width: '400px'}}
src={tile.preview}/>
</button>
))}
{this.state.banner.length === 0 ?
@ -186,9 +190,7 @@ class GeneralInfo extends Component {
</div>
</div>
<div className="save-info">
<Button>
<FormattedMessage id="Save" defaultMessage="Save"/>
</Button>
<Button>Save</Button>
</div>
</form>
</Row>

@ -54,7 +54,9 @@ class PlatformListing extends Component {
<div id="platform-listing">
<Row>
<div className="create-platform">
<Button id="create-platform-btn" onClick={this.onPlatformCreateClick}>Create Platform</Button>
<Button id="secondary-button" onClick={this.onPlatformCreateClick}>
<i className="fw fw-add"></i>Create Platform
</Button>
</div>
</Row>
<Row>

@ -329,12 +329,6 @@
<type>zip</type>
<version>${carbon.device.mgt.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.application.mgt.auth.handler.feature</artifactId>
<type>zip</type>
<version>${carbon.device.mgt.version}</version>
</dependency>
<dependency>
<groupId>org.wso2.carbon.devicemgt</groupId>
<artifactId>org.wso2.carbon.device.application.mgt.publisher.ui.feature</artifactId>

Loading…
Cancel
Save