Merge branch 'wso2-application-mgt' into application-mgt

feature/appm-store/pbac
sinthuja 7 years ago
commit d04777a1e6

@ -31,6 +31,7 @@ import javax.validation.Valid;
import javax.ws.rs.Path; import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.Response; import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.List; import java.util.List;
/** /**
@ -45,23 +46,25 @@ public class SubscriptionManagementAPIImpl implements SubscriptionManagementAPI{
@Override @Override
public Response installApplication(@ApiParam(name = "installationDetails", value = "The application ID and list" + public Response installApplication(@ApiParam(name = "installationDetails", value = "The application ID and list" +
" the devices/users/roles", required = true) @Valid InstallationDetails installationDetails) { " the devices/users/roles", required = true) @Valid InstallationDetails installationDetails) {
Object response; Object result;
SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager(); SubscriptionManager subscriptionManager = APIUtil.getSubscriptionManager();
try { try {
String applicationUUTD = installationDetails.getApplicationUUID(); String applicationUUID = installationDetails.getApplicationUUID();
if (!installationDetails.getDeviceIdentifiers().isEmpty()) { if (!installationDetails.getDeviceIdentifiers().isEmpty()) {
List<DeviceIdentifier> deviceList = installationDetails.getDeviceIdentifiers(); List<DeviceIdentifier> deviceList = installationDetails.getDeviceIdentifiers();
response = subscriptionManager.installApplicationForDevices(applicationUUTD, deviceList); result = subscriptionManager.installApplicationForDevices(applicationUUID, deviceList);
} else if (!installationDetails.getUserNameList().isEmpty()) { } else if (!installationDetails.getUserNameList().isEmpty()) {
List<String> userList = installationDetails.getUserNameList(); List<String> userList = installationDetails.getUserNameList();
response = subscriptionManager.installApplicationForUsers(applicationUUTD, userList); result = subscriptionManager.installApplicationForUsers(applicationUUID, userList);
} else if (!installationDetails.getRoleNameList().isEmpty()) { } else if (!installationDetails.getRoleNameList().isEmpty()) {
List<String> roleList = installationDetails.getRoleNameList(); List<String> roleList = installationDetails.getRoleNameList();
response = subscriptionManager.installApplicationForRoles(applicationUUTD, roleList); result = subscriptionManager.installApplicationForRoles(applicationUUID, roleList);
} else { } else {
response = "Missing request data!"; result = "Missing request data!";
return Response.status(Response.Status.BAD_REQUEST).entity(response).build(); return Response.status(Response.Status.BAD_REQUEST).entity(result).build();
} }
HashMap<String, Object> response = new HashMap<>();
response.put("failedDevices", result);
return Response.status(Response.Status.OK).entity(response).build(); return Response.status(Response.Status.OK).entity(response).build();
} catch (ApplicationManagementException e) { } catch (ApplicationManagementException e) {
String msg = "Error occurred while installing the application"; String msg = "Error occurred while installing the application";

@ -31,7 +31,7 @@ public interface SubscriptionManager {
* To install an application to given list of devices. * To install an application to given list of devices.
* @param applicationUUID Application ID * @param applicationUUID Application ID
* @param deviceList Device list * @param deviceList Device list
* @return DeviceList which the application has been installed * @return Failed Device List which the application was unable to install
* @throws ApplicationManagementException Application Management Exception * @throws ApplicationManagementException Application Management Exception
*/ */
List<DeviceIdentifier> installApplicationForDevices(String applicationUUID, List<DeviceIdentifier> installApplicationForDevices(String applicationUUID,
@ -42,10 +42,10 @@ public interface SubscriptionManager {
* To install an application to given list of users. * To install an application to given list of users.
* @param applicationUUID Application ID * @param applicationUUID Application ID
* @param userList User list * @param userList User list
* @return User list which the application has been installed * @return Failed Device List which the application was unable to install
* @throws ApplicationManagementException Application Management Exception * @throws ApplicationManagementException Application Management Exception
*/ */
List<String> installApplicationForUsers(String applicationUUID, List<DeviceIdentifier> installApplicationForUsers(String applicationUUID,
List<String> userList) List<String> userList)
throws ApplicationManagementException; throws ApplicationManagementException;
@ -53,10 +53,10 @@ public interface SubscriptionManager {
* To install an application to given list of users. * To install an application to given list of users.
* @param applicationUUID Application ID * @param applicationUUID Application ID
* @param roleList Role list * @param roleList Role list
* @return Role list which the application has been installed * @return Failed Device List which the application was unable to install
* @throws ApplicationManagementException Application Management Exception * @throws ApplicationManagementException Application Management Exception
*/ */
List<String> installApplicationForRoles(String applicationUUID, List<DeviceIdentifier> installApplicationForRoles(String applicationUUID,
List<String> roleList) List<String> roleList)
throws ApplicationManagementException; throws ApplicationManagementException;
@ -64,7 +64,7 @@ public interface SubscriptionManager {
* To uninstall an application from a given list of devices. * To uninstall an application from a given list of devices.
* @param applicationUUID Application ID * @param applicationUUID Application ID
* @param deviceList Device list * @param deviceList Device list
* @return DeviceList which the application has been uninstalled * @return Failed Device List which the application was unable to uninstall
* @throws ApplicationManagementException Application Management Exception * @throws ApplicationManagementException Application Management Exception
*/ */
List<DeviceIdentifier> uninstallApplication(String applicationUUID, List<DeviceIdentifier> uninstallApplication(String applicationUUID,

@ -19,10 +19,14 @@ package org.wso2.carbon.device.application.mgt.core.impl;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.wso2.carbon.context.PrivilegedCarbonContext;
import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier; import org.wso2.carbon.device.application.mgt.common.DeviceIdentifier;
import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException; import org.wso2.carbon.device.application.mgt.common.exception.ApplicationManagementException;
import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager; import org.wso2.carbon.device.application.mgt.common.services.SubscriptionManager;
import org.wso2.carbon.device.application.mgt.core.dao.common.DAOFactory; import org.wso2.carbon.device.application.mgt.core.dao.common.DAOFactory;
import org.wso2.carbon.device.application.mgt.core.internal.DataHolder;
import org.wso2.carbon.device.mgt.common.Device;
import org.wso2.carbon.device.mgt.common.DeviceManagementException;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOException;
import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory; import org.wso2.carbon.device.mgt.core.dao.DeviceManagementDAOFactory;
@ -42,7 +46,60 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
List<DeviceIdentifier> deviceList) List<DeviceIdentifier> deviceList)
throws ApplicationManagementException { throws ApplicationManagementException {
log.info("Install application: " + applicationUUID + " to: " + deviceList.size() + " devices."); log.info("Install application: " + applicationUUID + " to: " + deviceList.size() + " devices.");
List<DeviceIdentifier> failedDevices = installApplication(applicationUUID, deviceList);
return failedDevices;
}
@Override
public List<DeviceIdentifier> installApplicationForUsers(String applicationUUID, List<String> userList)
throws ApplicationManagementException {
log.info("Install application: " + applicationUUID + " to: " + userList.size() + " users.");
List<DeviceIdentifier> deviceList = new ArrayList<>();
int tenantId = PrivilegedCarbonContext.getThreadLocalCarbonContext().getTenantId();
for (String user : userList) {
try {
List<Device> devicesOfUser = DeviceManagementDAOFactory.getDeviceDAO().getDevicesOfUser(user, tenantId);
for (Device device : devicesOfUser) {
deviceList.add(new DeviceIdentifier(device
.getDeviceIdentifier(), device.getType()));
}
} catch (DeviceManagementDAOException e) {
log.error("Error when extracting the device list from user[" + user + "].", e);
}
}
return installApplication(applicationUUID, deviceList);
}
@Override
public List<DeviceIdentifier> installApplicationForRoles(String applicationUUID, List<String> roleList)
throws ApplicationManagementException {
log.info("Install application: " + applicationUUID + " to: " + roleList.size() + " roles.");
List<DeviceIdentifier> deviceList = new ArrayList<>();
for (String role : roleList) {
try {
List<Device> devicesOfRole = DataHolder.getInstance().getDeviceManagementService().getAllDevicesOfRole(role);
for (Device device : devicesOfRole) {
deviceList.add(new DeviceIdentifier(device
.getDeviceIdentifier(), device.getType()));
}
} catch (DeviceManagementException e) {
log.error("Error when extracting the device list from role[" + role + "].", e);
}
}
return installApplication(applicationUUID, deviceList);
}
@Override
public List<DeviceIdentifier> uninstallApplication(String applicationUUID,
List<DeviceIdentifier> deviceList)
throws ApplicationManagementException {
return null;
}
private List<DeviceIdentifier> installApplication(String applicationUUID, List<DeviceIdentifier> deviceList)
throws ApplicationManagementException {
List<DeviceIdentifier> failedDeviceList = new ArrayList<>(deviceList); List<DeviceIdentifier> failedDeviceList = new ArrayList<>(deviceList);
List<org.wso2.carbon.device.mgt.common.DeviceIdentifier> activeDeviceList = new ArrayList<>();
for (DeviceIdentifier device : deviceList) { for (DeviceIdentifier device : deviceList) {
org.wso2.carbon.device.mgt.common.DeviceIdentifier deviceIdentifier = new org.wso2.carbon.device.mgt org.wso2.carbon.device.mgt.common.DeviceIdentifier deviceIdentifier = new org.wso2.carbon.device.mgt
.common.DeviceIdentifier(device.getId(), device.getType()); .common.DeviceIdentifier(device.getId(), device.getType());
@ -52,9 +109,9 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
log.error("Device with ID: " + device.getId() + " not found to install the application."); log.error("Device with ID: " + device.getId() + " not found to install the application.");
} else { } else {
if (log.isDebugEnabled()) { if (log.isDebugEnabled()) {
log.debug("Installing application to : " + device.getId()); log.debug("Prepare application install to : " + device.getId());
} }
//Todo: generating one time download link for the application and put install operation to device. activeDeviceList.add(deviceIdentifier);
DAOFactory.getSubscriptionDAO().addDeviceApplicationMapping(device.getId(), applicationUUID, false); DAOFactory.getSubscriptionDAO().addDeviceApplicationMapping(device.getId(), applicationUUID, false);
failedDeviceList.remove(device); failedDeviceList.remove(device);
} }
@ -64,35 +121,7 @@ public class SubscriptionManagerImpl implements SubscriptionManager {
DeviceManagementDAOFactory.closeConnection(); DeviceManagementDAOFactory.closeConnection();
} }
} }
//Todo: generating one time download link for the application and put install operation to devices.
return failedDeviceList; return failedDeviceList;
} }
@Override
public List<String> installApplicationForUsers(String applicationUUID, List<String> userList)
throws ApplicationManagementException {
log.info("Install application: " + applicationUUID + " to: " + userList.size() + " users.");
for (String user : userList) {
//Todo: implementation
//Todo: get the device list and call installApplicationForDevices
}
return userList;
}
@Override
public List<String> installApplicationForRoles(String applicationUUID, List<String> roleList)
throws ApplicationManagementException {
log.info("Install application: " + applicationUUID + " to: " + roleList.size() + " users.");
for (String role : roleList) {
//Todo: implementation
//Todo: get the device list and call installApplicationForDevices
}
return roleList;
}
@Override
public List<DeviceIdentifier> uninstallApplication(String applicationUUID,
List<DeviceIdentifier> deviceList)
throws ApplicationManagementException {
return null;
}
} }

