@ -0,0 +1,124 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ 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.
|
||||||
|
-->
|
||||||
|
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||||
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
||||||
|
<parent>
|
||||||
|
<groupId>org.wso2.carbon.devicemgt</groupId>
|
||||||
|
<artifactId>application-mgt</artifactId>
|
||||||
|
<version>3.2.9-SNAPSHOT</version>
|
||||||
|
</parent>
|
||||||
|
<artifactId>io.entgra.device.mgt.ui</artifactId>
|
||||||
|
<version>3.2.9-SNAPSHOT</version>
|
||||||
|
<packaging>war</packaging>
|
||||||
|
<name>WSO2 Carbon - Device Management UI Component</name>
|
||||||
|
<url>http://wso2.org</url>
|
||||||
|
<description>This Component contains Device Management UI</description>
|
||||||
|
<dependencies>
|
||||||
|
</dependencies>
|
||||||
|
|
||||||
|
<build>
|
||||||
|
<plugins>
|
||||||
|
<plugin>
|
||||||
|
<artifactId>maven-war-plugin</artifactId>
|
||||||
|
<configuration>
|
||||||
|
<packagingExcludes>WEB-INF/lib/*cxf*.jar</packagingExcludes>
|
||||||
|
<warName>entgra</warName>
|
||||||
|
<webResources>
|
||||||
|
<resource>
|
||||||
|
<directory>${npm.output.directory}/dist</directory>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>${npm.output.directory}/public</directory>
|
||||||
|
<targetPath>public</targetPath>
|
||||||
|
</resource>
|
||||||
|
</webResources>
|
||||||
|
</configuration>
|
||||||
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>com.github.eirslett</groupId>
|
||||||
|
<artifactId>frontend-maven-plugin</artifactId>
|
||||||
|
<version>${frontend.mave.version}</version>
|
||||||
|
<configuration>
|
||||||
|
<workingDirectory>${npm.working.dir}</workingDirectory>
|
||||||
|
<!-- where to install npm -->
|
||||||
|
<installDirectory>${npm.install.dir}</installDirectory>
|
||||||
|
</configuration>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<id>install node and npm</id>
|
||||||
|
<goals>
|
||||||
|
<goal>install-node-and-npm</goal>
|
||||||
|
</goals>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
<configuration>
|
||||||
|
<nodeVersion>${node.version}</nodeVersion>
|
||||||
|
<npmVersion>${npm.version}</npmVersion>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>npm install</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<!-- Optional configuration which provides for running any npm command -->
|
||||||
|
<configuration>
|
||||||
|
<arguments>install</arguments>
|
||||||
|
</configuration>
|
||||||
|
</execution>
|
||||||
|
<execution>
|
||||||
|
<id>prod</id>
|
||||||
|
<goals>
|
||||||
|
<goal>npm</goal>
|
||||||
|
</goals>
|
||||||
|
<configuration>
|
||||||
|
<arguments>run-script ${npm.build.command}</arguments>
|
||||||
|
</configuration>
|
||||||
|
<phase>generate-resources</phase>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
|
</plugins>
|
||||||
|
</build>
|
||||||
|
<profiles>
|
||||||
|
<profile>
|
||||||
|
<id>platform-windows</id>
|
||||||
|
<activation>
|
||||||
|
<os>
|
||||||
|
<family>windows</family>
|
||||||
|
</os>
|
||||||
|
</activation>
|
||||||
|
<properties>
|
||||||
|
<!-- Override the executable names for Windows -->
|
||||||
|
<npm.executable>npm.cmd</npm.executable>
|
||||||
|
</properties>
|
||||||
|
</profile>
|
||||||
|
</profiles>
|
||||||
|
<properties>
|
||||||
|
<maven.test.skip>false</maven.test.skip>
|
||||||
|
<npm.executable>npm</npm.executable>
|
||||||
|
<npm.build.command>build_prod</npm.build.command>
|
||||||
|
<npm.working.dir>./react-app</npm.working.dir>
|
||||||
|
<npm.install.dir>./react-app/tmp</npm.install.dir>
|
||||||
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
|
<npm.output.directory>react-app</npm.output.directory>
|
||||||
|
</properties>
|
||||||
|
</project>
|
@ -0,0 +1,11 @@
|
|||||||
|
module.exports = function (api) {
|
||||||
|
api.cache(true);
|
||||||
|
const presets = [ "@babel/preset-env",
|
||||||
|
"@babel/preset-react" ];
|
||||||
|
const plugins = ["@babel/plugin-proposal-class-properties"];
|
||||||
|
|
||||||
|
return {
|
||||||
|
presets,
|
||||||
|
plugins
|
||||||
|
};
|
||||||
|
};
|
@ -0,0 +1,86 @@
|
|||||||
|
{
|
||||||
|
"name": "store",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "WSO2 IoT Server App Store",
|
||||||
|
"main": "App.js",
|
||||||
|
"proxy": "http://localhost:3001",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git://github.com/wso2/carbon-devicemgt"
|
||||||
|
},
|
||||||
|
"license": "Apache License 2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"acorn": "^6.2.0",
|
||||||
|
"antd": "^3.20.1",
|
||||||
|
"axios": "^0.18.1",
|
||||||
|
"d3": "^5.9.7",
|
||||||
|
"dagre": "^0.8.4",
|
||||||
|
"javascript-time-ago": "^2.0.1",
|
||||||
|
"keymirror": "^0.1.1",
|
||||||
|
"lodash.debounce": "^4.0.8",
|
||||||
|
"rc-viewer": "0.0.9",
|
||||||
|
"react-d3-graph": "^2.1.0",
|
||||||
|
"react-highlight-words": "^0.16.0",
|
||||||
|
"react-image-viewer-zoom": "^1.0.36",
|
||||||
|
"react-infinite-scroller": "^1.2.4",
|
||||||
|
"react-router": "^5.0.1",
|
||||||
|
"react-router-config": "^5.0.1",
|
||||||
|
"react-router-dom": "^5.0.1",
|
||||||
|
"react-scripts": "2.1.8",
|
||||||
|
"react-star-ratings": "^2.3.0",
|
||||||
|
"react-twemoji": "^0.2.3",
|
||||||
|
"react-virtualized": "^9.21.1",
|
||||||
|
"reqwest": "^2.0.5",
|
||||||
|
"storm-react-diagrams": "^5.2.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@babel/core": "^7.5.4",
|
||||||
|
"@babel/plugin-proposal-class-properties": "^7.5.0",
|
||||||
|
"@babel/preset-env": "^7.5.4",
|
||||||
|
"@babel/preset-react": "^7.0.0",
|
||||||
|
"@babel/register": "^7.4.4",
|
||||||
|
"babel-loader": "^8.0.6",
|
||||||
|
"body-parser": "^1.19.0",
|
||||||
|
"chai": "^4.1.2",
|
||||||
|
"css-loader": "^0.28.11",
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-pino-logger": "^4.0.0",
|
||||||
|
"file-loader": "^2.0.0",
|
||||||
|
"html-loader": "^0.5.5",
|
||||||
|
"html-webpack-plugin": "^3.2.0",
|
||||||
|
"img-loader": "^3.0.1",
|
||||||
|
"json-loader": "^0.5.7",
|
||||||
|
"less": "^3.9.0",
|
||||||
|
"less-loader": "^4.1.0",
|
||||||
|
"mini-css-extract-plugin": "^0.5.0",
|
||||||
|
"mocha": "^5.2.0",
|
||||||
|
"mock-local-storage": "^1.0.5",
|
||||||
|
"node-env-run": "^3.0.2",
|
||||||
|
"node-sass": "^4.12.0",
|
||||||
|
"nodemon": "^1.19.1",
|
||||||
|
"npm-run-all": "^4.1.5",
|
||||||
|
"pino-colada": "^1.4.5",
|
||||||
|
"postcss-loader": "^3.0.0",
|
||||||
|
"react": "^16.8.6",
|
||||||
|
"react-dom": "^16.8.6",
|
||||||
|
"react-intl": "^2.9.0",
|
||||||
|
"sass-loader": "^6.0.7",
|
||||||
|
"style-loader": "^0.18.2",
|
||||||
|
"url-loader": "^1.1.2",
|
||||||
|
"webpack": "^4.35.3",
|
||||||
|
"webpack-cli": "^3.3.5",
|
||||||
|
"webpack-dev-server": "^3.7.2"
|
||||||
|
},
|
||||||
|
"scripts": {
|
||||||
|
"start": "webpack-dev-server --mode development --open",
|
||||||
|
"dev": "webpack --mode development",
|
||||||
|
"build": "webpack --mode production",
|
||||||
|
"watch": "webpack --watch --mode development",
|
||||||
|
"test": "react-scripts test --env=jsdom",
|
||||||
|
"eject": "react-scripts eject",
|
||||||
|
"build_prod": "NODE_ENV=production NODE_OPTIONS=--max_old_space_size=4096 webpack -p --display errors-only --hide-modules",
|
||||||
|
"build_dev": "NODE_ENV=development webpack -d --watch ",
|
||||||
|
"server": "node-env-run server --exec nodemon | pino-colada",
|
||||||
|
"dev2": "run-p server start"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,43 @@
|
|||||||
|
{
|
||||||
|
"theme": {
|
||||||
|
"type": "default",
|
||||||
|
"value": "lightBaseTheme",
|
||||||
|
"logo" : "https://entgra.io/assets/images/svg/logo.svg",
|
||||||
|
"primaryColor": "rgb(24, 144, 255)"
|
||||||
|
},
|
||||||
|
"serverConfig": {
|
||||||
|
"invokerUri": "/ui-request-handler/invoke/application-mgt-store/v1.0",
|
||||||
|
"invoker": {
|
||||||
|
"uri": "/store-ui-request-handler/invoke",
|
||||||
|
"publisher": "/application-mgt-publisher/v1.0",
|
||||||
|
"store": "/application-mgt-store/v1.0",
|
||||||
|
"admin" : "",
|
||||||
|
"deviceMgt" : "/device-mgt/v1.0"
|
||||||
|
},
|
||||||
|
"loginUri": "/store-ui-request-handler/login",
|
||||||
|
"logoutUri": "/store-ui-request-handler/logout",
|
||||||
|
"platform": "store"
|
||||||
|
},
|
||||||
|
"defaultPlatformIcons": {
|
||||||
|
"default": {
|
||||||
|
"icon": "global",
|
||||||
|
"color": "#535c68",
|
||||||
|
"theme": "outlined"
|
||||||
|
},
|
||||||
|
"android": {
|
||||||
|
"icon": "android",
|
||||||
|
"color": "#7db343",
|
||||||
|
"theme": "filled"
|
||||||
|
},
|
||||||
|
"ios": {
|
||||||
|
"icon": "apple",
|
||||||
|
"color": "#535c68",
|
||||||
|
"theme": "filled"
|
||||||
|
},
|
||||||
|
"windows": {
|
||||||
|
"icon": "windows",
|
||||||
|
"color": "#008cc4",
|
||||||
|
"theme": "filled"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"short_name": "App Store",
|
||||||
|
"name": "WSO2 IoT App Store",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "images/favicon.png",
|
||||||
|
"sizes": "16x16",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"start_url": "./index.html",
|
||||||
|
"display": "standalone",
|
||||||
|
"theme_color": "#000000",
|
||||||
|
"background_color": "#ffffff"
|
||||||
|
}
|
After Width: | Height: | Size: 443 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 7.4 KiB |
After Width: | Height: | Size: 3.4 KiB |
After Width: | Height: | Size: 1.9 KiB |
After Width: | Height: | Size: 44 KiB |
@ -0,0 +1,67 @@
|
|||||||
|
{
|
||||||
|
"Title" : "Title",
|
||||||
|
"Description" : "Description",
|
||||||
|
"ShortDescription" : "Short Description",
|
||||||
|
"Category" : "Category",
|
||||||
|
"Visibility" : "Visibility",
|
||||||
|
"Devices" : "Devices",
|
||||||
|
"Roles" : "Roles",
|
||||||
|
"Groups" : "Groups",
|
||||||
|
"Tags" : "Tags",
|
||||||
|
"Platform" : "Platform",
|
||||||
|
"Platforms" : "Platforms",
|
||||||
|
"Applications": "Applications",
|
||||||
|
"No.Platform" : "No Platforms",
|
||||||
|
"Screenshots" : "Screenshots",
|
||||||
|
"Icon" : "Icon",
|
||||||
|
"Info" : "Info",
|
||||||
|
"Banner" : "Banner",
|
||||||
|
"Create.Application" : "Create Application",
|
||||||
|
"Back" : "Back",
|
||||||
|
"Cancel" : "Cancel",
|
||||||
|
"Finish" : "Finish",
|
||||||
|
"Continue" : "Continue",
|
||||||
|
"Name" : "Name",
|
||||||
|
"Application.Name" : "Application Name",
|
||||||
|
"General" : "General",
|
||||||
|
"App.Releases" : "Application Releases",
|
||||||
|
"Package.Manager" : "Package Manager",
|
||||||
|
"Save" : "Save",
|
||||||
|
"Create.Release" : "Create Release",
|
||||||
|
"Release.Channel" : "Release Channel",
|
||||||
|
"Release" : "Release",
|
||||||
|
"New.Release.For" : "New Release for",
|
||||||
|
"Upload.Package.File" : "Upload Package File",
|
||||||
|
"Upload" : "Upload",
|
||||||
|
"Select.from.package.library" : "Select from package library",
|
||||||
|
"Release.Name" : "Release Name",
|
||||||
|
"Release.Notes" : "Release Notes",
|
||||||
|
"Send.for.Review" : "Send for Review",
|
||||||
|
"Production.Releases" : "Production Releases",
|
||||||
|
"Beta.Releases" : "Beta Releases",
|
||||||
|
"Alpha.Releases" : "Alpha Releases",
|
||||||
|
"Version" : "Version",
|
||||||
|
"Status" : "Status",
|
||||||
|
"App.Publisher" : "Application Publisher",
|
||||||
|
"Search.Apps" : "Search for Applications",
|
||||||
|
"View.In.Store" : "View in Store",
|
||||||
|
"Last.Updated" : "Last updated on",
|
||||||
|
"Installs" : "Installs",
|
||||||
|
"General.Info" : "General Info",
|
||||||
|
"Select.Platform": "Select Platform",
|
||||||
|
"Add.Release" : "Add Release to Application",
|
||||||
|
"Share.With.Tenants" : "Share with Tenants",
|
||||||
|
"Disable" : "Disable",
|
||||||
|
"File.Based" : "File Based",
|
||||||
|
"Activate" : "Activate",
|
||||||
|
"Yes" : "Yes",
|
||||||
|
"No" : "No",
|
||||||
|
"No.Platform.Tags" : "No Platform Tags",
|
||||||
|
"Create.Platform" : "Create Platform",
|
||||||
|
"Optional": "Optional",
|
||||||
|
"Identifier": "Identifier",
|
||||||
|
"Next": "Next",
|
||||||
|
"Platform.Enable": "Enable Platform",
|
||||||
|
"Share.with.Tenants": "Share between all tenants",
|
||||||
|
"Platform.Properties": "Platform Properties"
|
||||||
|
}
|
@ -0,0 +1,903 @@
|
|||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@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");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Colors*/
|
||||||
|
.primary {
|
||||||
|
color: white;
|
||||||
|
background-color: #2196f3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primary-flat {
|
||||||
|
color: #2196F3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger {
|
||||||
|
color: white;
|
||||||
|
background-color: #e91e63 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.danger-flat {
|
||||||
|
color: #e91e63 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grey {
|
||||||
|
color: #b3b3b3 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================== */
|
||||||
|
/* Custom button styles based on material design specs. */
|
||||||
|
|
||||||
|
.custom-raised {
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
text-transform: uppercase !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
padding-left: 16px !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
padding-right: 16px !important;
|
||||||
|
height: 36px !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-raised:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
||||||
|
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
||||||
|
background-color: #1976D2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-raised:focus {
|
||||||
|
box-shadow: none !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
background-color: #1976D2 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-flat {
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
height: 36px !important;
|
||||||
|
border-radius: 2px !important;
|
||||||
|
margin-left: 8px !important;
|
||||||
|
margin-right: 8px !important;
|
||||||
|
padding-left: 8px !important;
|
||||||
|
padding-right: 8px !important;
|
||||||
|
background-color: transparent !important;
|
||||||
|
text-transform: uppercase;
|
||||||
|
outline: none !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-flat:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: rgba(0, 0, 0, 0.12) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-flat:focus {
|
||||||
|
outline: none !important;
|
||||||
|
border: none !important;
|
||||||
|
-webkit-box-shadow: none !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
background-color: rgba(0, 0, 0, 0.40) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-button {
|
||||||
|
border-radius: 100% !important;
|
||||||
|
height: 36px !important;
|
||||||
|
width: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ==================================================================== */
|
||||||
|
|
||||||
|
/* Body Styling */
|
||||||
|
body {
|
||||||
|
width: 100%;
|
||||||
|
font-family: "Roboto-Regular" !important;
|
||||||
|
font-size: 14px !important;
|
||||||
|
background-color: #e8e8e8 !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*/
|
||||||
|
#userName {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#password {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-btn {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header {
|
||||||
|
background-color: #3f50b5;
|
||||||
|
color: white;
|
||||||
|
height: 128px;
|
||||||
|
width: 100%;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
#login-card {
|
||||||
|
width: 25%;
|
||||||
|
height: 50%;
|
||||||
|
margin: 10% auto;
|
||||||
|
font-family: Roboto-Regular;
|
||||||
|
font-size: 14px;
|
||||||
|
border-radius: 0;
|
||||||
|
background-color: #ffffff;
|
||||||
|
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header-title {
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
font-size: 20px;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-header-logo {
|
||||||
|
height: 70px;
|
||||||
|
width: 150px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base layout container */
|
||||||
|
|
||||||
|
/* Base layout header content*/
|
||||||
|
.header-content {
|
||||||
|
height: 128px !important;
|
||||||
|
width: 100% !important;
|
||||||
|
margin: 0 10px 0 0;
|
||||||
|
background-color: #3f50b5 !important;
|
||||||
|
position: fixed; /* Set the navbar to fixed position */
|
||||||
|
top: 0; /* Position the navbar at the top of the page */
|
||||||
|
z-index: 2;
|
||||||
|
box-shadow: -2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Contains the header styles.*/
|
||||||
|
.header {
|
||||||
|
padding: 24px 24px 10px 24px;
|
||||||
|
/*margin: 16px 16px 20px 16px;*/
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-text {
|
||||||
|
color: #ffffff;
|
||||||
|
font-size: 20px;
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
top: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The buttons in the header (User and Notification)*/
|
||||||
|
.header-button-container {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-user-name {
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
font-size: 14px;
|
||||||
|
padding-top: 15px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-image {
|
||||||
|
height: 43px;
|
||||||
|
width: 100px;
|
||||||
|
margin-right: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-button {
|
||||||
|
border-radius: 50%;
|
||||||
|
background-color: transparent;
|
||||||
|
border: none;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
margin-right: 10px;
|
||||||
|
position: relative;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-button:hover {
|
||||||
|
background-color: #4353bd;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
#header-button i {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 19px;
|
||||||
|
left: 17px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-header {
|
||||||
|
margin-top: 15px;
|
||||||
|
margin-right: 20px;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#sub-title {
|
||||||
|
font-family: Roboto-Regular;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
padding-top: 5px;
|
||||||
|
padding-left: 18px;
|
||||||
|
color: RGBA(0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Search box styles */
|
||||||
|
.search-box {
|
||||||
|
display: flex;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.search-box i {
|
||||||
|
position: absolute;
|
||||||
|
top: 5px;
|
||||||
|
color: #BaBaBa;
|
||||||
|
}
|
||||||
|
|
||||||
|
#search {
|
||||||
|
position: relative;
|
||||||
|
color: white;
|
||||||
|
background-color: transparent;
|
||||||
|
left: 15px;
|
||||||
|
top: 0px;
|
||||||
|
height: 25px;
|
||||||
|
outline: none;
|
||||||
|
border: none;
|
||||||
|
border-radius: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Application Add button */
|
||||||
|
#add-btn-container {
|
||||||
|
position: absolute;
|
||||||
|
top: 98px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn {
|
||||||
|
background-color: #ff5722;
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-btn:hover {
|
||||||
|
background-color: #E64A19;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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 pages. */
|
||||||
|
.store-card {
|
||||||
|
height: auto;
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-link-placeholder {
|
||||||
|
color: #888888;
|
||||||
|
float: right;
|
||||||
|
padding-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-link-placeholder i {
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-list {
|
||||||
|
transition: margin-right .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
#batch-content {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-list-icon {
|
||||||
|
border-radius: 50%;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-table-row {
|
||||||
|
height: 62px;
|
||||||
|
cursor: pointer;
|
||||||
|
padding-top: 6px;
|
||||||
|
font-family: "Roboto-Regular";
|
||||||
|
font-size: medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-table-row:hover {
|
||||||
|
color: white;
|
||||||
|
background-color: #3f50b5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-list-table-header {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
font-family: "Roboto-Medium";
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-view-image {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-visibility-default {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-image-screenshot {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-image-icon {
|
||||||
|
width: 300px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-image-banner {
|
||||||
|
width: 400px;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form-error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-banner-dropzone {
|
||||||
|
width: 300px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 5%;
|
||||||
|
position: relative;
|
||||||
|
border: dashed #888888 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-banner-dropzone i {
|
||||||
|
position: absolute;
|
||||||
|
top: 65px;
|
||||||
|
left: 145px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-screenshot-dropzone {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
margin: 0 5px 0 5px;
|
||||||
|
border-radius: 10%;
|
||||||
|
position: relative;
|
||||||
|
border: dashed #888888 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-screenshot-dropzone i {
|
||||||
|
position: absolute;
|
||||||
|
top: 65px;
|
||||||
|
left: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-icon-dropzone {
|
||||||
|
width: 150px;
|
||||||
|
height: 150px;
|
||||||
|
border-radius: 10%;
|
||||||
|
position: relative;
|
||||||
|
border: dashed #888888 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-create-icon-dropzone i {
|
||||||
|
position: absolute;
|
||||||
|
top: 65px;
|
||||||
|
left: 65px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#screenshot-container {
|
||||||
|
max-width: 600px;
|
||||||
|
display: flex;
|
||||||
|
overflow-x: auto;
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-icon-container {
|
||||||
|
height: 300px;
|
||||||
|
overflow-x: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#modal-body-content {
|
||||||
|
max-height: 700px;
|
||||||
|
padding-left: 24px;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-footer {
|
||||||
|
justify-content: inherit !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer-main-btn {
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
#img-btn-screenshot {
|
||||||
|
margin: 0 5px 0 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-create-modal {
|
||||||
|
max-width: 850px;
|
||||||
|
border-radius: 0% !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-create-modal-header {
|
||||||
|
background-color: #4353bd;
|
||||||
|
color: white;
|
||||||
|
padding: 24px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-create-modal-content {
|
||||||
|
padding: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
#store {
|
||||||
|
border: none;
|
||||||
|
border-bottom: solid #BDBDBD 1px;
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#version {
|
||||||
|
border: none;
|
||||||
|
border-bottom: solid #BDBDBD 1px;
|
||||||
|
border-radius: 0px;
|
||||||
|
width: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-release-switch-content {
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-release-switch-label {
|
||||||
|
position: absolute;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-release-switch {
|
||||||
|
position: absolute;
|
||||||
|
right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-sub-title {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 12px;
|
||||||
|
color: #818181;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Application View */
|
||||||
|
|
||||||
|
#application-view-content {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#application-view-row {
|
||||||
|
margin: 10px 10px 0 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-icon {
|
||||||
|
height: 100px;
|
||||||
|
width: 100px;
|
||||||
|
border: solid 1px black;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-updated-date {
|
||||||
|
color: #888888;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-install-count {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-details-tbl {
|
||||||
|
outline: none;
|
||||||
|
border-color: #2196F3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-details-tbl tr {
|
||||||
|
margin: 20px 0 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-details-tbl td {
|
||||||
|
margin-left: 10px;
|
||||||
|
max-width: 400px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Application Edit Base Layout */
|
||||||
|
|
||||||
|
#application-edit-header {
|
||||||
|
height: 40px;
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.application-header-text {
|
||||||
|
margin: 10px 0px 0px 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#save-btn-content {
|
||||||
|
float: right;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-save-btn {
|
||||||
|
border-radius: 0%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn {
|
||||||
|
margin: 5px 5px 5px 0px;
|
||||||
|
height: 70%;
|
||||||
|
width: 50%;
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-btn:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Tab styling*/
|
||||||
|
|
||||||
|
div.tab {
|
||||||
|
float: left;
|
||||||
|
border-right: 1px solid #d8d8d8;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Style the tab buttons */
|
||||||
|
|
||||||
|
div.tab button {
|
||||||
|
display: block;
|
||||||
|
background-color: inherit;
|
||||||
|
color: black;
|
||||||
|
padding: 15px 16px;
|
||||||
|
width: 100%;
|
||||||
|
border: none;
|
||||||
|
outline: none;
|
||||||
|
text-align: left;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#app-edit-content {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-app {
|
||||||
|
position: absolute;
|
||||||
|
height: 50px;
|
||||||
|
width: 50px;
|
||||||
|
border-radius: 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-app i {
|
||||||
|
padding: 12px 10px 10px 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.back-to-app:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
background-color: #dedede;
|
||||||
|
transition: .5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create Release and Release management */
|
||||||
|
|
||||||
|
.release-header {
|
||||||
|
margin-top: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-create {
|
||||||
|
height: 150px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-detail-content {
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 20%;
|
||||||
|
height: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-btn {
|
||||||
|
float: right;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-content {
|
||||||
|
height: 180px;
|
||||||
|
width: 95%;
|
||||||
|
border: dashed 1px #626262;
|
||||||
|
border-radius: 2%;
|
||||||
|
position: relative;
|
||||||
|
background-color: #e8e8e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-content:after {
|
||||||
|
content: "";
|
||||||
|
letter-spacing: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release {
|
||||||
|
margin: 30px 10px 20px 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.no-release-content {
|
||||||
|
position: absolute;
|
||||||
|
margin-top: 10px;
|
||||||
|
left: 40%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-add:hover {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release-inner {
|
||||||
|
margin-top: 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Application Edit General Info */
|
||||||
|
|
||||||
|
.app-edit-general-info {
|
||||||
|
margin-top: 20px;
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.save-info {
|
||||||
|
float: right;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-view-field {
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.app-view-text {
|
||||||
|
font-family: Roboto-Regular;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Platform Specific Styles. */
|
||||||
|
#platform-listing {
|
||||||
|
margin: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.create-platform i {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#platform-list {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content {
|
||||||
|
margin: 10px;
|
||||||
|
padding-top: 16px;
|
||||||
|
box-shadow: 2px 4px 8px 0 rgba(0, 0, 0, 0.2), 0 6px 20px 0 rgba(0, 0, 0, 0.19);
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content .row {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content .col {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content-basic {
|
||||||
|
padding: 0 16px 0 16px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content-more-outer {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content-more {
|
||||||
|
padding: 16px 16px 24px 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-content-footer {
|
||||||
|
display: flex;
|
||||||
|
padding: 8px 8px 8px 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-text-container {
|
||||||
|
padding: 8px 16px 0 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-button {
|
||||||
|
float: right;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-icon-letter {
|
||||||
|
text-align: center;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
font-size: 70px;
|
||||||
|
color: white;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-icon-container {
|
||||||
|
height: 120px;
|
||||||
|
width: 120px;
|
||||||
|
background-color: #01579B;
|
||||||
|
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
||||||
|
-webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-property-container {
|
||||||
|
padding-top: 20px;
|
||||||
|
font-family: Roboto-Regular;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.platform-property-row {
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn-clear {
|
||||||
|
background-color: white !important;
|
||||||
|
color: rgba(0, 0, 0, 0.50) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn-clear:hover {
|
||||||
|
background-color: white !important;
|
||||||
|
color: rgba(0, 0, 0, 0.38) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn-clear:focus {
|
||||||
|
background-color: white !important;
|
||||||
|
color: rgba(0, 0, 0, 0.60) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.data-table-row-cell {
|
||||||
|
padding-top: 14px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-code {
|
||||||
|
text-align: center;
|
||||||
|
font-family: Roboto-Medium;
|
||||||
|
font-weight: 800;
|
||||||
|
font-size: 15em;
|
||||||
|
color: #BaBaBa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-code p {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-text {
|
||||||
|
text-align: center;
|
||||||
|
font-family: Roboto-Regular;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 500;
|
||||||
|
color: #9e9e9e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn-add {
|
||||||
|
background-color: #bababa !important;
|
||||||
|
border-radius: 50% !important;
|
||||||
|
height: 30px !important;
|
||||||
|
width: 30px;
|
||||||
|
text-align: -webkit-center;
|
||||||
|
font-size: 18px;
|
||||||
|
padding: 6px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.circle-btn-add:hover {
|
||||||
|
background-color: #828282 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
If you need to change the color of active steps in stepper,
|
||||||
|
uncomment the following and set the background color and font color as needed.
|
||||||
|
*/
|
||||||
|
/*
|
||||||
|
.stepper-active-index {
|
||||||
|
background-color: #0a6eff !important;
|
||||||
|
color: white !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.stepper-passed-index {
|
||||||
|
background-color: #0a6eff !important;
|
||||||
|
color: green !important;
|
||||||
|
}
|
||||||
|
*/
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.ant-upload.ant-upload-drag {
|
||||||
|
height: 170px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release .release-icon{
|
||||||
|
margin-right: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release .release-icon img{
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 28%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release .release-title{
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.release .release-screenshot img{
|
||||||
|
width: 100%;
|
||||||
|
border-radius: 15px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-image {
|
||||||
|
/*width: 120px;*/
|
||||||
|
height: 31px;
|
||||||
|
margin: 0 5px 16px 24px;
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo-image img{
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-container{
|
||||||
|
background: #f0f2f5;
|
||||||
|
min-height: 780px
|
||||||
|
}
|
||||||
|
|
||||||
|
.profile{
|
||||||
|
float:right;
|
||||||
|
margin-right: 2%;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media only screen and (min-width: 768px) {
|
||||||
|
.main-container{
|
||||||
|
padding: 24px;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,111 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import "antd/dist/antd.less";
|
||||||
|
import RouteWithSubRoutes from "./components/RouteWithSubRoutes";
|
||||||
|
import {
|
||||||
|
BrowserRouter as Router,
|
||||||
|
Redirect, Switch,
|
||||||
|
} from 'react-router-dom';
|
||||||
|
import axios from "axios";
|
||||||
|
import {Layout, Spin, Result} from "antd";
|
||||||
|
import ConfigContext from "./context/ConfigContext";
|
||||||
|
|
||||||
|
const {Content} = Layout;
|
||||||
|
const loadingView = (
|
||||||
|
<Layout>
|
||||||
|
<Content style={{
|
||||||
|
padding: '0 0',
|
||||||
|
paddingTop: 300,
|
||||||
|
backgroundColor: '#fff',
|
||||||
|
textAlign: 'center'
|
||||||
|
}}>
|
||||||
|
<Spin tip="Loading..."/>
|
||||||
|
</Content>
|
||||||
|
</Layout>
|
||||||
|
);
|
||||||
|
|
||||||
|
const errorView = (
|
||||||
|
<Result
|
||||||
|
style={{
|
||||||
|
paddingTop: 200
|
||||||
|
}}
|
||||||
|
status="500"
|
||||||
|
title="Error occurred while loading the configuration"
|
||||||
|
subTitle="Please refresh your browser window"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
|
||||||
|
class App extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
error: false,
|
||||||
|
config: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
axios.get(
|
||||||
|
window.location.origin + "/store/public/conf/config.json",
|
||||||
|
).then(res => {
|
||||||
|
console.log(res);
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
config: res.data
|
||||||
|
})
|
||||||
|
}).catch((error) => {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
error: true
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {loading, error} = this.state;
|
||||||
|
|
||||||
|
const applicationView = (
|
||||||
|
<Router>
|
||||||
|
<ConfigContext.Provider value={this.state.config}>
|
||||||
|
<div>
|
||||||
|
<Switch>
|
||||||
|
<Redirect exact from="/store" to="/store/android"/>
|
||||||
|
{this.props.routes.map((route) => (
|
||||||
|
<RouteWithSubRoutes key={route.path} {...route} />
|
||||||
|
))}
|
||||||
|
</Switch>
|
||||||
|
</div>
|
||||||
|
</ConfigContext.Provider>
|
||||||
|
</Router>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{loading && loadingView}
|
||||||
|
{!loading && !error && applicationView}
|
||||||
|
{error && errorView}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default App;
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import App from './App';
|
||||||
|
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
ReactDOM.render(<App />, div);
|
||||||
|
ReactDOM.unmountComponentAtNode(div);
|
||||||
|
});
|
@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from 'react';
|
||||||
|
import {Route} from 'react-router-dom';
|
||||||
|
class RouteWithSubRoutes extends React.Component{
|
||||||
|
props;
|
||||||
|
constructor(props){
|
||||||
|
super(props);
|
||||||
|
this.props = props;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
return(
|
||||||
|
<Route path={this.props.path} exact={this.props.exact} render={(props) => (
|
||||||
|
<this.props.component {...props} {...this.props} routes={this.props.routes}/>
|
||||||
|
)}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default RouteWithSubRoutes;
|
@ -0,0 +1,78 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 {Card, Typography, Col, Row} from 'antd';
|
||||||
|
import React from "react";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import "../../App.css";
|
||||||
|
import StarRatings from 'react-star-ratings';
|
||||||
|
|
||||||
|
const {Meta} = Card;
|
||||||
|
const {Text} = Typography;
|
||||||
|
|
||||||
|
class AppCard extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.handleReleasesClick = this.handleReleasesClick.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
handleReleasesClick() {
|
||||||
|
this.props.openReleasesModal(this.props.app);
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const app = this.props.app;
|
||||||
|
const release = this.props.app.applicationReleases[0];
|
||||||
|
|
||||||
|
const description = (
|
||||||
|
<div className="appCard">
|
||||||
|
<Link to={"/store/"+app.deviceType+"/apps/" + release.uuid}>
|
||||||
|
<Row className="release">
|
||||||
|
<Col span={24} className="release-icon">
|
||||||
|
<img src={release.iconPath} alt="icon"/>
|
||||||
|
{/*<Avatar shape="square" size={128} src={release.iconPath} />*/}
|
||||||
|
</Col>
|
||||||
|
<Col span={24}>
|
||||||
|
<Text strong level={4}>{app.name}</Text><br/>
|
||||||
|
<Text type="secondary" level={4}>{app.deviceType}</Text><br/>
|
||||||
|
<StarRatings
|
||||||
|
rating={app.rating}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starDimension = "12px"
|
||||||
|
starSpacing = "0"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Card style={{marginTop: 16}}>
|
||||||
|
<Meta
|
||||||
|
description={description}
|
||||||
|
/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppCard;
|
@ -0,0 +1,120 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import AppCard from "./AppCard";
|
||||||
|
import {Col, message, notification, Row, Result, Skeleton} from "antd";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../context/ConfigContext";
|
||||||
|
|
||||||
|
class AppList extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
apps: [],
|
||||||
|
loading: true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const {deviceType} = this.props;
|
||||||
|
this.props.changeSelectedMenuItem(deviceType);
|
||||||
|
this.fetchData(deviceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
if (prevProps.deviceType !== this.props.deviceType) {
|
||||||
|
const {deviceType} = this.props;
|
||||||
|
this.props.changeSelectedMenuItem(deviceType);
|
||||||
|
this.fetchData(deviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData = (deviceType) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
const payload = {};
|
||||||
|
if (deviceType === "web-clip") {
|
||||||
|
payload.appType = "WEB_CLIP";
|
||||||
|
} else {
|
||||||
|
payload.deviceType = deviceType;
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
//send request to the invoker
|
||||||
|
axios.post(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/applications/",
|
||||||
|
payload,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
//todo remove this property check after backend improvement
|
||||||
|
let apps = (res.data.data.hasOwnProperty("applications")) ? res.data.data.applications : [];
|
||||||
|
this.setState({
|
||||||
|
apps: apps,
|
||||||
|
loading: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error.response);
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||||
|
//todo display a popup with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load apps.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({loading: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {apps,loading} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Skeleton loading={loading} active>
|
||||||
|
<Row gutter={16}>
|
||||||
|
{apps.length === 0 && (
|
||||||
|
<Result
|
||||||
|
status="404"
|
||||||
|
title="No apps, yet."
|
||||||
|
subTitle="No apps available, yet! When the administration uploads, apps will show up here."
|
||||||
|
// extra={<Button type="primary">Back Home</Button>}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{apps.map(app => (
|
||||||
|
<Col key={app.id} xs={12} sm={6} md={6} lg={4} xl={3}>
|
||||||
|
<AppCard key={app.id}
|
||||||
|
app={app}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
))}
|
||||||
|
</Row>
|
||||||
|
</Skeleton>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(AppList);
|
@ -0,0 +1,90 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.d-rating .numeric-data{
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px 0 20px 0;
|
||||||
|
vertical-align: top;
|
||||||
|
text-align: center;
|
||||||
|
width: 30%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .bar-containers{
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 20px 20px 20px 30px;
|
||||||
|
vertical-align: top;
|
||||||
|
width: 70%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .bar-containers .bar-container{
|
||||||
|
color: #737373;
|
||||||
|
font-weight: 400;
|
||||||
|
height: 20px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
position: relative;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .bar-containers .bar-container .number{
|
||||||
|
font-size: 11px;
|
||||||
|
left: -16px;
|
||||||
|
letter-spacing: 1px;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .bar-containers .bar-container .bar{
|
||||||
|
transition: width .25s ease;
|
||||||
|
display: inline-block;
|
||||||
|
height: 100%;
|
||||||
|
opacity: .8;
|
||||||
|
border-radius: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-container .rate-5{
|
||||||
|
background: #57bb8a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-container .rate-4{
|
||||||
|
background: #9ace6a;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-container .rate-3{
|
||||||
|
background: #ffcf02;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-container .rate-2{
|
||||||
|
background: #ff9f02;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bar-container .rate-1{
|
||||||
|
background: #ff6f31;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .numeric-data .rate{
|
||||||
|
color: #333;
|
||||||
|
font-size: 64px;
|
||||||
|
font-weight: 100;
|
||||||
|
line-height: 64px;
|
||||||
|
padding-bottom: 6px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.d-rating .numeric-data .people-count{
|
||||||
|
padding-top: 6px;
|
||||||
|
}
|
@ -0,0 +1,140 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Row, Typography, Icon} from "antd";
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import "./DetailedRating.css";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
|
||||||
|
class DetailedRating extends React.Component{
|
||||||
|
|
||||||
|
constructor(props){
|
||||||
|
super(props);
|
||||||
|
this.state={
|
||||||
|
detailedRating: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const {type,uuid} = this.props;
|
||||||
|
this.getData(type,uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState) {
|
||||||
|
if (prevProps.uuid !== this.props.uuid) {
|
||||||
|
const {type,uuid} = this.props;
|
||||||
|
this.getData(type,uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getData = (type, uuid)=>{
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
return axios.get(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri +config.serverConfig.invoker.store+"/reviews/"+uuid+"/"+type+"-rating",
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let detailedRating = res.data.data;
|
||||||
|
this.setState({
|
||||||
|
detailedRating
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+'/store/login';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const detailedRating = this.state.detailedRating;
|
||||||
|
|
||||||
|
if(detailedRating ==null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalCount = detailedRating.noOfUsers;
|
||||||
|
const ratingVariety = detailedRating.ratingVariety;
|
||||||
|
|
||||||
|
const ratingArray = [];
|
||||||
|
|
||||||
|
for (let [key, value] of Object.entries(ratingVariety)) {
|
||||||
|
ratingArray.push(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
const maximumRating = Math.max(...ratingArray);
|
||||||
|
|
||||||
|
const ratingBarPercentages = [0,0,0,0,0];
|
||||||
|
|
||||||
|
if(maximumRating>0){
|
||||||
|
for(let i = 0; i<5; i++){
|
||||||
|
ratingBarPercentages[i] = (ratingVariety[(i+1).toString()])/maximumRating*100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Row className="d-rating">
|
||||||
|
<div className="numeric-data">
|
||||||
|
<div className="rate">{detailedRating.ratingValue.toFixed(1)}</div>
|
||||||
|
<StarRatings
|
||||||
|
rating={detailedRating.ratingValue}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starDimension = "16px"
|
||||||
|
starSpacing = "2px"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
<br/>
|
||||||
|
<Text type="secondary" className="people-count"><Icon type="team" /> {totalCount} total</Text>
|
||||||
|
</div>
|
||||||
|
<div className="bar-containers">
|
||||||
|
<div className="bar-container">
|
||||||
|
<span className="number">5</span>
|
||||||
|
<span className="bar rate-5" style={{width: ratingBarPercentages[4]+"%"}}> </span>
|
||||||
|
</div>
|
||||||
|
<div className="bar-container">
|
||||||
|
<span className="number">4</span>
|
||||||
|
<span className="bar rate-4" style={{width: ratingBarPercentages[3]+"%"}}> </span>
|
||||||
|
</div>
|
||||||
|
<div className="bar-container">
|
||||||
|
<span className="number">3</span>
|
||||||
|
<span className="bar rate-3" style={{width: ratingBarPercentages[2]+"%"}}> </span>
|
||||||
|
</div>
|
||||||
|
<div className="bar-container">
|
||||||
|
<span className="number">2</span>
|
||||||
|
<span className="bar rate-2" style={{width: ratingBarPercentages[1]+"%"}}> </span>
|
||||||
|
</div>
|
||||||
|
<div className="bar-container">
|
||||||
|
<span className="number">1</span>
|
||||||
|
<span className="bar rate-1" style={{width: ratingBarPercentages[0]+"%"}}> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default withConfigContext(DetailedRating);
|
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Divider, Row, Col, Typography, Button, Rate, notification} from "antd";
|
||||||
|
import "../../../App.css";
|
||||||
|
import ImgViewer from "../../apps/release/images/ImgViewer";
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import DetailedRating from "./DetailedRating";
|
||||||
|
import Reviews from "./review/Reviews";
|
||||||
|
import axios from "axios";
|
||||||
|
import AppInstallModal from "./install/AppInstallModal";
|
||||||
|
import CurrentUsersReview from "./review/CurrentUsersReview";
|
||||||
|
import {withConfigContext} from "../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Title, Text, Paragraph} = Typography;
|
||||||
|
|
||||||
|
class ReleaseView extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
loading: false,
|
||||||
|
appInstallModalVisible: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
installApp = (type, payload) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
const release = this.props.app.applicationReleases[0];
|
||||||
|
const {uuid} = release;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
const url = window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/subscription/" + uuid + "/" + type + "/install";
|
||||||
|
axios.post(
|
||||||
|
url,
|
||||||
|
payload,
|
||||||
|
{
|
||||||
|
headers: {'X-Platform': config.serverConfig.platform}
|
||||||
|
}
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
appInstallModalVisible: false
|
||||||
|
});
|
||||||
|
notification["success"]({
|
||||||
|
message: 'Done!',
|
||||||
|
description:
|
||||||
|
'App installed triggered.',
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while installing app",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while installing the app.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
showAppInstallModal = () => {
|
||||||
|
this.setState({
|
||||||
|
appInstallModalVisible: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
closeAppInstallModal = () => {
|
||||||
|
this.setState({
|
||||||
|
appInstallModalVisible: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {app,deviceType} = this.props;
|
||||||
|
const release = app.applicationReleases[0];
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<AppInstallModal
|
||||||
|
uuid={release.uuid}
|
||||||
|
visible={this.state.appInstallModalVisible}
|
||||||
|
deviceType = {deviceType}
|
||||||
|
onClose={this.closeAppInstallModal}
|
||||||
|
onInstall={this.installApp}/>
|
||||||
|
<div className="release">
|
||||||
|
<Row>
|
||||||
|
<Col xl={4} sm={6} xs={8} className="release-icon">
|
||||||
|
<img src={release.iconPath} alt="icon"/>
|
||||||
|
</Col>
|
||||||
|
<Col xl={10} sm={11} className="release-title">
|
||||||
|
<Title level={2}>{app.name}</Title>
|
||||||
|
<Text>Version : {release.version}</Text><br/><br/>
|
||||||
|
<StarRatings
|
||||||
|
rating={app.rating}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starDimension="20px"
|
||||||
|
starSpacing="2px"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
<Col xl={8} md={10} sm={24} xs={24} style={{float: "right"}}>
|
||||||
|
<div>
|
||||||
|
<Button.Group style={{float: "right"}}>
|
||||||
|
<Button onClick={this.showAppInstallModal} loading={this.state.loading}
|
||||||
|
htmlType="button" type="primary" icon="download">Install</Button>
|
||||||
|
</Button.Group>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider/>
|
||||||
|
<Row>
|
||||||
|
<ImgViewer images={release.screenshots}/>
|
||||||
|
</Row>
|
||||||
|
<Divider/>
|
||||||
|
<Paragraph type="secondary" ellipsis={{rows: 3, expandable: true}}>
|
||||||
|
{release.description}
|
||||||
|
</Paragraph>
|
||||||
|
<Divider/>
|
||||||
|
<CurrentUsersReview uuid={release.uuid}/>
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
<Text>REVIEWS</Text>
|
||||||
|
<Row>
|
||||||
|
<Col lg={18} md={24}>
|
||||||
|
<DetailedRating type="app" uuid={release.uuid}/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Reviews type="app" uuid={release.uuid}/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(ReleaseView);
|
@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 RcViewer from 'rc-viewer';
|
||||||
|
import {Col} from "antd";
|
||||||
|
|
||||||
|
class ImgViewer extends Component {
|
||||||
|
render() {
|
||||||
|
const options = {
|
||||||
|
title: false,
|
||||||
|
toolbar: {
|
||||||
|
zoomIn: 0,
|
||||||
|
zoomOut: 0,
|
||||||
|
oneToOne: 0,
|
||||||
|
reset: 0,
|
||||||
|
prev: 1,
|
||||||
|
play: {
|
||||||
|
show: 0
|
||||||
|
},
|
||||||
|
next: 1,
|
||||||
|
rotateLeft: 0,
|
||||||
|
rotateRight: 0,
|
||||||
|
flipHorizontal: 0,
|
||||||
|
flipVertical: 0
|
||||||
|
},
|
||||||
|
rotatable: false,
|
||||||
|
transition: false,
|
||||||
|
movable : false
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<RcViewer options={options} ref='viewer'>
|
||||||
|
{this.props.images.map((screenshotUrl) => {
|
||||||
|
return (
|
||||||
|
<Col key={"col-" + screenshotUrl} lg={6} md={8} xs={8} className="release-screenshot">
|
||||||
|
<img key={screenshotUrl} src={screenshotUrl}/>
|
||||||
|
</Col>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</RcViewer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ImgViewer;
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Modal, Tabs} from "antd";
|
||||||
|
import UserInstall from "./UserInstall";
|
||||||
|
import GroupInstall from "./GroupInstall";
|
||||||
|
import RoleInstall from "./RoleInstall";
|
||||||
|
import DeviceInstall from "./DeviceInstall";
|
||||||
|
|
||||||
|
const { TabPane } = Tabs;
|
||||||
|
|
||||||
|
class AppInstallModal extends React.Component{
|
||||||
|
state={
|
||||||
|
data:[]
|
||||||
|
};
|
||||||
|
render() {
|
||||||
|
const {deviceType} = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Modal
|
||||||
|
title="Install App"
|
||||||
|
visible={this.props.visible}
|
||||||
|
onCancel={this.props.onClose}
|
||||||
|
footer={null}
|
||||||
|
>
|
||||||
|
<Tabs defaultActiveKey="device">
|
||||||
|
<TabPane tab="Device" key="device">
|
||||||
|
<DeviceInstall deviceType={deviceType} onInstall={this.props.onInstall}/>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="User" key="user">
|
||||||
|
<UserInstall onInstall={this.props.onInstall}/>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="Role" key="role">
|
||||||
|
<RoleInstall onInstall={this.props.onInstall}/>
|
||||||
|
</TabPane>
|
||||||
|
<TabPane tab="Group" key="group">
|
||||||
|
<GroupInstall onInstall={this.props.onInstall}/>
|
||||||
|
</TabPane>
|
||||||
|
</Tabs>
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppInstallModal;
|
@ -0,0 +1,248 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import axios from "axios";
|
||||||
|
import {Button, message, notification, Table, Typography} from "antd";
|
||||||
|
import TimeAgo from 'javascript-time-ago'
|
||||||
|
|
||||||
|
// Load locale-specific relative date/time formatting rules.
|
||||||
|
import en from 'javascript-time-ago/locale/en'
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: 'Device',
|
||||||
|
dataIndex: 'name',
|
||||||
|
fixed: 'left',
|
||||||
|
width: 100,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Modal',
|
||||||
|
dataIndex: 'deviceInfo',
|
||||||
|
key: 'modal',
|
||||||
|
render: deviceInfo => `${deviceInfo.vendor} ${deviceInfo.deviceModel}`
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Owner',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'owner',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.owner
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Last Updated',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'dateOfLastUpdate',
|
||||||
|
render: (data) => {
|
||||||
|
return (getTimeAgo(data.dateOfLastUpdate));
|
||||||
|
}
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Status',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'status',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.status
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Ownership',
|
||||||
|
dataIndex: 'enrolmentInfo',
|
||||||
|
key: 'ownership',
|
||||||
|
render: enrolmentInfo => enrolmentInfo.ownership
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'OS Version',
|
||||||
|
dataIndex: 'deviceInfo',
|
||||||
|
key: 'osVersion',
|
||||||
|
render: deviceInfo => deviceInfo.osVersion
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'IMEI',
|
||||||
|
dataIndex: 'properties',
|
||||||
|
key: 'imei',
|
||||||
|
render: properties => {
|
||||||
|
let imei = "not-found";
|
||||||
|
for (let i = 0; i < properties.length; i++) {
|
||||||
|
if (properties[i].name === "IMEI") {
|
||||||
|
imei = properties[i].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return imei;
|
||||||
|
}
|
||||||
|
// todo add filtering options
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const getTimeAgo = (time) => {
|
||||||
|
const timeAgo = new TimeAgo('en-US');
|
||||||
|
return timeAgo.format(time);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class DeviceInstall extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
TimeAgo.addLocale(en);
|
||||||
|
this.state = {
|
||||||
|
data: [],
|
||||||
|
pagination: {},
|
||||||
|
loading: false,
|
||||||
|
selectedRows: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
rowSelection = {
|
||||||
|
onChange: (selectedRowKeys, selectedRows) => {
|
||||||
|
// console.log(`selectedRowKeys: ${selectedRowKeys}`, 'selectedRows: ', selectedRows);
|
||||||
|
this.setState({
|
||||||
|
selectedRows: selectedRows
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getCheckboxProps: record => ({
|
||||||
|
disabled: record.name === 'Disabled User', // Column configuration not to be checked
|
||||||
|
name: record.name,
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
//fetch data from api
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({loading: true});
|
||||||
|
const {deviceType} = this.props;
|
||||||
|
// get current page
|
||||||
|
const currentPage = (params.hasOwnProperty("page")) ? params.page : 1;
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (currentPage - 1), //calculate the offset
|
||||||
|
limit: 10,
|
||||||
|
status: "ACTIVE",
|
||||||
|
requireDeviceInfo: true,
|
||||||
|
type: deviceType
|
||||||
|
};
|
||||||
|
|
||||||
|
// note: encode with '%26' not '&'
|
||||||
|
const encodedExtraParams = Object.keys(extraParams).map(key => key + '=' + extraParams[key]).join('&');
|
||||||
|
|
||||||
|
//send request to the invoker
|
||||||
|
axios.get(
|
||||||
|
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt +
|
||||||
|
"/devices?" + encodedExtraParams,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const pagination = {...this.state.pagination};
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
data: res.data.data.devices,
|
||||||
|
pagination,
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
if (error.hasOwnProperty("status") && error.response.status === 401) {
|
||||||
|
//todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load devices.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({loading: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleTableChange = (pagination, filters, sorter) => {
|
||||||
|
const pager = {...this.state.pagination};
|
||||||
|
pager.current = pagination.current;
|
||||||
|
this.setState({
|
||||||
|
pagination: pager,
|
||||||
|
});
|
||||||
|
this.fetch({
|
||||||
|
results: pagination.pageSize,
|
||||||
|
page: pagination.current,
|
||||||
|
sortField: sorter.field,
|
||||||
|
sortOrder: sorter.order,
|
||||||
|
...filters,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
install = () => {
|
||||||
|
const {selectedRows} = this.state;
|
||||||
|
const payload = [];
|
||||||
|
selectedRows.map(device => {
|
||||||
|
payload.push({
|
||||||
|
id: device.deviceIdentifier,
|
||||||
|
type: device.type
|
||||||
|
});
|
||||||
|
});
|
||||||
|
this.props.onInstall("devices", payload);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {data, pagination, loading, selectedRows} = this.state;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>
|
||||||
|
Start installing the application for one or more users by entering the corresponding user name.
|
||||||
|
Select install to automatically start downloading the application for the respective user/users.
|
||||||
|
</Text>
|
||||||
|
<Table
|
||||||
|
style={{paddingTop: 20}}
|
||||||
|
columns={columns}
|
||||||
|
rowKey={record => record.deviceIdentifier}
|
||||||
|
dataSource={data}
|
||||||
|
pagination={{
|
||||||
|
...pagination,
|
||||||
|
size: "small",
|
||||||
|
// position: "top",
|
||||||
|
showTotal: (total, range) => `showing ${range[0]}-${range[1]} of ${total} devices`
|
||||||
|
// showQuickJumper: true
|
||||||
|
}}
|
||||||
|
loading={loading}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
rowSelection={this.rowSelection}
|
||||||
|
scroll={{x: 1000}}
|
||||||
|
/>
|
||||||
|
<div style={{paddingTop: 10, textAlign: "right"}}>
|
||||||
|
<Button disabled={selectedRows.length === 0} htmlType="button" type="primary"
|
||||||
|
onClick={this.install}>
|
||||||
|
Install
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(DeviceInstall);
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Typography, Select, Spin, message, notification, Button} from "antd";
|
||||||
|
import debounce from 'lodash.debounce';
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
|
|
||||||
|
class GroupInstall extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.lastFetchId = 0;
|
||||||
|
this.fetchUser = debounce(this.fetchUser, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
data: [],
|
||||||
|
value: [],
|
||||||
|
fetching: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUser = value => {
|
||||||
|
this.lastFetchId += 1;
|
||||||
|
const fetchId = this.lastFetchId;
|
||||||
|
const config = this.props.context;
|
||||||
|
this.setState({data: [], fetching: true});
|
||||||
|
|
||||||
|
axios.post(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/groups?name=" + value,
|
||||||
|
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
if (fetchId !== this.lastFetchId) {
|
||||||
|
// for fetch callback order
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = res.data.data.deviceGroups.map(group => ({
|
||||||
|
text: group.name,
|
||||||
|
value: group.name,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.setState({data, fetching: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => { console.log(error);
|
||||||
|
if (error.hasOwnProperty("status") && error.response.status === 401) {
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin+'/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load groups.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({fetching: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = value => {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
data: [],
|
||||||
|
fetching: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
install = () =>{
|
||||||
|
const {value} = this.state;
|
||||||
|
const data = [];
|
||||||
|
value.map(val=>{
|
||||||
|
data.push(val.key);
|
||||||
|
});
|
||||||
|
this.props.onInstall("group",data);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const {fetching, data, value} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>Start installing the application for one or more groups by entering the corresponding group name. Select install to automatically start downloading the application for the respective device group/ groups.</Text>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
labelInValue
|
||||||
|
value={value}
|
||||||
|
placeholder="Search groups"
|
||||||
|
notFoundContent={fetching ? <Spin size="small"/> : null}
|
||||||
|
filterOption={false}
|
||||||
|
onSearch={this.fetchUser}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
style={{width: '100%'}}
|
||||||
|
>
|
||||||
|
{data.map(d => (
|
||||||
|
<Option key={d.value}>{d.text}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<div style={{paddingTop:10, textAlign:"right"}}>
|
||||||
|
<Button disabled={value.length===0} htmlType="button" type="primary" onClick={this.install}>Install</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(GroupInstall);
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Typography, Select, Spin, message, notification, Button} from "antd";
|
||||||
|
import debounce from 'lodash.debounce';
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
|
|
||||||
|
class RoleInstall extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.lastFetchId = 0;
|
||||||
|
this.fetchUser = debounce(this.fetchUser, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
data: [],
|
||||||
|
value: [],
|
||||||
|
fetching: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUser = value => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.lastFetchId += 1;
|
||||||
|
const fetchId = this.lastFetchId;
|
||||||
|
this.setState({data: [], fetching: true});
|
||||||
|
|
||||||
|
axios.get(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/roles?filter=" + value,
|
||||||
|
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
if (fetchId !== this.lastFetchId) {
|
||||||
|
// for fetch callback order
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = res.data.data.roles.map(role => ({
|
||||||
|
text: role,
|
||||||
|
value: role,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.setState({data, fetching: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => { console.log(error);
|
||||||
|
if (error.hasOwnProperty("status") && error.response.status === 401) {
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin+'/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load roles.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({fetching: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = value => {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
data: [],
|
||||||
|
fetching: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
install = () =>{
|
||||||
|
const {value} = this.state;
|
||||||
|
const data = [];
|
||||||
|
value.map(val=>{
|
||||||
|
data.push(val.key);
|
||||||
|
});
|
||||||
|
this.props.onInstall("role",data);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
|
||||||
|
const {fetching, data, value} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>Start installing the application for one or more roles by entering the corresponding role name. Select install to automatically start downloading the application for the respective user role/roles.</Text>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
labelInValue
|
||||||
|
value={value}
|
||||||
|
placeholder="Search roles"
|
||||||
|
notFoundContent={fetching ? <Spin size="small"/> : null}
|
||||||
|
filterOption={false}
|
||||||
|
onSearch={this.fetchUser}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
style={{width: '100%'}}
|
||||||
|
>
|
||||||
|
{data.map(d => (
|
||||||
|
<Option key={d.value}>{d.text}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<div style={{paddingTop:10, textAlign:"right"}}>
|
||||||
|
<Button disabled={value.length===0} htmlType="button" type="primary" onClick={this.install}>Install</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(RoleInstall);
|
@ -0,0 +1,133 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Typography, Select, Spin, message, notification, Button} from "antd";
|
||||||
|
import debounce from 'lodash.debounce';
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text} = Typography;
|
||||||
|
const {Option} = Select;
|
||||||
|
|
||||||
|
|
||||||
|
class UserInstall extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.lastFetchId = 0;
|
||||||
|
this.fetchUser = debounce(this.fetchUser, 800);
|
||||||
|
}
|
||||||
|
|
||||||
|
state = {
|
||||||
|
data: [],
|
||||||
|
value: [],
|
||||||
|
fetching: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchUser = value => {
|
||||||
|
const config = this.props.context;
|
||||||
|
this.lastFetchId += 1;
|
||||||
|
const fetchId = this.lastFetchId;
|
||||||
|
this.setState({data: [], fetching: true});
|
||||||
|
|
||||||
|
|
||||||
|
//send request to the invoker
|
||||||
|
axios.get(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt+"/users/search?username=" + value,
|
||||||
|
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
if (fetchId !== this.lastFetchId) {
|
||||||
|
// for fetch callback order
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const data = res.data.data.users.map(user => ({
|
||||||
|
text: user.username,
|
||||||
|
value: user.username,
|
||||||
|
}));
|
||||||
|
|
||||||
|
this.setState({data, fetching: false});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.hasOwnProperty(status) && error.response.status === 401) {
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load users.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({fetching: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = value => {
|
||||||
|
this.setState({
|
||||||
|
value,
|
||||||
|
data: [],
|
||||||
|
fetching: false,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
install = () => {
|
||||||
|
const {value} = this.state;
|
||||||
|
const data = [];
|
||||||
|
value.map(val => {
|
||||||
|
data.push(val.key);
|
||||||
|
});
|
||||||
|
this.props.onInstall("user", data);
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {fetching, data, value} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>Start installing the application for one or more users by entering the corresponding user name. Select install to automatically start downloading the application for the respective user/users. </Text>
|
||||||
|
<p>Select users</p>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
labelInValue
|
||||||
|
value={value}
|
||||||
|
placeholder="Enter the username"
|
||||||
|
notFoundContent={fetching ? <Spin size="small"/> : null}
|
||||||
|
filterOption={false}
|
||||||
|
onSearch={this.fetchUser}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
style={{width: '100%'}}
|
||||||
|
>
|
||||||
|
{data.map(d => (
|
||||||
|
<Option key={d.value}>{d.text}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
|
<div style={{paddingTop: 10, textAlign: "right"}}>
|
||||||
|
<Button disabled={value.length===0} htmlType="button" type="primary" onClick={this.install}>Install</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(UserInstall);
|
@ -0,0 +1,181 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Drawer, Button, Icon, Row, Col, Typography, Divider, Input, Spin, notification} from 'antd';
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
const {TextArea} = Input;
|
||||||
|
|
||||||
|
class AddReview extends React.Component {
|
||||||
|
state = {
|
||||||
|
visible: false,
|
||||||
|
content: '',
|
||||||
|
rating: 0,
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
|
||||||
|
showDrawer = () => {
|
||||||
|
this.setState({
|
||||||
|
visible: true,
|
||||||
|
content: '',
|
||||||
|
rating: 0,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onClose = () => {
|
||||||
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
changeRating = (newRating, name) => {
|
||||||
|
this.setState({
|
||||||
|
rating: newRating
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onChange = (e) => {
|
||||||
|
this.setState({content: e.target.value})
|
||||||
|
};
|
||||||
|
|
||||||
|
onSubmit = () => {
|
||||||
|
const config = this.props.context;
|
||||||
|
const {content, rating} = this.state;
|
||||||
|
const {uuid} = this.props;
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
content: content,
|
||||||
|
rating: rating
|
||||||
|
};
|
||||||
|
|
||||||
|
axios.post(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/reviews/" + uuid,
|
||||||
|
payload,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 201) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["success"]({
|
||||||
|
message: 'Done!',
|
||||||
|
description:
|
||||||
|
'Your review has been posted successfully.',
|
||||||
|
});
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
window.location.href = uuid;
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"We are unable to add your review right now.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"We are unable to add your review right now.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Button type="primary" onClick={this.showDrawer}>
|
||||||
|
<Icon type="star"/> Add a review
|
||||||
|
</Button>
|
||||||
|
|
||||||
|
<Drawer
|
||||||
|
// title="Basic Drawer"
|
||||||
|
placement="bottom"
|
||||||
|
closable={false}
|
||||||
|
onClose={this.onClose}
|
||||||
|
visible={this.state.visible}
|
||||||
|
height={400}
|
||||||
|
>
|
||||||
|
<Spin spinning={this.state.loading} tip="Posting your review...">
|
||||||
|
<Row>
|
||||||
|
<Col lg={8}/>
|
||||||
|
<Col lg={8}>
|
||||||
|
<Title level={4}>Add review</Title>
|
||||||
|
<Divider/>
|
||||||
|
<TextArea
|
||||||
|
placeholder="Tell others what you think about this app. Would you recommend it, and why?"
|
||||||
|
onChange={this.onChange}
|
||||||
|
rows={4}
|
||||||
|
value={this.state.content || ''}
|
||||||
|
style={{marginBottom: 20}}
|
||||||
|
/>
|
||||||
|
<StarRatings
|
||||||
|
rating={this.state.rating}
|
||||||
|
changeRating={this.changeRating}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starHoverColor="#444"
|
||||||
|
starDimension="20px"
|
||||||
|
starSpacing="2px"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
<br/><br/>
|
||||||
|
<Button onClick={this.onClose} style={{marginRight: 8}}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button disabled={this.state.rating === 0} onClick={this.onSubmit} type="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Spin>
|
||||||
|
</Drawer>
|
||||||
|
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(AddReview);
|
@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {List, message, Typography, Empty, Button, Row, Col, notification} from "antd";
|
||||||
|
import SingleReview from "./singleReview/SingleReview";
|
||||||
|
import axios from "axios";
|
||||||
|
import AddReview from "./AddReview";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text, Paragraph} = Typography;
|
||||||
|
|
||||||
|
class CurrentUsersReview extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
data: []
|
||||||
|
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchData();
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData = () => {
|
||||||
|
const {uuid} = this.props;
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
axios.get(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/reviews/app/user/" + uuid,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const data = res.data.data.data;
|
||||||
|
this.setState({data});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.hasOwnProperty(status) && error.response.status === 401) {
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to get your review.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteCallback = () =>{
|
||||||
|
this.setState({
|
||||||
|
data: []
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
addCallBack =(review) =>{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {data} = this.state;
|
||||||
|
const {uuid} = this.props;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Text>MY REVIEW</Text>
|
||||||
|
<div style={{
|
||||||
|
overflow: "auto",
|
||||||
|
paddingTop: 8,
|
||||||
|
paddingLeft: 24
|
||||||
|
}}>
|
||||||
|
{data.length > 0 && (
|
||||||
|
<div>
|
||||||
|
<List
|
||||||
|
dataSource={data}
|
||||||
|
renderItem={item => (
|
||||||
|
<List.Item key={item.id}>
|
||||||
|
<SingleReview uuid={uuid} review={item} isDeletable={true} isEditable={true} deleteCallback={this.deleteCallback} isPersonalReview={true}/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
</List>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{data.length === 0 && (
|
||||||
|
<div>
|
||||||
|
<Empty
|
||||||
|
image={Empty.PRESENTED_IMAGE_DEFAULT}
|
||||||
|
imagestyle={{
|
||||||
|
height: 60,
|
||||||
|
}}
|
||||||
|
description={
|
||||||
|
<span>Share your experience with your community by adding a review.</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
{/*<Button type="primary">Add review</Button>*/}
|
||||||
|
<AddReview uuid={uuid}/>
|
||||||
|
</Empty>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(CurrentUsersReview);
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.infinite-container {
|
||||||
|
overflow: auto;
|
||||||
|
padding: 8px 24px;
|
||||||
|
}
|
||||||
|
.loading-container {
|
||||||
|
position: absolute;
|
||||||
|
bottom: 40px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading {
|
||||||
|
position: absolute;
|
||||||
|
bottom: -40px;
|
||||||
|
left: 50%;
|
||||||
|
}
|
@ -0,0 +1,155 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {List, message, Avatar, Spin, Button, notification} from 'antd';
|
||||||
|
import "./Reviews.css";
|
||||||
|
|
||||||
|
import InfiniteScroll from 'react-infinite-scroller';
|
||||||
|
import SingleReview from "./singleReview/SingleReview";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const limit = 5;
|
||||||
|
|
||||||
|
class Reviews extends React.Component {
|
||||||
|
state = {
|
||||||
|
data: [],
|
||||||
|
loading: false,
|
||||||
|
hasMore: false,
|
||||||
|
loadMore: false
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetchData(0, limit, res => {
|
||||||
|
this.setState({
|
||||||
|
data: res,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData = (offset, limit, callback) => {
|
||||||
|
|
||||||
|
const {uuid, type} = this.props;
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
axios.get(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri +config.serverConfig.invoker.store+"/reviews/"+type+"/"+uuid,
|
||||||
|
{
|
||||||
|
headers: {'X-Platform': config.serverConfig.platform}
|
||||||
|
}).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let reviews = res.data.data.data;
|
||||||
|
callback(reviews);
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load reviews.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleInfiniteOnLoad = (count) => {
|
||||||
|
const offset = count * limit;
|
||||||
|
let data = this.state.data;
|
||||||
|
this.setState({
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
|
if (data.length > 149) {
|
||||||
|
this.setState({
|
||||||
|
hasMore: false,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.fetchData(offset, limit, res => {
|
||||||
|
if (res.length > 0) {
|
||||||
|
data = data.concat(res);
|
||||||
|
this.setState({
|
||||||
|
data,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
hasMore: false,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
enableLoading = () => {
|
||||||
|
this.setState({
|
||||||
|
hasMore: true,
|
||||||
|
loadMore: true
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteCallback = () =>{
|
||||||
|
this.fetchData(0, limit, res => {
|
||||||
|
this.setState({
|
||||||
|
data: res,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {loading, hasMore, data, loadMore} = this.state;
|
||||||
|
const {uuid} = this.props;
|
||||||
|
return (
|
||||||
|
<div className="infinite-container">
|
||||||
|
<InfiniteScroll
|
||||||
|
initialLoad={false}
|
||||||
|
pageStart={0}
|
||||||
|
loadMore={this.handleInfiniteOnLoad}
|
||||||
|
hasMore={!loading && hasMore}
|
||||||
|
useWindow={true}
|
||||||
|
>
|
||||||
|
<List
|
||||||
|
dataSource={data}
|
||||||
|
renderItem={item => (
|
||||||
|
<List.Item key={item.id}>
|
||||||
|
<SingleReview uuid={uuid} review={item} isDeletable={true} isEditable={false} deleteCallback={this.deleteCallback}/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{loading && hasMore && (
|
||||||
|
<div className="loading-container">
|
||||||
|
<Spin/>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</List>
|
||||||
|
</InfiniteScroll>
|
||||||
|
{!loadMore && (data.length >= limit) && (<div style={{textAlign: "center"}}>
|
||||||
|
<Button type="dashed" htmlType="button" onClick={this.enableLoading}>Read All Reviews</Button>
|
||||||
|
</div>)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(Reviews);
|
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img.twemoji {
|
||||||
|
height: 1em;
|
||||||
|
width: 1em;
|
||||||
|
margin: 0 .05em 0 .1em;
|
||||||
|
vertical-align: -0.1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
color: #1890ff;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-button {
|
||||||
|
color: #e74c3c;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
@ -0,0 +1,152 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Avatar, notification} from "antd";
|
||||||
|
import {List, Typography, Popconfirm} from "antd";
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import Twemoji from "react-twemoji";
|
||||||
|
import "./SingleReview.css";
|
||||||
|
import EditReview from "./editReview/EditReview";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Text, Paragraph} = Typography;
|
||||||
|
const colorList = ['#f0932b', '#badc58', '#6ab04c', '#eb4d4b', '#0abde3', '#9b59b6', '#3498db', '#22a6b3', '#e84393', '#f9ca24'];
|
||||||
|
|
||||||
|
class SingleReview extends React.Component {
|
||||||
|
|
||||||
|
static defaultProps = {
|
||||||
|
isPersonalReview: false
|
||||||
|
};
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
const {username} = this.props.review;
|
||||||
|
const color = colorList[username.length % 10];
|
||||||
|
this.state = {
|
||||||
|
content: '',
|
||||||
|
rating: 0,
|
||||||
|
color: color,
|
||||||
|
review: props.review
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateCallback = (review) => {
|
||||||
|
this.setState({
|
||||||
|
review
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
deleteReview = () => {
|
||||||
|
const {uuid} = this.props;
|
||||||
|
const {id} = this.state.review;
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
let url =window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store;
|
||||||
|
|
||||||
|
// call as an admin api if the review is not a personal review
|
||||||
|
if (!this.props.isPersonalReview) {
|
||||||
|
url += "/admin";
|
||||||
|
}
|
||||||
|
|
||||||
|
url += "/reviews/" + uuid + "/" + id;
|
||||||
|
|
||||||
|
axios.delete(url).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
notification["success"]({
|
||||||
|
message: 'Done!',
|
||||||
|
description:
|
||||||
|
'The review has been deleted successfully.',
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.deleteCallback(id);
|
||||||
|
}
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"We were unable to delete the review..",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {isEditable, isDeletable, uuid} = this.props;
|
||||||
|
const {color, review} = this.state;
|
||||||
|
const {content, rating, username} = review;
|
||||||
|
const avatarLetter = username.charAt(0).toUpperCase();
|
||||||
|
const body = (
|
||||||
|
<div style={{marginTop: -5}}>
|
||||||
|
<StarRatings
|
||||||
|
rating={rating}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starDimension="12px"
|
||||||
|
starSpacing="2px"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
<Text style={{fontSize: 12, color: "#aaa"}} type="secondary"> {review.createdAt}</Text><br/>
|
||||||
|
<Paragraph style={{color: "#777"}}>
|
||||||
|
<Twemoji options={{className: 'twemoji'}}>
|
||||||
|
{content}
|
||||||
|
</Twemoji>
|
||||||
|
</Paragraph>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const title = (
|
||||||
|
<div>
|
||||||
|
{review.username}
|
||||||
|
{isEditable && (<EditReview uuid={uuid} review={review} updateCallback={this.updateCallback}/>)}
|
||||||
|
{isDeletable && (
|
||||||
|
<Popconfirm
|
||||||
|
title="Are you sure delete this review?"
|
||||||
|
onConfirm={this.deleteReview}
|
||||||
|
okText="Yes"
|
||||||
|
cancelText="No"
|
||||||
|
>
|
||||||
|
<span className="delete-button">delete</span>
|
||||||
|
</Popconfirm>)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<List.Item.Meta
|
||||||
|
avatar={
|
||||||
|
<Avatar style={{backgroundColor: color, verticalAlign: 'middle'}} size="large">
|
||||||
|
{avatarLetter}
|
||||||
|
</Avatar>
|
||||||
|
}
|
||||||
|
title={title}
|
||||||
|
description={body}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(SingleReview);
|
@ -0,0 +1,27 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.edit-button {
|
||||||
|
color: #1890ff;
|
||||||
|
text-decoration: none;
|
||||||
|
outline: none;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: normal;
|
||||||
|
font-size: 0.8em;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
@ -0,0 +1,191 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Drawer, Button, Icon, Row, Col, Typography, Divider, Input, Spin, notification} from 'antd';
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import axios from "axios";
|
||||||
|
import "./EditReview.css";
|
||||||
|
import {withConfigContext} from "../../../../../../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
const {TextArea} = Input;
|
||||||
|
|
||||||
|
class EditReview extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
visible: false,
|
||||||
|
content: '',
|
||||||
|
rating: 0,
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const {content,rating,id} = this.props.review;
|
||||||
|
console.log(this.props.review);
|
||||||
|
this.setState({
|
||||||
|
content,
|
||||||
|
rating
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
showDrawer = () => {
|
||||||
|
this.setState({
|
||||||
|
visible: true,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onClose = () => {
|
||||||
|
this.setState({
|
||||||
|
visible: false,
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
changeRating = (newRating, name) => {
|
||||||
|
this.setState({
|
||||||
|
rating: newRating
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
onChange = (e) => {
|
||||||
|
this.setState({content: e.target.value})
|
||||||
|
};
|
||||||
|
|
||||||
|
onSubmit = () => {
|
||||||
|
const config = this.props.context;
|
||||||
|
const {content, rating} = this.state;
|
||||||
|
const {id} = this.props.review;
|
||||||
|
const {uuid} = this.props;
|
||||||
|
this.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
|
||||||
|
const payload = {
|
||||||
|
content: content,
|
||||||
|
rating: rating
|
||||||
|
};
|
||||||
|
|
||||||
|
axios.put(
|
||||||
|
window.location.origin+ config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/reviews/" + uuid+"/"+id,
|
||||||
|
payload,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["success"]({
|
||||||
|
message: 'Done!',
|
||||||
|
description:
|
||||||
|
'Your review has been update successfully.',
|
||||||
|
});
|
||||||
|
|
||||||
|
this.props.updateCallback(res.data.data);
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"We are unable to update your review right now.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin+ '/store/login';
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
visible: false
|
||||||
|
});
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"We are unable to add your review right now.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<span>
|
||||||
|
<span className="edit-button" onClick={this.showDrawer}>edit</span>
|
||||||
|
<Drawer
|
||||||
|
// title="Basic Drawer"
|
||||||
|
placement="bottom"
|
||||||
|
closable={false}
|
||||||
|
onClose={this.onClose}
|
||||||
|
visible={this.state.visible}
|
||||||
|
height={400}
|
||||||
|
>
|
||||||
|
<Spin spinning={this.state.loading} tip="Posting your review...">
|
||||||
|
<Row>
|
||||||
|
<Col lg={8}/>
|
||||||
|
<Col lg={8}>
|
||||||
|
<Title level={4}>Edit review</Title>
|
||||||
|
<Divider/>
|
||||||
|
<TextArea
|
||||||
|
placeholder="Tell others what you think about this app. Would you recommend it, and why?"
|
||||||
|
onChange={this.onChange}
|
||||||
|
rows={6}
|
||||||
|
value={this.state.content || ''}
|
||||||
|
style={{marginBottom: 20}}
|
||||||
|
/>
|
||||||
|
<StarRatings
|
||||||
|
rating={this.state.rating}
|
||||||
|
changeRating={this.changeRating}
|
||||||
|
starRatedColor="#777"
|
||||||
|
starHoverColor="#444"
|
||||||
|
starDimension="20px"
|
||||||
|
starSpacing="2px"
|
||||||
|
numberOfStars={5}
|
||||||
|
name='rating'
|
||||||
|
/>
|
||||||
|
<br/><br/>
|
||||||
|
<Button onClick={this.onClose} style={{marginRight: 8}}>
|
||||||
|
Cancel
|
||||||
|
</Button>
|
||||||
|
<Button disabled={this.state.rating === 0} onClick={this.onSubmit} type="primary">
|
||||||
|
Submit
|
||||||
|
</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</Spin>
|
||||||
|
</Drawer>
|
||||||
|
|
||||||
|
|
||||||
|
</span>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(EditReview);
|
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
|
||||||
|
const ConfigContext = React.createContext();
|
||||||
|
|
||||||
|
export const withConfigContext = Component => {
|
||||||
|
return props => (
|
||||||
|
<ConfigContext.Consumer>
|
||||||
|
{context => {
|
||||||
|
return <Component {...props} context={context}/>;
|
||||||
|
}}
|
||||||
|
</ConfigContext.Consumer>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConfigContext;
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.App {
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-layout-header{
|
||||||
|
padding: 0;
|
||||||
|
height: auto;
|
||||||
|
box-shadow: 0 2px 8px #f0f1f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps-content {
|
||||||
|
margin-top: 16px;
|
||||||
|
border: 1px dashed #e9e9e9;
|
||||||
|
border-radius: 6px;
|
||||||
|
background-color: #fafafa;
|
||||||
|
min-height: 200px;
|
||||||
|
text-align: center;
|
||||||
|
padding-top: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps-action {
|
||||||
|
margin-top: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-input-affix-wrapper .ant-input{
|
||||||
|
min-height: 0;
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
<!--
|
||||||
|
~ Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
~
|
||||||
|
~ Entgra (pvt) Ltd. 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.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/>
|
||||||
|
<title>Entgra App Store</title>
|
||||||
|
</head>
|
||||||
|
<div id="root"></div>
|
||||||
|
</html>
|
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from 'react';
|
||||||
|
import ReactDOM from 'react-dom';
|
||||||
|
import * as serviceWorker from './serviceWorker';
|
||||||
|
import App from "./App";
|
||||||
|
import Login from "./pages/Login";
|
||||||
|
import Dashboard from "./pages/dashboard/Dashboard";
|
||||||
|
import Apps from "./pages/dashboard/apps/Apps";
|
||||||
|
import Release from "./pages/dashboard/apps/release/Release";
|
||||||
|
import './index.css';
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: '/store/login',
|
||||||
|
exact: true,
|
||||||
|
component: Login
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/store',
|
||||||
|
exact: false,
|
||||||
|
component: Dashboard,
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
path: '/store/:deviceType',
|
||||||
|
component: Apps,
|
||||||
|
exact: true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: '/store/:deviceType/apps/:uuid',
|
||||||
|
exact: true,
|
||||||
|
component: Release
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
ReactDOM.render(
|
||||||
|
<App routes={routes}/>,
|
||||||
|
document.getElementById('root'));
|
||||||
|
|
||||||
|
// If you want your app e and load faster, you can change
|
||||||
|
// unregister() to register() below. Note this comes with some pitfalls.
|
||||||
|
// Learn more about service workers: https://bit.ly/CRA-PWA
|
||||||
|
serviceWorker.unregister();
|
After Width: | Height: | Size: 2.6 KiB |
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@-moz-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-moz-transform: rotate(0deg) scale(1.0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-moz-transform: rotate(360deg) scale(0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg) scale(1.0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg) scale(0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% {
|
||||||
|
-webkit-transform: rotate(0deg) scale(1.0);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
-webkit-transform: rotate(360deg) scale(0.1);
|
||||||
|
transform: rotate(360deg) scale(0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.background {
|
||||||
|
position: absolute;
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
background-image: url('https://gw.alipayobjects.com/zos/rmsportal/TVYTbAXWheQpRcWDaDMu.svg');
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center 110px;
|
||||||
|
background-size: 100%;
|
||||||
|
animation: spin 200s infinite linear;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
position: relative;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
@ -0,0 +1,171 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Typography, Row, Col, Form, Icon, Input, Button, Checkbox} from 'antd';
|
||||||
|
import './Login.css';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {withConfigContext} from "../context/ConfigContext";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
const {Text} = Typography;
|
||||||
|
|
||||||
|
class Login extends React.Component {
|
||||||
|
render() {
|
||||||
|
const config = this.props.context;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="background">
|
||||||
|
</div>
|
||||||
|
<div className="content">
|
||||||
|
<Row>
|
||||||
|
<Col xs={3} sm={3} md={10}>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col xs={18} sm={18} md={4}>
|
||||||
|
<Row style={{marginBottom: 20}}>
|
||||||
|
<Col style={{textAlign: "center"}}>
|
||||||
|
<img style={
|
||||||
|
{
|
||||||
|
marginTop: 36,
|
||||||
|
height: 60
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src={config.theme.logo}/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Title level={2}>Login</Title>
|
||||||
|
<WrappedNormalLoginForm/>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Row>
|
||||||
|
<Col span={4} offset={10}>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NormalLoginForm extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
inValid: false,
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSubmit = (e) => {
|
||||||
|
const thisForm = this;
|
||||||
|
const config = this.props.context;
|
||||||
|
console.log(config);
|
||||||
|
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.form.validateFields((err, values) => {
|
||||||
|
thisForm.setState({
|
||||||
|
inValid: false
|
||||||
|
});
|
||||||
|
if (!err) {
|
||||||
|
thisForm.setState({
|
||||||
|
loading: true
|
||||||
|
});
|
||||||
|
const parameters = {
|
||||||
|
username: values.username,
|
||||||
|
password: values.password,
|
||||||
|
platform: "store"
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
|
||||||
|
|
||||||
|
axios.post(window.location.origin+ config.serverConfig.loginUri, request
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
window.location = window.location.origin+ "/store";
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
if (error.response.status === 400) {
|
||||||
|
thisForm.setState({
|
||||||
|
inValid: true,
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {getFieldDecorator} = this.props.form;
|
||||||
|
let errorMsg = "";
|
||||||
|
if (this.state.inValid) {
|
||||||
|
errorMsg = <Text type="danger">Invalid Login Details</Text>;
|
||||||
|
}
|
||||||
|
let loading = "";
|
||||||
|
if (this.state.loading) {
|
||||||
|
loading = <Text type="secondary">Loading..</Text>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Form onSubmit={this.handleSubmit} className="login-form">
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('username', {
|
||||||
|
rules: [{required: true, message: 'Please input your username!'}],
|
||||||
|
})(
|
||||||
|
<Input name="username" style={{height: 32}}
|
||||||
|
prefix={<Icon type="user" style={{color: 'rgba(0,0,0,.25)'}}/>}
|
||||||
|
placeholder="Username"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('password', {
|
||||||
|
rules: [{required: true, message: 'Please input your Password!'}],
|
||||||
|
})(
|
||||||
|
<Input name="password" style={{height: 32}}
|
||||||
|
prefix={<Icon type="lock" style={{color: 'rgba(0,0,0,.25)'}}/>} type="password"
|
||||||
|
placeholder="Password"/>
|
||||||
|
)}
|
||||||
|
</Form.Item>
|
||||||
|
{loading}
|
||||||
|
{errorMsg}
|
||||||
|
<Form.Item>
|
||||||
|
{getFieldDecorator('remember', {
|
||||||
|
valuePropName: 'checked',
|
||||||
|
initialValue: true,
|
||||||
|
})(
|
||||||
|
<Checkbox>Remember me</Checkbox>
|
||||||
|
)}
|
||||||
|
<br/>
|
||||||
|
<a className="login-form-forgot" href="">Forgot password</a>
|
||||||
|
<Button block type="primary" htmlType="submit" className="login-form-button">
|
||||||
|
Log in
|
||||||
|
</Button>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const WrappedNormalLoginForm = withConfigContext(Form.create({name: 'normal_login'})(NormalLoginForm));
|
||||||
|
|
||||||
|
export default withConfigContext(Login);
|
@ -0,0 +1,157 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Layout, Menu, Icon} from 'antd';
|
||||||
|
|
||||||
|
const {Header, Content, Footer} = Layout;
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
import RouteWithSubRoutes from "../../components/RouteWithSubRoutes";
|
||||||
|
import {Switch} from 'react-router';
|
||||||
|
import axios from "axios";
|
||||||
|
import "../../App.css";
|
||||||
|
import {withConfigContext} from "../../context/ConfigContext";
|
||||||
|
import Logout from "./logout/Logout";
|
||||||
|
|
||||||
|
const {SubMenu} = Menu;
|
||||||
|
|
||||||
|
class Dashboard extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
routes: props.routes,
|
||||||
|
selectedKeys: [],
|
||||||
|
deviceTypes: []
|
||||||
|
};
|
||||||
|
this.logo = this.props.context.theme.logo;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getDeviceTypes();
|
||||||
|
}
|
||||||
|
|
||||||
|
getDeviceTypes = () => {
|
||||||
|
const config = this.props.context;
|
||||||
|
axios.get(
|
||||||
|
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.deviceMgt + "/device-types"
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
const deviceTypes = JSON.parse(res.data.data);
|
||||||
|
this.setState({
|
||||||
|
deviceTypes,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||||
|
window.location.href = window.location.origin + '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load device types.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
loading: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
changeSelectedMenuItem = (key) => {
|
||||||
|
this.setState({
|
||||||
|
selectedKeys: [key]
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const config = this.props.context;
|
||||||
|
const {selectedKeys, deviceTypes} = this.state;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Layout className="layout">
|
||||||
|
<Header style={{paddingLeft: 0, paddingRight: 0}}>
|
||||||
|
<div className="logo-image">
|
||||||
|
<img alt="logo" src={this.logo}/>
|
||||||
|
</div>
|
||||||
|
<Menu
|
||||||
|
theme="light"
|
||||||
|
mode="horizontal"
|
||||||
|
defaultSelectedKeys={selectedKeys}
|
||||||
|
style={{lineHeight: '64px'}}
|
||||||
|
>
|
||||||
|
{
|
||||||
|
deviceTypes.map((deviceType) => {
|
||||||
|
const platform = deviceType.name;
|
||||||
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
|
let icon = defaultPlatformIcons.default.icon;
|
||||||
|
let theme = defaultPlatformIcons.default.theme;
|
||||||
|
if (defaultPlatformIcons.hasOwnProperty(platform)) {
|
||||||
|
icon = defaultPlatformIcons[platform].icon;
|
||||||
|
theme = defaultPlatformIcons[platform].theme;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Menu.Item key={platform}>
|
||||||
|
<Link to={"/store/" + platform}>
|
||||||
|
<Icon type={icon} theme={theme}/>
|
||||||
|
{platform}
|
||||||
|
</Link>
|
||||||
|
</Menu.Item>
|
||||||
|
);
|
||||||
|
})
|
||||||
|
}
|
||||||
|
<Menu.Item key="web-clip"><Link to="/store/web-clip"><Icon type="upload"/>Web
|
||||||
|
Clips</Link></Menu.Item>
|
||||||
|
|
||||||
|
<SubMenu className="profile"
|
||||||
|
title={
|
||||||
|
<span className="submenu-title-wrapper">
|
||||||
|
<Icon type="user"/>
|
||||||
|
Profile
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Logout/>
|
||||||
|
</SubMenu>
|
||||||
|
</Menu>
|
||||||
|
</Header>
|
||||||
|
</Layout>
|
||||||
|
<Layout>
|
||||||
|
<Content style={{padding: '0 0'}}>
|
||||||
|
<Switch>
|
||||||
|
{this.state.routes.map((route) => (
|
||||||
|
<RouteWithSubRoutes changeSelectedMenuItem={this.changeSelectedMenuItem}
|
||||||
|
key={route.path} {...route} />
|
||||||
|
))}
|
||||||
|
|
||||||
|
</Switch>
|
||||||
|
|
||||||
|
</Content>
|
||||||
|
<Footer style={{textAlign: 'center'}}>
|
||||||
|
©2019 entgra.io
|
||||||
|
</Footer>
|
||||||
|
</Layout>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(Dashboard);
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
width: 120px;
|
||||||
|
height: 31px;
|
||||||
|
margin: 16px 0 16px 20px;
|
||||||
|
float: left;
|
||||||
|
|
||||||
|
img{
|
||||||
|
height: 35px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
input{
|
||||||
|
min-height: 0;
|
||||||
|
}
|
@ -0,0 +1,353 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {
|
||||||
|
PageHeader,
|
||||||
|
Typography,
|
||||||
|
Card,
|
||||||
|
Steps,
|
||||||
|
Button,
|
||||||
|
message,
|
||||||
|
Row,
|
||||||
|
Col,
|
||||||
|
Tag,
|
||||||
|
Tooltip,
|
||||||
|
Input,
|
||||||
|
Icon,
|
||||||
|
Select,
|
||||||
|
Switch,
|
||||||
|
Form,
|
||||||
|
Upload,
|
||||||
|
Divider
|
||||||
|
} from "antd";
|
||||||
|
import Step1 from "./Step1";
|
||||||
|
import Step2 from "./Step2";
|
||||||
|
import Step3 from "./Step3";
|
||||||
|
import styles from "./Style.less";
|
||||||
|
import IconImage from "./IconImg";
|
||||||
|
import UploadScreenshots from "./UploadScreenshots";
|
||||||
|
|
||||||
|
const Paragraph = Typography;
|
||||||
|
const Dragger = Upload.Dragger;
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
breadcrumbName: 'store',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'first',
|
||||||
|
breadcrumbName: 'dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'second',
|
||||||
|
breadcrumbName: 'add new app',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const props = {
|
||||||
|
name: 'file',
|
||||||
|
multiple: false,
|
||||||
|
action: '//jsonplaceholder.typicode.com/posts/',
|
||||||
|
onChange(info) {
|
||||||
|
const status = info.file.status;
|
||||||
|
if (status !== 'uploading') {
|
||||||
|
// console.log(info.file, info.fileList);
|
||||||
|
}
|
||||||
|
if (status === 'done') {
|
||||||
|
message.success(`${info.file.name} file uploaded successfully.`);
|
||||||
|
} else if (status === 'error') {
|
||||||
|
message.error(`${info.file.name} file upload failed.`);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const Step = Steps.Step;
|
||||||
|
|
||||||
|
const steps = [{
|
||||||
|
title: 'First',
|
||||||
|
content: Step1
|
||||||
|
}, {
|
||||||
|
title: 'Second',
|
||||||
|
content: Step2,
|
||||||
|
}, {
|
||||||
|
title: 'Last',
|
||||||
|
content: Step3,
|
||||||
|
}];
|
||||||
|
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {TextArea} = Input;
|
||||||
|
const InputGroup = Input.Group;
|
||||||
|
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {
|
||||||
|
span: 4,
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
span: 20,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
class EditableTagGroup extends React.Component {
|
||||||
|
state = {
|
||||||
|
tags: [],
|
||||||
|
inputVisible: false,
|
||||||
|
inputValue: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClose = (removedTag) => {
|
||||||
|
const tags = this.state.tags.filter(tag => tag !== removedTag);
|
||||||
|
// console.log(tags);
|
||||||
|
this.setState({tags});
|
||||||
|
}
|
||||||
|
|
||||||
|
showInput = () => {
|
||||||
|
this.setState({inputVisible: true}, () => this.input.focus());
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputChange = (e) => {
|
||||||
|
this.setState({inputValue: e.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputConfirm = () => {
|
||||||
|
const {inputValue} = this.state;
|
||||||
|
let {tags} = this.state;
|
||||||
|
if (inputValue && tags.indexOf(inputValue) === -1) {
|
||||||
|
tags = [...tags, inputValue];
|
||||||
|
}
|
||||||
|
// console.log(tags);
|
||||||
|
this.setState({
|
||||||
|
tags,
|
||||||
|
inputVisible: false,
|
||||||
|
inputValue: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveInputRef = input => this.input = input
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {tags, inputVisible, inputValue} = this.state;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{tags.map((tag, index) => {
|
||||||
|
const isLongTag = tag.length > 20;
|
||||||
|
const tagElem = (
|
||||||
|
<Tag key={tag} closable={index !== 0} onClose={() => this.handleClose(tag)}>
|
||||||
|
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
return isLongTag ? <Tooltip title={tag} key={tag}>{tagElem}</Tooltip> : tagElem;
|
||||||
|
})}
|
||||||
|
{inputVisible && (
|
||||||
|
<Input
|
||||||
|
ref={this.saveInputRef}
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
style={{width: 78}}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
onBlur={this.handleInputConfirm}
|
||||||
|
onPressEnter={this.handleInputConfirm}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!inputVisible && (
|
||||||
|
<Tag
|
||||||
|
onClick={this.showInput}
|
||||||
|
style={{background: '#fff', borderStyle: 'dashed'}}
|
||||||
|
>
|
||||||
|
<Icon type="plus"/> New Tag
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AddNewApp extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
current: 0,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
tags = [];
|
||||||
|
|
||||||
|
addTag(key, value){
|
||||||
|
this.tags.push(<Option key={key}>{value}</Option>);
|
||||||
|
}
|
||||||
|
|
||||||
|
next() {
|
||||||
|
const current = this.state.current + 1;
|
||||||
|
this.setState({current});
|
||||||
|
}
|
||||||
|
|
||||||
|
prev() {
|
||||||
|
const current = this.state.current - 1;
|
||||||
|
this.setState({current});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {current} = this.state;
|
||||||
|
const Content = steps[current].content;
|
||||||
|
this.addTag('1','Lorem');
|
||||||
|
this.addTag('2','Ipsum');
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<PageHeader
|
||||||
|
title="Add New App"
|
||||||
|
breadcrumb={{routes}}
|
||||||
|
>
|
||||||
|
<div className="wrap">
|
||||||
|
<div className="content">
|
||||||
|
<Paragraph>
|
||||||
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempo.
|
||||||
|
</Paragraph>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageHeader>
|
||||||
|
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
|
||||||
|
<Row>
|
||||||
|
<Col span={20} offset={2}>
|
||||||
|
<Card>
|
||||||
|
<Row>
|
||||||
|
<Col span={12}>
|
||||||
|
<div>
|
||||||
|
<Form labelAlign="left" layout="horizontal" className={styles.stepForm}
|
||||||
|
hideRequiredMark>
|
||||||
|
<Form.Item {...formItemLayout} label="Platform">
|
||||||
|
<Select placeholder="ex: android">
|
||||||
|
<Option value="Android">Android</Option>
|
||||||
|
<Option value="iOS">iOS</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Type">
|
||||||
|
<Select value="Enterprise">
|
||||||
|
<Option value="Enterprise" selected>Enterprise</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="App Name">
|
||||||
|
<Input placeholder="ex: Lorem App"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Description">
|
||||||
|
<TextArea placeholder="Enter the description..." rows={7}/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Category">
|
||||||
|
<Select placeholder="Select a category">
|
||||||
|
<Option value="travel">Travel</Option>
|
||||||
|
<Option value="entertainment">Entertainment</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Price">
|
||||||
|
<Input prefix="$" placeholder="00.00"/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Is Sahred?">
|
||||||
|
<Switch checkedChildren={<Icon type="check" />} unCheckedChildren={<Icon type="close" />} defaultChecked />
|
||||||
|
</Form.Item>
|
||||||
|
<Divider/>
|
||||||
|
<Form.Item {...formItemLayout} label="Tags">
|
||||||
|
|
||||||
|
<InputGroup>
|
||||||
|
<Row gutter={8}>
|
||||||
|
<Col span={22}>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
style={{ width: '100%' }}
|
||||||
|
placeholder="Tags Mode"
|
||||||
|
>
|
||||||
|
{this.tags}
|
||||||
|
</Select>
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<Button type="dashed" shape="circle" icon="plus"/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</InputGroup>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Meta Daa">
|
||||||
|
<InputGroup>
|
||||||
|
<Row gutter={8}>
|
||||||
|
<Col span={10}>
|
||||||
|
<Input placeholder="Key"/>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<Input placeholder="value"/>
|
||||||
|
</Col>
|
||||||
|
<Col span={2}>
|
||||||
|
<Button type="dashed" shape="circle" icon="plus"/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</InputGroup>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
</Col>
|
||||||
|
<Col span={12} style={{paddingTop: 40, paddingLeft: 20}}>
|
||||||
|
<p>Application</p>
|
||||||
|
<div style={{height: 170}}>
|
||||||
|
<Dragger {...props}>
|
||||||
|
<p className="ant-upload-drag-icon">
|
||||||
|
<Icon type="inbox"/>
|
||||||
|
</p>
|
||||||
|
<p className="ant-upload-text">Click or drag file to this area to
|
||||||
|
upload</p>
|
||||||
|
<p className="ant-upload-hint">Support for a single or bulk upload.
|
||||||
|
Strictly prohibit from uploading company data or other band
|
||||||
|
files</p>
|
||||||
|
</Dragger>
|
||||||
|
</div>
|
||||||
|
<Row style={{marginTop: 40}}>
|
||||||
|
<Col span={12}>
|
||||||
|
<p>Icon</p>
|
||||||
|
<IconImage/>
|
||||||
|
</Col>
|
||||||
|
<Col span={12}>
|
||||||
|
<p>Banner</p>
|
||||||
|
<IconImage/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
|
||||||
|
<Row style={{marginTop: 40}}>
|
||||||
|
<Col span={24}>
|
||||||
|
<p>Screenshots</p>
|
||||||
|
<UploadScreenshots/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
|
||||||
|
</Row>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AddNewApp;
|
@ -0,0 +1,84 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import { Upload, Icon, message } from 'antd';
|
||||||
|
|
||||||
|
function getBase64(img, callback) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.addEventListener('load', () => callback(reader.result));
|
||||||
|
reader.readAsDataURL(img);
|
||||||
|
}
|
||||||
|
|
||||||
|
function beforeUpload(file) {
|
||||||
|
const isJPG = file.type === 'image/jpeg';
|
||||||
|
if (!isJPG) {
|
||||||
|
message.error('You can only upload JPG file!');
|
||||||
|
}
|
||||||
|
const isLt2M = file.size / 1024 / 1024 < 2;
|
||||||
|
if (!isLt2M) {
|
||||||
|
message.error('Image must smaller than 2MB!');
|
||||||
|
}
|
||||||
|
return isJPG && isLt2M;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class IconImage extends React.Component {
|
||||||
|
state = {
|
||||||
|
loading: false,
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = (info) => {
|
||||||
|
if (info.file.status === 'uploading') {
|
||||||
|
this.setState({ loading: true });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (info.file.status === 'done') {
|
||||||
|
// Get this url from response in real world.
|
||||||
|
getBase64(info.file.originFileObj, imageUrl => this.setState({
|
||||||
|
imageUrl,
|
||||||
|
loading: false,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const uploadButton = (
|
||||||
|
<div>
|
||||||
|
<Icon type={this.state.loading ? 'loading' : 'plus'} />
|
||||||
|
<div className="ant-upload-text">Upload</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
const imageUrl = this.state.imageUrl;
|
||||||
|
return (
|
||||||
|
<Upload
|
||||||
|
name="avatar"
|
||||||
|
listType="picture-card"
|
||||||
|
className="avatar-uploader"
|
||||||
|
showUploadList={false}
|
||||||
|
action="//jsonplaceholder.typicode.com/posts/"
|
||||||
|
beforeUpload={beforeUpload}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
>
|
||||||
|
{imageUrl ? <img src={imageUrl} alt="avatar" /> : uploadButton}
|
||||||
|
</Upload>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IconImage;
|
@ -0,0 +1,170 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {Form, Input, Button, Select, Divider, Tag, Tooltip, Icon, Checkbox, Row, Col} from "antd";
|
||||||
|
import styles from './Style.less';
|
||||||
|
|
||||||
|
const { Option } = Select;
|
||||||
|
const { TextArea } = Input;
|
||||||
|
const InputGroup = Input.Group;
|
||||||
|
|
||||||
|
const formItemLayout = {
|
||||||
|
labelCol: {
|
||||||
|
span: 8,
|
||||||
|
},
|
||||||
|
wrapperCol: {
|
||||||
|
span: 16,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
class EditableTagGroup extends React.Component {
|
||||||
|
state = {
|
||||||
|
tags: [],
|
||||||
|
inputVisible: false,
|
||||||
|
inputValue: '',
|
||||||
|
};
|
||||||
|
|
||||||
|
handleClose = (removedTag) => {
|
||||||
|
const tags = this.state.tags.filter(tag => tag !== removedTag);
|
||||||
|
// console.log(tags);
|
||||||
|
this.setState({ tags });
|
||||||
|
}
|
||||||
|
|
||||||
|
showInput = () => {
|
||||||
|
this.setState({ inputVisible: true }, () => this.input.focus());
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputChange = (e) => {
|
||||||
|
this.setState({ inputValue: e.target.value });
|
||||||
|
}
|
||||||
|
|
||||||
|
handleInputConfirm = () => {
|
||||||
|
const { inputValue } = this.state;
|
||||||
|
let { tags } = this.state;
|
||||||
|
if (inputValue && tags.indexOf(inputValue) === -1) {
|
||||||
|
tags = [...tags, inputValue];
|
||||||
|
}
|
||||||
|
// console.log(tags);
|
||||||
|
this.setState({
|
||||||
|
tags,
|
||||||
|
inputVisible: false,
|
||||||
|
inputValue: '',
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
saveInputRef = input => this.input = input
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { tags, inputVisible, inputValue } = this.state;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
{tags.map((tag, index) => {
|
||||||
|
const isLongTag = tag.length > 20;
|
||||||
|
const tagElem = (
|
||||||
|
<Tag key={tag} closable={index !== 0} onClose={() => this.handleClose(tag)}>
|
||||||
|
{isLongTag ? `${tag.slice(0, 20)}...` : tag}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
return isLongTag ? <Tooltip title={tag} key={tag}>{tagElem}</Tooltip> : tagElem;
|
||||||
|
})}
|
||||||
|
{inputVisible && (
|
||||||
|
<Input
|
||||||
|
ref={this.saveInputRef}
|
||||||
|
type="text"
|
||||||
|
size="small"
|
||||||
|
style={{ width: 78 }}
|
||||||
|
value={inputValue}
|
||||||
|
onChange={this.handleInputChange}
|
||||||
|
onBlur={this.handleInputConfirm}
|
||||||
|
onPressEnter={this.handleInputConfirm}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{!inputVisible && (
|
||||||
|
<Tag
|
||||||
|
onClick={this.showInput}
|
||||||
|
style={{ background: '#fff', borderStyle: 'dashed' }}
|
||||||
|
>
|
||||||
|
<Icon type="plus" /> New Tag
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Step1 extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Form layout="horizontal" className={styles.stepForm} hideRequiredMark>
|
||||||
|
|
||||||
|
<Form.Item {...formItemLayout} label="Platform">
|
||||||
|
<Select placeholder="ex: android">
|
||||||
|
<Option value="Android">Android</Option>
|
||||||
|
<Option value="iOS">iOS</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Type">
|
||||||
|
<Select value="Enterprise">
|
||||||
|
<Option value="Enterprise" selected>Enterprise</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Name">
|
||||||
|
<Input placeholder="App Name" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Description">
|
||||||
|
<TextArea placeholder="Enter the description" rows={4} />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Category">
|
||||||
|
<Select placeholder="Select a category">
|
||||||
|
<Option value="travel">Travel</Option>
|
||||||
|
<Option value="entertainment">Entertainment</Option>
|
||||||
|
</Select>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Tags">
|
||||||
|
<EditableTagGroup/>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Price">
|
||||||
|
<Input prefix="$" placeholder="00.00" />
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Share with all tenents?">
|
||||||
|
<Checkbox > </Checkbox>
|
||||||
|
</Form.Item>
|
||||||
|
<Form.Item {...formItemLayout} label="Meta Daa">
|
||||||
|
<InputGroup>
|
||||||
|
<Row gutter={8}>
|
||||||
|
<Col span={5}>
|
||||||
|
<Input placeholder="Key" />
|
||||||
|
</Col>
|
||||||
|
<Col span={10}>
|
||||||
|
<Input placeholder="value" />
|
||||||
|
</Col>
|
||||||
|
<Col span={4}>
|
||||||
|
<Button type="dashed" shape="circle" icon="plus" />
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
</InputGroup>
|
||||||
|
</Form.Item>
|
||||||
|
</Form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Step1;
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react"
|
||||||
|
|
||||||
|
class Step2 extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<p>tttoooeeee</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Step2;
|
@ -0,0 +1,29 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react"
|
||||||
|
|
||||||
|
class Step3 extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<p>tttoooeeee</p>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Step3;
|
@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
.stepForm {
|
||||||
|
max-width: 500px;
|
||||||
|
margin: 40px auto 0;
|
||||||
|
}
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import { Upload, Icon, Modal} from 'antd';
|
||||||
|
|
||||||
|
|
||||||
|
class UploadScreenshots extends React.Component {
|
||||||
|
state = {
|
||||||
|
previewVisible: false,
|
||||||
|
previewImage: '',
|
||||||
|
fileList: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancel = () => this.setState({ previewVisible: false });
|
||||||
|
|
||||||
|
handlePreview = (file) => {
|
||||||
|
this.setState({
|
||||||
|
previewImage: file.url || file.thumbUrl,
|
||||||
|
previewVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = ({ fileList }) => this.setState({ fileList });
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { previewVisible, previewImage, fileList } = this.state;
|
||||||
|
const uploadButton = (
|
||||||
|
<div>
|
||||||
|
<Icon type="plus" />
|
||||||
|
<div className="ant-upload-text">Upload</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="clearfix">
|
||||||
|
<Upload
|
||||||
|
action="//jsonplaceholder.typicode.com/posts/"
|
||||||
|
listType="picture-card"
|
||||||
|
fileList={fileList}
|
||||||
|
onPreview={this.handlePreview}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
>
|
||||||
|
{fileList.length >= 3 ? null : uploadButton}
|
||||||
|
</Upload>
|
||||||
|
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
|
||||||
|
<img alt="example" style={{ width: '100%' }} src={previewImage} />
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default UploadScreenshots;
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import { Upload, Icon, Modal} from 'antd';
|
||||||
|
|
||||||
|
|
||||||
|
class AddTagModal extends React.Component {
|
||||||
|
state = {
|
||||||
|
previewVisible: false,
|
||||||
|
previewImage: '',
|
||||||
|
fileList: [],
|
||||||
|
};
|
||||||
|
|
||||||
|
handleCancel = () => this.setState({ previewVisible: false });
|
||||||
|
|
||||||
|
handlePreview = (file) => {
|
||||||
|
this.setState({
|
||||||
|
previewImage: file.url || file.thumbUrl,
|
||||||
|
previewVisible: true,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
handleChange = ({ fileList }) => this.setState({ fileList });
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { previewVisible, previewImage, fileList } = this.state;
|
||||||
|
const uploadButton = (
|
||||||
|
<div>
|
||||||
|
<Icon type="plus" />
|
||||||
|
<div className="ant-upload-text">Upload</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
return (
|
||||||
|
<div className="clearfix">
|
||||||
|
<Upload
|
||||||
|
action="//jsonplaceholder.typicode.com/posts/"
|
||||||
|
listType="picture-card"
|
||||||
|
fileList={fileList}
|
||||||
|
onPreview={this.handlePreview}
|
||||||
|
onChange={this.handleChange}
|
||||||
|
>
|
||||||
|
{fileList.length >= 3 ? null : uploadButton}
|
||||||
|
</Upload>
|
||||||
|
<Modal visible={previewVisible} footer={null} onCancel={this.handleCancel}>
|
||||||
|
<img alt="example" style={{ width: '100%' }} src={previewImage} />
|
||||||
|
</Modal>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
export default AddTagModal;
|
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import AppList from "../../../components/apps/AppList";
|
||||||
|
|
||||||
|
class Apps extends React.Component {
|
||||||
|
routes;
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.routes = props.routes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {deviceType} = this.props.match.params;
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div style={{background: '#f0f2f5', padding: 24, minHeight: 760}}>
|
||||||
|
{deviceType!==null && <AppList changeSelectedMenuItem={this.props.changeSelectedMenuItem} deviceType={deviceType}/>}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Apps;
|
@ -0,0 +1,131 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import '../../../../App.css';
|
||||||
|
import {Skeleton, Typography, Row, Col, Card, message, notification, Breadcrumb, Icon} from "antd";
|
||||||
|
import ReleaseView from "../../../../components/apps/release/ReleaseView";
|
||||||
|
import axios from "axios";
|
||||||
|
import {withConfigContext} from "../../../../context/ConfigContext";
|
||||||
|
import {Link} from "react-router-dom";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
|
||||||
|
class Release extends React.Component {
|
||||||
|
routes;
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.routes = props.routes;
|
||||||
|
this.state = {
|
||||||
|
loading: true,
|
||||||
|
app: null,
|
||||||
|
uuid: null
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
const {uuid, deviceType} = this.props.match.params;
|
||||||
|
this.fetchData(uuid);
|
||||||
|
this.props.changeSelectedMenuItem(deviceType);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(prevProps, prevState, snapshot) {
|
||||||
|
if (prevState.uuid !== this.state.uuid) {
|
||||||
|
const {uuid, deviceType} = this.props.match.params;
|
||||||
|
this.fetchData(uuid);
|
||||||
|
this.props.changeSelectedMenuItem(deviceType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData = (uuid) => {
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
//send request to the invoker
|
||||||
|
axios.get(
|
||||||
|
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.store + "/applications/" + uuid,
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let app = res.data.data;
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
app: app,
|
||||||
|
loading: false,
|
||||||
|
uuid: uuid
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
console.log(error);
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 401) {
|
||||||
|
//todo display a popop with error
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = window.location.origin + '/store/login';
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to load releases.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({loading: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {app, loading} = this.state;
|
||||||
|
const {deviceType} = this.props.match.params;
|
||||||
|
|
||||||
|
let content = <Title level={3}>No Releases Found</Title>;
|
||||||
|
let appName = "loading...";
|
||||||
|
|
||||||
|
if (app != null && app.applicationReleases.length !== 0) {
|
||||||
|
content = <ReleaseView app={app} deviceType={deviceType}/>;
|
||||||
|
appName = app.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div style={{background: '#f0f2f5', minHeight: 780}}>
|
||||||
|
<Row style={{padding: 10}}>
|
||||||
|
<Col lg={4}>
|
||||||
|
|
||||||
|
</Col>
|
||||||
|
<Col lg={16} md={24} style={{padding: 3}}>
|
||||||
|
<Breadcrumb style={{paddingBottom: 16}}>
|
||||||
|
<Breadcrumb.Item>
|
||||||
|
<Link to={"/store/"+deviceType}><Icon type="home"/> {deviceType + " apps"} </Link>
|
||||||
|
</Breadcrumb.Item>
|
||||||
|
<Breadcrumb.Item>{appName}</Breadcrumb.Item>
|
||||||
|
</Breadcrumb>
|
||||||
|
<Card>
|
||||||
|
<Skeleton loading={loading} avatar={{size: 'large'}} active paragraph={{rows: 8}}>
|
||||||
|
{content}
|
||||||
|
</Skeleton>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default withConfigContext(Release);
|
@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 from "react";
|
||||||
|
import {notification, Menu, Icon} from 'antd';
|
||||||
|
import axios from 'axios';
|
||||||
|
import {withConfigContext} from "../../../context/ConfigContext";
|
||||||
|
|
||||||
|
/*
|
||||||
|
This class for call the logout api by sending request
|
||||||
|
*/
|
||||||
|
class Logout extends React.Component {
|
||||||
|
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
inValid: false,
|
||||||
|
loading: false
|
||||||
|
};
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
This function call the logout api when the request is success
|
||||||
|
*/
|
||||||
|
handleSubmit = () => {
|
||||||
|
|
||||||
|
const thisForm = this;
|
||||||
|
const config = this.props.context;
|
||||||
|
|
||||||
|
thisForm.setState({
|
||||||
|
inValid: false
|
||||||
|
});
|
||||||
|
|
||||||
|
axios.post(window.location.origin + config.serverConfig.logoutUri
|
||||||
|
).then(res => {
|
||||||
|
//if the api call status is correct then user will logout and then it goes to login page
|
||||||
|
if (res.status === 200) {
|
||||||
|
window.location = window.location.origin + "/store/login";
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
|
||||||
|
if (error.hasOwnProperty("response") && error.response.status === 400) {
|
||||||
|
thisForm.setState({
|
||||||
|
inValid: true
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
notification["error"]({
|
||||||
|
message: "There was a problem",
|
||||||
|
duration: 0,
|
||||||
|
description:
|
||||||
|
"Error occurred while trying to logout.",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<Menu>
|
||||||
|
<Menu.Item key="1" onClick={this.handleSubmit}><Icon type="logout"/>Logout</Menu.Item>
|
||||||
|
</Menu>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default withConfigContext(Logout);
|
@ -0,0 +1,153 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2019, Entgra (pvt) Ltd. (http://entgra.io) All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Entgra (pvt) Ltd. 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 optional code is used to register a service worker.
|
||||||
|
// register() is not called by default.
|
||||||
|
|
||||||
|
// This lets the app load faster on subsequent visits in production, and gives
|
||||||
|
// it offline capabilities. However, it also means that developers (and users)
|
||||||
|
// will only see deployed updates on subsequent visits to a page, after all the
|
||||||
|
// existing tabs open on the page have been closed, since previously cached
|
||||||
|
// resources are updated in the background.
|
||||||
|
|
||||||
|
// To learn more about the benefits of this model and instructions on how to
|
||||||
|
// opt-in, read https://bit.ly/CRA-PWA
|
||||||
|
|
||||||
|
const isLocalhost = Boolean(
|
||||||
|
window.location.hostname === 'localhost' ||
|
||||||
|
// [::1] is the IPv6 localhost address.
|
||||||
|
window.location.hostname === '[::1]' ||
|
||||||
|
// 127.0.0.1/8 is considered localhost for IPv4.
|
||||||
|
window.location.hostname.match(
|
||||||
|
/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
export function register(config) {
|
||||||
|
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
|
// The URL constructor is available in all browsers that support SW.
|
||||||
|
const publicUrl = new URL(process.env.PUBLIC_URL, window.location.href);
|
||||||
|
if (publicUrl.origin !== window.location.origin) {
|
||||||
|
// Our service worker won't work if PUBLIC_URL is on a different origin
|
||||||
|
// from what our page is served on. This might happen if a CDN is used to
|
||||||
|
// serve assets; see https://github.com/facebook/create-react-app/issues/2374
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener('load', () => {
|
||||||
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||||
|
|
||||||
|
if (isLocalhost) {
|
||||||
|
// This is running on localhost. Let's check if a service worker still exists or not.
|
||||||
|
checkValidServiceWorker(swUrl, config);
|
||||||
|
|
||||||
|
// Add some additional logging to localhost, pointing developers to the
|
||||||
|
// service worker/PWA documentation.
|
||||||
|
navigator.serviceWorker.ready.then(() => {
|
||||||
|
console.log(
|
||||||
|
'This web app is being served cache-first by a service ' +
|
||||||
|
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Is not localhost. Just register service worker
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerValidSW(swUrl, config) {
|
||||||
|
navigator.serviceWorker
|
||||||
|
.register(swUrl)
|
||||||
|
.then(registration => {
|
||||||
|
registration.onupdatefound = () => {
|
||||||
|
const installingWorker = registration.installing;
|
||||||
|
if (installingWorker == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
installingWorker.onstatechange = () => {
|
||||||
|
if (installingWorker.state === 'installed') {
|
||||||
|
if (navigator.serviceWorker.controller) {
|
||||||
|
// At this point, the updated precached content has been fetched,
|
||||||
|
// but the previous service worker will still serve the older
|
||||||
|
// content until all client tabs are closed.
|
||||||
|
console.log(
|
||||||
|
'New content is available and will be used when all ' +
|
||||||
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||||
|
);
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onUpdate) {
|
||||||
|
config.onUpdate(registration);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// At this point, everything has been precached.
|
||||||
|
// It's the perfect time to display a
|
||||||
|
// "Content is cached for offline use." message.
|
||||||
|
console.log('Content is cached for offline use.');
|
||||||
|
|
||||||
|
// Execute callback
|
||||||
|
if (config && config.onSuccess) {
|
||||||
|
config.onSuccess(registration);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error('Error during service worker registration:', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkValidServiceWorker(swUrl, config) {
|
||||||
|
// Check if the service worker can be found. If it can't reload the page.
|
||||||
|
fetch(swUrl)
|
||||||
|
.then(response => {
|
||||||
|
// Ensure service worker exists, and that we really are getting a JS file.
|
||||||
|
const contentType = response.headers.get('content-type');
|
||||||
|
if (
|
||||||
|
response.status === 404 ||
|
||||||
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
|
) {
|
||||||
|
// No service worker found. Probably a different app. Reload the page.
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister().then(() => {
|
||||||
|
window.location.reload();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Service worker found. Proceed as normal.
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(
|
||||||
|
'No internet connection found. App is running in offline mode.'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function unregister() {
|
||||||
|
if ('serviceWorker' in navigator) {
|
||||||
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
|
registration.unregister();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
* 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 path = require('path');
|
||||||
|
const HtmlWebPackPlugin = require("html-webpack-plugin");
|
||||||
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
|
||||||
|
const configurations = require("./public/conf/config.json");
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
devtool: "source-map",
|
||||||
|
output: {
|
||||||
|
publicPath: '/store/'
|
||||||
|
},
|
||||||
|
watch: false,
|
||||||
|
resolve: {
|
||||||
|
alias: {
|
||||||
|
AppData: path.resolve(__dirname, 'source/src/app/common/'),
|
||||||
|
AppComponents: path.resolve(__dirname, 'source/src/app/components/')
|
||||||
|
},
|
||||||
|
extensions: ['.jsx', '.js', '.ttf', '.woff', '.woff2', '.svg']
|
||||||
|
},
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.(js|jsx)$/,
|
||||||
|
exclude: /node_modules/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'babel-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.html$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "html-loader",
|
||||||
|
options: { minimize: true }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
use: [MiniCssExtractPlugin.loader, "css-loader"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [
|
||||||
|
MiniCssExtractPlugin.loader,
|
||||||
|
"css-loader",
|
||||||
|
"postcss-loader",
|
||||||
|
"sass-loader"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.scss$/,
|
||||||
|
use: [ 'style-loader', 'scss-loader' ]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.less$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "style-loader"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "css-loader",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "less-loader",
|
||||||
|
options: {
|
||||||
|
modifyVars: {
|
||||||
|
'primary-color': configurations.theme.primaryColor,
|
||||||
|
'link-color': configurations.theme.primaryColor,
|
||||||
|
},
|
||||||
|
javascriptEnabled: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(woff|woff2|eot|ttf|svg)$/,
|
||||||
|
loader: 'url-loader?limit=100000',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.(png|jpe?g)/i,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: "url-loader",
|
||||||
|
options: {
|
||||||
|
name: "./img/[name].[ext]",
|
||||||
|
limit: 10000
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: "img-loader"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
new HtmlWebPackPlugin({
|
||||||
|
template: "./src/index.html",
|
||||||
|
filename: "./index.html"
|
||||||
|
}),
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: "[name].css",
|
||||||
|
chunkFilename: "[id].css"
|
||||||
|
})
|
||||||
|
],
|
||||||
|
externals: {
|
||||||
|
'Config': JSON.stringify(require('./public/conf/config.json'))
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (process.env.NODE_ENV === "development") {
|
||||||
|
config.watch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = config;
|
@ -0,0 +1,25 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
~ Copyright (c) 2016, 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.
|
||||||
|
-->
|
||||||
|
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
|
||||||
|
<display-name>Store-Webapp</display-name>
|
||||||
|
<error-page>
|
||||||
|
<error-code>404</error-code>
|
||||||
|
<location>/index.html</location>
|
||||||
|
</error-page>
|
||||||
|
</web-app>
|