@ -31,32 +31,6 @@
<build> <build>
<plugins> <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</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> <plugin>
<groupId>org.codehaus.mojo</groupId> <groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId> <artifactId>exec-maven-plugin</artifactId>
@ -96,8 +70,15 @@
<workingDirectory>${npm.working.dir}</workingDirectory> <workingDirectory>${npm.working.dir}</workingDirectory>
</configuration> </configuration>
</plugin> </plugin>
</plugins> </plugins>
<resources>
<resource>
<directory>${project.build.directory}/target</directory>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
</build> </build>
<profiles> <profiles>
<profile> <profile>

@ -39,11 +39,11 @@
<title>WSO2 IoT App Publisher</title> <title>WSO2 IoT App Publisher</title>
</head> </head>
<body> <body>
<script src='./dist/index.js'></script>
<noscript> <noscript>
You need to enable JavaScript to run this app. You need to enable JavaScript to run this app.
</noscript> </noscript>
<div id="root"></div> <div id="root"></div>
<script src='./dist/index.js'></script>
<!-- <!--
This HTML file is a template. This HTML file is a template.
If you open it directly in the browser, you will see an empty page. If you open it directly in the browser, you will see an empty page.

@ -0,0 +1,25 @@
/*
* 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.
*/
.creatediv {
margin: 0 16px;
}
.nextButton {
margin-top: 12px;
}

@ -0,0 +1,120 @@
/*
* 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.
*/
.applicationCreateChip {
margin: 4px;
}
.createStep2Content {
margin: 0 16px;
}
.applicationCreateWrapper {
display: flex;
flex-wrap: wrap;
}
.platformSpecificPropertyDiv {
border: solid #BDBDBD 1px;
}
.platformSpecificPropertyP {
color: #BDBDBD;
}
.applicationCreateBannerError {
color: #f44336;
}
.applicationCreateBannerTitle {
color: #BDBDBD;
}
.applicationCreateGrid {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}
.applicationCreateBannerDropZone {
width: 300px;
height: 150px;
border: dashed #BDBDBD 1px
}
.applicationCreateBannerp {
margin: 70px 40px 40px 150px;
}
.applicationCreateScreenshotError {
color: #f44336;
}
.applicationCreateScreenshotTitle {
color: #BDBDBD;
}
.applicationCreateScreenshotGrid {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}
.applicationCreateScreenshotDropZone {
width: 150px;
height: 150px;
border: dashed #BDBDBD 1px;
}
.applicationCreateScreenshotp {
margin: 70px 40px 70px 70px;
}
.applcationCreateIconError {
color: #f44336;
}
.applicationCreateIconTitle {
color: #BDBDBD;
}
.applicationCreateIconGrid {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}
.applicationCreateIconDropZone {
width: 150px;
height: 150px;
border: dashed #BDBDBD 1px;
}
.applicationCreateIconp {
margin: 70px 40px 70px 70px;
}
.applicationCreateBackAndNext {
margin-top: 12px;
}
.applicationCreateBack {
margin-right: 12px;
}

@ -0,0 +1,29 @@
/*
* 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.
*/
.applicationCreateStepMiddle {
margin: 0 16px;
}
.applicationCreateBackAndFinish {
margin-top: 12px;
}
.applicationCreateFinish {
margin-right: 12px;
}

@ -0,0 +1,36 @@
/*
* 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.
*/
.createapplicationmiddle {
width: 95%;
height: 100%;
margin-top: 1%;
}
.creataapplicationcard {
max-height: 700px;
overflow: auto;
}
.createapplicationcardaction {
width: 100%;
margin: auto;
}
.createapplicationcontent {
margin: 0 16px;
}

@ -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.
*/
.applicationListingMiddle {
width: 95%;
height: 100%;
margin-top: 1%;
}
.applicationListingCard {
display: flex;
flex-wrap: wrap;
}
.applicationListingSearch {
float:right;
padding-right: 2px;
}
.applicationListTitle {
display: flex;
flex-wrap: wrap;
}

@ -0,0 +1,25 @@
/*
* 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.
*/
.basicLayoutDiv {
height: calc(100% - 64px);
margin-left: 16%;
width: calc(100% - 15%);
top: 64px;
left: -100px;
}

@ -0,0 +1,43 @@
/*
* 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.
*/
.tableRow {
display: flex;
}
.datatableRowColumn {
align-items: center;
}
.sortableHeaderCell {
color: #bdbdbd;
}
.notsortableHeaderCell {
position: relative;
padding-left: 16px;
padding-right: 16px;
text-transform: uppercase;
font-weight: normal;
color: #bdbdbd;
font-size: 14px;
}
.datatableHeaderColumn {
padding-left: 0;
}

@ -0,0 +1,68 @@
/*
* 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.
*/
.createplatformmiddle {
width: 95%;
height: 100%;
margin-top: 1%
}
.createplatformcardaction {
width: 100%;
margin: auto;
padding-left: 10px;
}
.createplatformproperties {
color: #BaBaBa;
}
.createplatformpropertyclose {
height: 10px;
width: 10px;
}
.createplatformproperty {
display: flex;
}
.createplatformpropertyselect {
flex: 1 1 23% 1;
margin: 0 1%
}
.createplatformicon {
display: flex;
flex-wrap: nowrap;
overflow-x: auto;
}
.createplatformiconp {
color: #BDBDBD;
}
.createplatformdropzone {
width: 150px;
height: 150px;
border: dashed #BDBDBD 1px;
}
.createplatformdropzonep {
margin: 70px 40px 70px 70px
}

@ -0,0 +1,39 @@
/*
* 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.
*/
.listingplatformmiddle {
width: 95%;
height: 100%;
margin-top: 1%;
}
.listingplatformcard {
display: flex;
flex-wrap: wrap;
}
.listingplatformsearch {
float:right;
padding-right: 2px;
}
.listingplatformTitle {
display: flex;
flex-wrap: wrap;
}

@ -31,20 +31,11 @@ import {
PlatformCreate, PlatformCreate,
PlatformListing PlatformListing
} from './components'; } from './components';
import Theme from './theme';
const history = createHistory({basename: '/publisher'}); const history = createHistory({basename: '/publisher'});
/**
* 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. * This component defines the layout and the routes for the app.
@ -101,10 +92,59 @@ class Base extends Component {
* *
* */ * */
class Publisher extends Component { class Publisher extends Component {
constructor() {
super();
this.state = {
muiTheme: null,
selectedType: null,
selectedTheme: null
};
this.setTheme = this.setTheme.bind(this);
}
componentDidMount() {
/**
*Loading the theme files based on the the user-preference.
*/
let themeConfig = Theme.loadThemeConfigs();
themeConfig.then(this.setTheme).catch(function (error) {
console.log(error);
});
}
/**
* To set the theme based on the configuration file.
* @param response Configuration file data.
*/
setTheme(response) {
this.setState({
selectedType: response.data.theme.type,
selectedTheme: response.data.theme.value
});
Theme.currentThemeType = this.state.selectedType;
Theme.currentTheme = this.state.selectedTheme;
Theme.selectedTheme =
(Theme.currentThemeType === Theme.defaultThemeType) ? Theme.defaultThemeType : Theme.currentTheme;
if (this.state.selectedType === "default") {
let defaultTheme = require("material-ui/styles/baseThemes/" + this.state.selectedTheme);
this.setState({
muiTheme : getMuiTheme(defaultTheme.default)
});
} else {
let customTheme = require("./themes/" + this.state.selectedTheme);
this.setState({
muiTheme : getMuiTheme(customTheme.default)
});
}
}
render() { render() {
return ( return (
<div className="App"> <div className="App">
<MuiThemeProvider muiTheme={muiTheme}> <MuiThemeProvider muiTheme={this.state.muiTheme}>
<Router basename="publisher" history={history}> <Router basename="publisher" history={history}>
<Switch> <Switch>
<Route path="/login" component={Login}/> <Route path="/login" component={Login}/>

@ -24,7 +24,7 @@ import {Step1, Step2, Step3} from './CreateSteps';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import {Step, StepLabel, Stepper,} from 'material-ui/Stepper'; import {Step, StepLabel, Stepper,} from 'material-ui/Stepper';
import Theme from '../../theme';
/** /**
* The App Create Component. * The App Create Component.
@ -37,6 +37,7 @@ import {Step, StepLabel, Stepper,} from 'material-ui/Stepper';
class ApplicationCreate extends Component { class ApplicationCreate extends Component {
constructor() { constructor() {
super(); super();
this.scriptId = "application-create";
this.setStepData.bind(this); this.setStepData.bind(this);
this.removeStepData.bind(this); this.removeStepData.bind(this);
this.handleSubmit.bind(this); this.handleSubmit.bind(this);
@ -51,6 +52,17 @@ class ApplicationCreate extends Component {
}; };
} }
componentWillMount() {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
}
/** /**
* Handles next button click event. * Handles next button click event.
* */ * */
@ -179,15 +191,15 @@ class ApplicationCreate extends Component {
return ( return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}> <div className="middle createapplicationmiddle">
<Card style={{maxHeight: '700px', overflow: 'auto'}}> <Card className="creataapplicationcard">
<CardTitle title="Create Application"/> <CardTitle title="Create Application"/>
{/** {/**
* The stepper goes here. * The stepper goes here.
*/} */}
<CardActions> <CardActions>
<div style={{width: '100%', margin: 'auto'}}> <div className="createapplicationcardaction">
<Stepper activeStep={stepIndex}> <Stepper activeStep={stepIndex}>
<Step> <Step>
<StepLabel>Select Application Platform</StepLabel> <StepLabel>Select Application Platform</StepLabel>
@ -199,7 +211,7 @@ class ApplicationCreate extends Component {
<StepLabel>Release</StepLabel> <StepLabel>Release</StepLabel>
</Step> </Step>
</Stepper> </Stepper>
<div style={contentStyle}> <div className="createapplicationcontent">
{finished ? ( {finished ? (
<div> <div>
<p>Create App?</p> <p>Create App?</p>

@ -21,6 +21,7 @@ import {withRouter} from 'react-router-dom';
import TextField from 'material-ui/TextField'; import TextField from 'material-ui/TextField';
import DataTable from '../UIComponents/DataTable'; import DataTable from '../UIComponents/DataTable';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import Theme from '../../theme';
/** /**
* The App Create Component. * The App Create Component.
@ -36,7 +37,8 @@ class ApplicationListing extends Component {
this.state = { this.state = {
data: [], data: [],
asc: true asc: true
} };
this.scriptId = "application-listing";
} }
data = [ data = [
@ -112,8 +114,18 @@ class ApplicationListing extends Component {
componentWillMount() { componentWillMount() {
//Fetch all the applications from backend and create application objects. //Fetch all the applications from backend and create application objects.
this.setState({data: this.data}); this.setState({data: this.data});
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
} }
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
}
/** /**
* Handles the search action. * Handles the search action.
* When typing in the search bar, this method will be invoked. * When typing in the search bar, this method will be invoked.
@ -156,12 +168,11 @@ class ApplicationListing extends Component {
render() { render() {
return ( return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}> <div className="middle applicationListingMiddle">
<Card style={{display: 'flex', flexWrap: 'wrap'}}> <Card className="applicationListingCard">
<TextField hintText="Search" <TextField hintText="Search" className="applicationListingSearch"
style={{float:'right', paddingRight: '2px'}}
onChange={this._searchApplications.bind(this)}/> onChange={this._searchApplications.bind(this)}/>
<CardTitle title="Applications" style={{display: 'flex', flexWrap: 'wrap'}}/> <CardTitle title="Applications" className="applicationListTitle"/>
<CardActions> <CardActions>
</CardActions> </CardActions>

@ -19,9 +19,9 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import MenuItem from 'material-ui/MenuItem'; import MenuItem from 'material-ui/MenuItem';
import TextField from 'material-ui/TextField';
import SelectField from 'material-ui/SelectField'; import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import Theme from '../../../theme';
/** /**
* The first step of the application creation wizard. * The first step of the application creation wizard.
@ -48,10 +48,18 @@ class Step1 extends Component {
title: "", title: "",
titleError: "" titleError: ""
}; };
this.scriptId = "application-create-step1";
} }
componentWillMount() { componentWillMount() {
//Get the list of available platforms and set to the state. /**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -105,10 +113,9 @@ class Step1 extends Component {
}; };
render() { render() {
const contentStyle = {margin: '0 16px'};
return ( return (
<div> <div>
<div style={contentStyle}> <div className="creatediv">
<div> <div>
<div> <div>
<SelectField <SelectField
@ -134,7 +141,7 @@ class Step1 extends Component {
<br/> <br/>
<br/> <br/>
<div style={{marginTop: 12}}> <div className="nextButton">
<RaisedButton <RaisedButton
label="Next >" label="Next >"
primary={true} primary={true}

@ -28,6 +28,7 @@ import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import Clear from 'material-ui/svg-icons/content/clear'; import Clear from 'material-ui/svg-icons/content/clear';
import {GridList, GridTile} from 'material-ui/GridList'; import {GridList, GridTile} from 'material-ui/GridList';
import Theme from '../../../theme';
/** /**
* The Second step of application create wizard. * The Second step of application create wizard.
@ -66,18 +67,19 @@ class Step2 extends Component {
screenshots: [], screenshots: [],
icon: [] icon: []
}; };
this.scriptId = "application-create-step2";
}
this.styles = { componentWillMount() {
chip: { /**
margin: 4, *Loading the theme files based on the the user-preference.
}, */
wrapper: { Theme.insertThemingScripts(this.scriptId);
display: 'flex',
flexWrap: 'wrap',
},
};
} }
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
}
/** /**
* Create a tag on Enter key press and set it to the state. * Create a tag on Enter key press and set it to the state.
@ -142,8 +144,7 @@ class Step2 extends Component {
<Chip <Chip
key={data.key} key={data.key}
onRequestDelete={() => this._handleRequestDelete(data.key)} onRequestDelete={() => this._handleRequestDelete(data.key)}
style={this.styles.chip} className="applicationCreateChip">
>
{data.value} {data.value}
</Chip> </Chip>
); );
@ -299,9 +300,8 @@ class Step2 extends Component {
render() { render() {
console.log(this.state.visibilityComponent); console.log(this.state.visibilityComponent);
const contentStyle = {margin: '0 16px'};
return ( return (
<div style={contentStyle}> <div className="createStep2Content">
<div> <div>
<div> <div>
<TextField <TextField
@ -353,7 +353,7 @@ class Step2 extends Component {
onChange={this._handleTagChange.bind(this)} onChange={this._handleTagChange.bind(this)}
onKeyPress={this._addTags.bind(this)} onKeyPress={this._addTags.bind(this)}
/><br/> /><br/>
<div style={this.styles.wrapper}> <div className="applicationCreateWrapper">
{this.state.tags.map(this._renderChip, this)} {this.state.tags.map(this._renderChip, this)}
</div> </div>
<br/> <br/>
@ -365,18 +365,14 @@ class Step2 extends Component {
<MenuItem value={0} primaryText="Business"/> <MenuItem value={0} primaryText="Business"/>
</SelectField> <br/> </SelectField> <br/>
{/*Platform Specific Properties.*/} {/*Platform Specific Properties.*/}
<div style={{border: 'solid #BDBDBD 1px'}}> <div className="platformSpecificPropertyDiv">
<p style={{color: '#BDBDBD'}}>Platform Specific Properties</p> <p className="platformSpecificPropertyP">Platform Specific Properties</p>
</div> </div>
<br/> <br/>
<div> <div>
<p style={{color: '#f44336'}}>{this.state.errors["Banner"]}</p> <p className="applicationCreateBannerError">{this.state.errors["Banner"]}</p>
<p style={{color: '#BDBDBD'}}>Banner*:</p> <p className="applicationCreateBannerTitle">Banner*:</p>
<GridList style={{ <GridList className="applicationCreateGrid" cols={1.1}>
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.banner.map((tile) => ( {this.state.banner.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)} <GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name} title={tile.name}
@ -387,12 +383,11 @@ class Step2 extends Component {
<img src={tile.preview}/></GridTile> <img src={tile.preview}/></GridTile>
))} ))}
{this.state.banner.length === 0 ? {this.state.banner.length === 0 ?
<Dropzone style={{width: '300px', height: '150px', border: 'dashed #BDBDBD 1px'}} <Dropzone className="applicationCreateBannerDropZone" accept="image/jpeg, image/png"
accept="image/jpeg, image/png"
onDrop={(banner, rejected) => { onDrop={(banner, rejected) => {
this.setState({banner, rejected}); this.setState({banner, rejected});
}}> }}>
<p style={{margin: '70px 40px 40px 150px'}}>+</p> <p className="applicationCreateBannerp">+</p>
</Dropzone> : <div />} </Dropzone> : <div />}
</GridList> </GridList>
@ -400,13 +395,9 @@ class Step2 extends Component {
</div> </div>
<br/> <br/>
<div> <div>
<p style={{color: '#f44336'}}>{this.state.errors["Screenshots"]}</p> <p className="applicationCreateScreenshotError">{this.state.errors["Screenshots"]}</p>
<p style={{color: '#BDBDBD'}}>Screenshots*:</p> <p className="applicationCreateScreenshotTitle">Screenshots*:</p>
<GridList style={{ <GridList className = "applicationCreateScreenshotGrid" cols={1.1}>
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.screenshots.map((file) => ( {this.state.screenshots.map((file) => (
<GridTile key={Math.floor(Math.random() * 1000)} <GridTile key={Math.floor(Math.random() * 1000)}
title={file[0].name} title={file[0].name}
@ -417,7 +408,7 @@ class Step2 extends Component {
<img src={file[0].preview}/></GridTile> <img src={file[0].preview}/></GridTile>
))} ))}
{this.state.screenshots.length < 3 ? {this.state.screenshots.length < 3 ?
<Dropzone style={{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}} <Dropzone className="applicationCreateScreenshotDropZone"
accept="image/jpeg, image/png" accept="image/jpeg, image/png"
onDrop={(screenshots, rejected) => { onDrop={(screenshots, rejected) => {
let tmpScreenshots = this.state.screenshots; let tmpScreenshots = this.state.screenshots;
@ -425,19 +416,15 @@ class Step2 extends Component {
this.setState({ this.setState({
screenshots: tmpScreenshots}); screenshots: tmpScreenshots});
}}> }}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p> <p className="applicationCreateScreenshotp">+</p>
</Dropzone> : <div />} </Dropzone> : <div />}
</GridList> </GridList>
</div> </div>
<br/> <br/>
<div> <div>
<p style={{color: '#f44336'}}>{this.state.errors["Icon"]}</p> <p className="applcationCreateIconError">{this.state.errors["Icon"]}</p>
<p style={{color: '#BDBDBD'}}>Icon*:</p> <p className="applicationCreateIconTitle">Icon*:</p>
<GridList style={{ <GridList className="applicationCreateIconGrid" cols={1.1}>
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.icon.map((tile) => ( {this.state.icon.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)} <GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name} title={tile.name}
@ -448,10 +435,10 @@ class Step2 extends Component {
<img src={tile.preview}/></GridTile> <img src={tile.preview}/></GridTile>
))} ))}
{this.state.icon.length === 0 ? {this.state.icon.length === 0 ?
<Dropzone style={{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}} <Dropzone className="applicationCreateIconDropZone"
accept="image/jpeg, image/png" accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected});}}> onDrop={(icon, rejected) => {this.setState({icon, rejected});}}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p> <p className="applicationCreateIconp">+</p>
</Dropzone> : <div />} </Dropzone> : <div />}
</GridList> </GridList>
</div> </div>
@ -460,12 +447,12 @@ class Step2 extends Component {
<br/> <br/>
<br/> <br/>
<div style={{marginTop: 12}}> <div className="applicationCreateBackAndNext">
<FlatButton <FlatButton
label="< Back" label="< Back"
disabled={false} disabled={false}
onClick={this._handlePrev.bind(this)} onClick={this._handlePrev.bind(this)}
style={{marginRight: 12}} className="applicationCreateBack"
/> />
<RaisedButton <RaisedButton
label="Next >" label="Next >"

@ -24,6 +24,7 @@ import TextField from 'material-ui/TextField';
import FlatButton from 'material-ui/FlatButton'; import FlatButton from 'material-ui/FlatButton';
import SelectField from 'material-ui/SelectField'; import SelectField from 'material-ui/SelectField';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import Theme from '../../../theme';
/** /**
* The Third step of application create wizard. {Application Release Step} * The Third step of application create wizard. {Application Release Step}
@ -54,7 +55,19 @@ class Step3 extends Component {
showForm: false, showForm: false,
releaseChannel: 1, releaseChannel: 1,
errors: {} errors: {}
};
this.scriptId = "application-create-step3";
} }
componentWillMount() {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -81,9 +94,8 @@ class Step3 extends Component {
} }
render() { render() {
const contentStyle = {margin: '0 16px'};
return ( return (
<div style={contentStyle}> <div className="applicationCreateStepMiddle">
<div> <div>
<Toggle <Toggle
label="Release the Application" label="Release the Application"
@ -110,13 +122,9 @@ class Step3 extends Component {
/><br/> /><br/>
</div>} </div>}
<div style={{marginTop: 12}}> <div className="applicationCreateBackAndFinish">
<FlatButton <FlatButton label="< Back" disabled={false} onClick={this._handlePrev.bind(this)}
label="< Back" className="applicationCreateFinish"/>
disabled={false}
onClick={this._handlePrev.bind(this)}
style={{marginRight: 12}}
/>
<RaisedButton <RaisedButton
label="Finish" label="Finish"
primary={true} primary={true}

@ -27,10 +27,11 @@ import {List, ListItem} from 'material-ui/List';
import Apps from 'material-ui/svg-icons/navigation/apps'; import Apps from 'material-ui/svg-icons/navigation/apps';
import Add from 'material-ui/svg-icons/content/add-circle'; import Add from 'material-ui/svg-icons/content/add-circle';
import Feedback from 'material-ui/svg-icons/action/feedback'; import Feedback from 'material-ui/svg-icons/action/feedback';
import Dashboard from 'material-ui/svg-icons/action/dashboard';
import DevicesOther from 'material-ui/svg-icons/hardware/devices-other'; import DevicesOther from 'material-ui/svg-icons/hardware/devices-other';
import NotificationsIcon from 'material-ui/svg-icons/social/notifications'; import NotificationsIcon from 'material-ui/svg-icons/social/notifications';
import ActionAccountCircle from 'material-ui/svg-icons/action/account-circle'; import ActionAccountCircle from 'material-ui/svg-icons/action/account-circle';
import Theme from '../../theme';
/** /**
* Base Layout: * Base Layout:
@ -45,11 +46,19 @@ class BaseLayout extends Component {
this.state = { this.state = {
notifications: 0, notifications: 0,
user: 'Admin' user: 'Admin'
} };
this.scriptId = "basic-layout";
} }
componentWillMount() { componentWillMount() {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId)
} }
handleApplicationClick() { handleApplicationClick() {
@ -86,6 +95,7 @@ class BaseLayout extends Component {
render() { render() {
return ( return (
<div> <div>
<AppBar title="App Publisher" <AppBar title="App Publisher"
iconElementRight={ iconElementRight={
@ -142,16 +152,7 @@ class BaseLayout extends Component {
</List> </List>
</Drawer> </Drawer>
</div> </div>
<div style= <div className="basicLayoutDiv">
{
{
height: 'calc(100% - 64px)',
marginLeft: '16%',
width: 'calc(100%-15%)',
top: 64,
left: "-100px"
}
}>
{this.props.children} {this.props.children}
</div> </div>
</div>); </div>);

@ -31,6 +31,7 @@ import {GridList, GridTile} from 'material-ui/GridList';
import Close from 'material-ui/svg-icons/navigation/close'; import Close from 'material-ui/svg-icons/navigation/close';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import AddCircleOutline from 'material-ui/svg-icons/content/add-circle-outline'; import AddCircleOutline from 'material-ui/svg-icons/content/add-circle-outline';
import Theme from '../../theme';
/** /**
* Platform Create component. * Platform Create component.
@ -61,7 +62,19 @@ class PlatformCreate extends Component {
{key: 1, value: 'Number'}, {key: 1, value: 'Number'},
{key: 2, value: 'Boolean'}, {key: 2, value: 'Boolean'},
{key: 3, value: 'File'}] {key: 3, value: 'File'}]
};
this.scriptId = "platform-create";
} }
componentWillMount() {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -184,12 +197,12 @@ class PlatformCreate extends Component {
property} = this.state; property} = this.state;
return ( return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}> <div className="middle createplatformmiddle">
<Card> <Card>
<CardTitle title="Create Platform"/> <CardTitle title="Create Platform"/>
<CardActions> <CardActions>
<div style={{width: '100%', margin: 'auto', paddingLeft: '10px'}}> <div className="createplatformcardaction">
<form> <form>
<TextField <TextField
hintText="Enter the Platform Name." hintText="Enter the Platform Name."
@ -224,17 +237,17 @@ class PlatformCreate extends Component {
toggled={enabled} toggled={enabled}
/> <br/> /> <br/>
<div> <div>
<p style={{color: '#BaBaBa'}}>Platform Properties</p> <p className="createplatformproperties">Platform Properties</p>
<div id="property-container"> <div id="property-container">
{platformProperties.map((p) => { {platformProperties.map((p) => {
return <div key={p.key}>{p.key} : {p.value} return <div key={p.key}>{p.key} : {p.value}
<IconButton onClick={this._removeProperty.bind(this, p)}> <IconButton onClick={this._removeProperty.bind(this, p)}>
<Close style={{height: '10px', width: '10px'}}/> <Close className="createplatformpropertyclose"/>
</IconButton> </IconButton>
</div> </div>
})} })}
</div> </div>
<div style={{display: 'flex'}}> <div className="createplatformproperty">
<TextField <TextField
id="property" id="property"
hintText="Property Name" hintText="Property Name"
@ -244,7 +257,7 @@ class PlatformCreate extends Component {
onChange={this._onTextChange.bind(this)} onChange={this._onTextChange.bind(this)}
/> <em/> /> <em/>
<SelectField <SelectField
style={{flex: '1 1 23% 1', margin: '0 1%'}} className="createplatformpropertyselect"
floatingLabelText="Property Type" floatingLabelText="Property Type"
value={selectedProperty} value={selectedProperty}
floatingLabelFixed={true} floatingLabelFixed={true}
@ -262,13 +275,8 @@ class PlatformCreate extends Component {
</div> </div>
</div> </div>
<div> <div>
{/*<p style={{color: '#f44336'}}>{this.state.errors["Icon"]}</p>*/} <p className="createplatformiconp">Platform Icon*:</p>
<p style={{color: '#BDBDBD'}}>Platform Icon*:</p> <GridList className="createplatformicon" cols={1.1}>
<GridList style={{
display: 'flex',
flexWrap: 'nowrap',
overflowX: 'auto',
}} cols={1.1}>
{this.state.icon.map((tile) => ( {this.state.icon.map((tile) => (
<GridTile key={Math.floor(Math.random() * 1000)} <GridTile key={Math.floor(Math.random() * 1000)}
title={tile.name} title={tile.name}
@ -280,12 +288,10 @@ class PlatformCreate extends Component {
</GridTile> </GridTile>
))} ))}
{this.state.icon.length === 0 ? {this.state.icon.length === 0 ?
<Dropzone style={ <Dropzone className="createplatformdropzone"
{width: '150px', height: '150px', border: 'dashed #BDBDBD 1px'}
}
accept="image/jpeg, image/png" accept="image/jpeg, image/png"
onDrop={(icon, rejected) => {this.setState({icon, rejected})}}> onDrop={(icon, rejected) => {this.setState({icon, rejected})}}>
<p style={{margin: '70px 40px 70px 70px'}}>+</p> <p className="createplatformdropzonep">+</p>
</Dropzone> : <div />} </Dropzone> : <div />}
</GridList> </GridList>
</div> </div>

@ -21,6 +21,7 @@ import {withRouter} from 'react-router-dom';
import TextField from 'material-ui/TextField'; import TextField from 'material-ui/TextField';
import DataTable from '../UIComponents/DataTable'; import DataTable from '../UIComponents/DataTable';
import {Card, CardActions, CardTitle} from 'material-ui/Card'; import {Card, CardActions, CardTitle} from 'material-ui/Card';
import Theme from '../../theme';
/** /**
* The App Create Component. * The App Create Component.
@ -36,11 +37,19 @@ class PlatformListing extends Component {
this.state = { this.state = {
data: [], data: [],
asc: true asc: true
} };
this.scriptId = "platform-listing";
} }
componentWillMount() { componentWillMount() {
//Fetch all the applications from backend and create application objects. /**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -75,12 +84,11 @@ class PlatformListing extends Component {
render() { render() {
return ( return (
<div className="middle" style={{width: '95%', height: '100%', marginTop: '1%'}}> <div className= 'middle listingplatformmiddle'>
<Card style={{display: 'flex', flexWrap: 'wrap'}}> <Card className='listingplatformcard'>
<TextField hintText="Search" <TextField hintText="Search" onChange={this._searchApplications.bind(this)}
style={{float:'right', paddingRight: '2px'}} className='listingplatformsearch'/>
onChange={this._searchApplications.bind(this)}/> <CardTitle title="Platforms" className='listingplatformTitle'/>
<CardTitle title="Platforms" style={{display: 'flex', flexWrap: 'wrap'}}/>
<CardActions> <CardActions>
</CardActions> </CardActions>

@ -22,6 +22,7 @@ import DataTableRow from './DataTableRow';
import DataTableHeader from './DataTableHeader'; import DataTableHeader from './DataTableHeader';
import RaisedButton from 'material-ui/RaisedButton'; import RaisedButton from 'material-ui/RaisedButton';
import {Table, TableBody, TableHeader, TableRow} from 'material-ui/Table'; import {Table, TableBody, TableHeader, TableRow} from 'material-ui/Table';
import Theme from '../../theme';
/** /**
* The Custom Table Component. * The Custom Table Component.
@ -55,12 +56,21 @@ class DataTable extends Component {
this.state = { this.state = {
data: [], data: [],
headers: [], headers: [],
} };
this.scriptId = "data-table"
}; };
componentWillMount() { componentWillMount() {
this.setState({data: this.props.data, headers: this.props.headers}) this.setState({data: this.props.data, headers: this.props.headers});
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
shouldComponentUpdate(nextProps, nextState) { shouldComponentUpdate(nextProps, nextState) {
@ -95,8 +105,8 @@ class DataTable extends Component {
adjustForCheckbox={ false }> adjustForCheckbox={ false }>
<TableRow> <TableRow>
{headers.map((header) => { {headers.map((header) => {
return (<DataTableHeader key={header.data_id} return (<DataTableHeader key={header.data_id} className="datatableRowColumn"
style={{display: 'flex'}} header={header}/>) header={header}/>)
} }
)} )}
</TableRow> </TableRow>

@ -20,6 +20,7 @@ import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import FlatButton from 'material-ui/FlatButton'; import FlatButton from 'material-ui/FlatButton';
import {TableHeaderColumn} from 'material-ui/Table'; import {TableHeaderColumn} from 'material-ui/Table';
import Theme from '../../theme';
/** /**
* Data Table header component. * Data Table header component.
@ -29,6 +30,18 @@ class DataTableHeader extends Component {
constructor() { constructor() {
super(); super();
this.scriptId = "data-table";
}
componentWillMount() {
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -48,20 +61,13 @@ class DataTableHeader extends Component {
* */ * */
if (this.props.header.sortable) { if (this.props.header.sortable) {
headerCell = <FlatButton label={this.props.header.label} headerCell = <FlatButton label={this.props.header.label}
onClick={this._tableHeaderClick.bind(this)} onClick={this._tableHeaderClick.bind(this)} className="sortableHeaderCell"/>;
style={{color: '#bdbdbd'}}/>;
} else { } else {
headerCell = <span style={{position: 'relative', headerCell = <span className="notsortableHeaderCell">{this.props.header.label}</span>;
paddingLeft: '16px',
paddingRight: '16px',
textTransform: 'uppercase',
fontWeight: 'normal',
color: '#bdbdbd',
fontSize: '14px'}}>{this.props.header.label}</span>;
} }
return ( return (
<TableHeaderColumn key={this.props.header.id} style={{paddingLeft: '0px'}} > <TableHeaderColumn key={this.props.header.id} className="datatableHeaderColumn" >
{headerCell} {headerCell}
</TableHeaderColumn> </TableHeaderColumn>
); );

@ -19,6 +19,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, {Component} from 'react'; import React, {Component} from 'react';
import {TableRow, TableRowColumn} from 'material-ui/Table'; import {TableRow, TableRowColumn} from 'material-ui/Table';
import Theme from '../../theme';
/** /**
* Data table row component. * Data table row component.
@ -30,11 +31,21 @@ class DataTableRow extends Component {
super(); super();
this.state = { this.state = {
dataItem: {} dataItem: {}
} };
this.scriptId = "data-table";
} }
componentWillMount() { componentWillMount() {
this.setState({dataItem: this.props.dataItem}) this.setState({dataItem: this.props.dataItem});
/**
*Loading the theme files based on the the user-preference.
*/
Theme.insertThemingScripts(this.scriptId);
}
componentWillUnmount() {
Theme.removeThemingScripts(this.scriptId);
} }
/** /**
@ -50,7 +61,7 @@ class DataTableRow extends Component {
<TableRow key={this.props.key} onClick={this._handleClick.bind(this)} > <TableRow key={this.props.key} onClick={this._handleClick.bind(this)} >
{Object.keys(dataItem).map((key) => { {Object.keys(dataItem).map((key) => {
if (key !== 'id') { if (key !== 'id') {
return <TableRowColumn style={{alignItems: 'center'}} return <TableRowColumn className = "datatableRowColumn"
key={key}>{dataItem[key]}</TableRowColumn> key={key}>{dataItem[key]}</TableRowColumn>
} else { } else {
return <TableRowColumn key={key}/> return <TableRowColumn key={key}/>

@ -1,7 +1,6 @@
{ {
"theme" : { "theme": {
"current" : "default", "type": "default",
"default" : "lightBaseTheme", "value": "lightBaseTheme"
"custom" : "custom-theme"
} }
} }

@ -0,0 +1,110 @@
/*
* 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 axios from 'axios';
/**
* This class will read through the configuration file and saves the theme names for the usage in other files.
* User can define the themes in the config.json. The themes will be loaded based on the user preference.
*/
class Theme {
constructor() {
this.defaultThemeType = "default";
this.currentThemeType = this.defaultThemeType;
this.currentTheme = "lightBaseTheme";
this.themeFolder = "themes";
this.styleSheetType = "text/css";
this.styleSheetRel = "stylesheet";
this.selectedTheme = this.defaultThemeType;
//TODO Need to get the app context properly when the server is ready
this.baseURL = window.location.origin;
this.appContext = window.location.pathname.split("/")[1];
this.loadThemeConfigs.bind(this);
this.loadThemeFiles.bind(this);
this.insertThemingScripts.bind(this);
this.removeThemingScripts.bind(this);
}
/**
* To load the theme related configurations from the configuration file.
* @returns the http response.
*/
loadThemeConfigs () {
let httpClient = axios.create({
baseURL: this.baseURL + "/" + this.appContext + "/config.json",
timeout: 2000
});
httpClient.defaults.headers.post['Content-Type'] = 'application/json';
return httpClient.get();
}
/**
* To load the particular theme file from the path.
* @param path Path to load the theme files
* @returns Http response from the particular file.
*/
loadThemeFiles (path) {
let httpClient = axios.create({
baseURL: this.baseURL + "/" + this.appContext + path,
timeout: 2000
});
return httpClient.get();
}
/**
* To insert the css files to the document.
* @param scriptId ID of the script that need to be inserted
*/
insertThemingScripts(scriptId) {
const script = scriptId + ".css";
let themePath = "/" + this.themeFolder + "/" + this.selectedTheme + "/" + script;
let themeFile = this.loadThemeFiles(themePath);
let head = document.getElementsByTagName("head")[0];
let link = document.createElement("link");
link.type = this.styleSheetType;
link.href = this.baseURL + "/" + this.appContext + themePath;
link.id = scriptId;
link.rel = this.styleSheetRel;
this.removeThemingScripts(scriptId);
themeFile.then(function () {
head.appendChild(link);
}).catch(error => {
// If there is no customized css file, load the default one.
themePath = "/" + this.themeFolder + "/" + this.defaultThemeType + "/" + script;
link.href = this.baseURL + "/" + this.appContext + themePath;
head.appendChild(link);
});
}
/**
* To remove the css scripts that are inserted before.
* @param scriptId Id of the script that need to be removed
*/
removeThemingScripts(scriptId) {
let styleSheet = document.getElementById(scriptId);
if (styleSheet !== null) {
styleSheet.disabled = true;
styleSheet.parentNode.removeChild(styleSheet);
}
}
}
export default (new Theme);

@ -1,3 +1,30 @@
/*
* 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.
*/
/**
* This a sample custom theme file. In config.json, if the following changes are done, this theme will be applied.
* {
* "theme" : {
* "type" : "custom",
* "value" : "custom-theme"
* }
* }
*/
import { import {
indigo500, indigo700, redA200, indigo500, indigo700, redA200,
} from 'material-ui/styles/colors'; } from 'material-ui/styles/colors';

@ -58,7 +58,12 @@ const config = {
}] }]
} }
] ]
},
resolve: {
// you can now require('file') instead of require('file.coffee')
extensions: ['.jsx', '.js']
} }
}; };
if (process.env.NODE_ENV === "development") { if (process.env.NODE_ENV === "development") {

Loading…
Cancel
Save