Merge branch 'application-mgt-new' into 'application-mgt-new'

Create component to add new app in APPM UI

See merge request entgra/carbon-device-mgt!149
feature/appm-store/pbac
Dharmakeerthi Lasantha 6 years ago
commit e846207a49

@ -15,6 +15,7 @@
"axios": "^0.18.0", "axios": "^0.18.0",
"d3": "^5.9.2", "d3": "^5.9.2",
"dagre": "^0.8.4", "dagre": "^0.8.4",
"fetch": "^1.1.0",
"keymirror": "^0.1.1", "keymirror": "^0.1.1",
"rc-tween-one": "^2.4.1", "rc-tween-one": "^2.4.1",
"react": "^16.8.4", "react": "^16.8.4",

@ -10,12 +10,12 @@ const {Option} = Select;
const {Title, Text} = Typography; const {Title, Text} = Typography;
const Search = Input.Search; const Search = Input.Search;
// connecting state.apps with the component // connecting state.apps with the component
const mapStateToProps = state => { // const mapStateToProps = state => {
return {apps: state.apps} // return {apps: state.apps}
}; // };
class ConnectedListApps extends React.Component { class ListApps extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
@ -70,6 +70,6 @@ class ConnectedListApps extends React.Component {
} }
} }
const ListApps = connect(mapStateToProps, {getApps})(ConnectedListApps); // const ListApps = connect(mapStateToProps, {getApps})(ConnectedListApps);
export default ListApps; export default ListApps;

@ -0,0 +1,569 @@
import React from "react";
import "antd/dist/antd.css";
import {
PageHeader,
Typography,
Card,
Steps,
Button,
message,
Row,
Col,
Tag,
Tooltip,
Input,
Icon,
Select,
Switch,
Form,
Upload,
Divider, notification
} from "antd";
import IconImage from "./IconImg";
import UploadScreenshots from "./UploadScreenshots";
import axios from "axios";
import config from "../../../public/conf/config.json";
const Paragraph = Typography;
const Dragger = Upload.Dragger;
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 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 AddNewAppFormComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
current: 0,
categories: [],
tags: [],
icons: [],
screenshots: []
};
}
componentDidMount() {
this.getCategories();
this.getTags();
}
getCategories = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/categories",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let categories = JSON.parse(res.data.data);
this.setState({
categories: categories,
loading: false
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
getTags = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/tags",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let tags = JSON.parse(res.data.data);
this.setState({
tags: tags,
loading: false,
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
handleCategoryChange = (value) => {
console.log(`selected ${value}`);
};
handleSubmit = e => {
e.preventDefault();
this.props.form.validateFields((err, values) => {
if (!err) {
const {name, description, appCategories, tags, deviceType, price, isSharedWithAllTenants, binaryFile, icon, screenshots} = values;
const payload = {
binaryFile: binaryFile[0].originFileObj,
icon: icon[0].originFileObj,
screenshot1: screenshots[0].originFileObj,
screenshot2: screenshots[1].originFileObj,
screenshot3: screenshots[2].originFileObj,
application: {
name,
description,
appCategories,
subType: (price === undefined || parseInt(price) === 0) ? "FREE" : "PAID",
tags,
unrestrictedRoles: [],
deviceType,
entAppReleaseWrappers: [{
description,
price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants,
metaData: "string",
supportedOsVersions: "4.0-10.0"
}]
}
};
console.log(payload);
// let data = new FormData();
//
// const url = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/ent-app";
//
// data.append('binaryFile', binaryFile[0].originFileObj);
// data.append('icon', icon[0].originFileObj);
// data.append('screenshot1', screenshots[0].originFileObj);
// data.append('screenshot2', screenshots[1].originFileObj);
// data.append('screenshot3', screenshots[2].originFileObj);
// data.append('application', JSON.toString(payload.application));
// let request = new XMLHttpRequest();
// request.open('POST', url);
// request.send(data);
// var xhr = new XMLHttpRequest();
// // xhr.withCredentials = true;
//
// xhr.addEventListener("readystatechange", function () {
// if (this.readyState === 4) {
// console.log(this.responseText);
// }
// });
//
// xhr.open("POST", "https://localhost:9443/ui-request-handler/invoke/application-mgt-publisher/v1.0/applications/ent-app");
// xhr.open("GET", "https://localhost:9443/ui-request-handler/invoke/application-mgt-publisher/v1.0/applications/tags");
// xhr.setRequestHeader("Content-Type", "multipart/mixed");
// xhr.setRequestHeader("X-Platform", "publisher");
//
// // xhr.setRequestHeader("Accept", "*/*");
//
// xhr.send(data);
// xhr.send();
// const options = {method: 'POST', body: data};
//
// fetch(url, options).then(function (response) {
// console.log(response);
// });
// axios.post(
// url,
// data,
// {
// headers:{
// 'X-Platform': config.serverConfig.platform,
// 'Content-Type': 'multipart/mixed',
// 'content-type': 'multipart/form-data'
// },
// 'Content-Type': 'multipart/mixed',
// 'content-type': 'multipart/form-data'
// }
// ).then(res => {
// if (res.status === 201) {
// this.setState({
// loading: false,
// });
//
// notification["success"]({
// message: "Done!",
// description:
// "New app was added successfully",
// });
// }
//
// }).catch((error) => {
// if (error.response.status === 401) {
// window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
// } else {
// message.warning('Something went wrong');
//
// }
// this.setState({
// loading: false
// });
// });
var data = new FormData();
// data.append("binaryFile", "/Users/jayasanka/Desktop/gov/viber/a.apk");
// data.append("application", "{\n\t\"name\": \"Tub1111\",\n\t\"description\": \"Watch thousands of hit movies and TV series for free. Tubi is 100% legal unlimited streaming, with no credit cards and no subscription required. Choose what you want to watch, when you want to watch it, with fewer ads than regular TV. Tubi is the largest free streaming service featuring award-winning movies and TV series. There is something for everybody; from comedy to drama, kids to classics, and niche favorites such as Korean dramas, anime, and British series. Download now and start streaming entertainment for free, today!\",\n\t\"appCategories\": [\"EMM\"],\n\t\"subType\": \"FREE\",\n\t\"tags\": [\"tv\", \"movies\"],\n\t\"unrestrictedRoles\": [],\n\t\"deviceType\": \"android\",\n\t\"entAppReleaseWrappers\": [{\n\t\t\"description\": \" SEND A MESSAGE -Skip exchanging phone numbers, just send a message. It's seamless across devices. * SHOW YOUR REACTION - Add a silly sticker\",\n\t\t\"releaseType\": \"GA\",\n\t\t\"price\": 0.0,\n\t\t\"isSharedWithAllTenants\": false,\n\t\t\"metaData\": \"{\\\"developer\\\":\\\"Facebook, Inc.\\\",\\\"Copyright\\\":\\\"\\u00A9 Facebook, Inc.\\\",\\\"Location\\\":\\\"This app may use your location even when it isn't open, which can decrease battery life.\\\"}\",\n\t\t\"ratedUsers\": 0,\n\t\t\"rating\": 0,\n\t\t\"supportedOsVersions\": \"4.0-10.0\"\n\t}]\n}");
// data.append("icon", "/Users/jayasanka/Desktop/gov/angular/i.png");
// data.append("screenshot1", "/Users/jayasanka/Desktop/gov/angular/1.webp");
// data.append("screenshot2", "/Users/jayasanka/Desktop/gov/angular/2.webp");
// data.append("screenshot3", "/Users/jayasanka/Desktop/gov/angular/3.webp");
data.append('binaryFile', binaryFile[0].originFileObj);
data.append('icon', icon[0].originFileObj);
data.append('screenshot1', screenshots[0].originFileObj);
data.append('screenshot2', screenshots[1].originFileObj);
data.append('screenshot3', screenshots[2].originFileObj);
data.append('application', JSON.toString(payload.application));
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://localhost:9443/ui-request-handler/invoke/application-mgt-publisher/v1.0/applications/ent-app");
xhr.setRequestHeader("Content-Type", "multipart/mixed");
xhr.setRequestHeader("X-Platform", "publisher");
xhr.send(data);
}
});
};
normFile = e => {
console.log('Upload event:', e);
if (Array.isArray(e)) {
return e;
}
return e && e.fileList;
};
handleIconChange = ({fileList}) => this.setState({icons: fileList});
handleScreenshotChange = ({fileList}) => this.setState({screenshots: fileList});
validateIcon = (rule, value, callback) => {
const {icons} = this.state;
if (icons.length !== 1) {
callback("Please select icon file");
}
callback();
};
render() {
const {categories, tags, icons, screenshots} = this.state;
const {getFieldDecorator} = this.props.form;
return (
<div>
<Row>
<Col span={20} offset={2}>
<Card>
<Form labelAlign="left" layout="horizontal"
hideRequiredMark
onSubmit={this.handleSubmit}>
<Row>
<Col span={12}>
<div>
{/*device type*/}
<Form.Item {...formItemLayout} label="Device Type">
{getFieldDecorator('deviceType', {
rules: [{
required: false,
message: 'Please select device type'
},
{
validator: this.validateIcon
}],
})(
<Select placeholder="select device type">
<Option key="android">Android</Option>
<Option key="ios">iOS</Option>
</Select>
)}
</Form.Item>
{/*app name*/}
<Form.Item {...formItemLayout} label="App Name">
{getFieldDecorator('name', {
rules: [{
required: false,
message: 'Please input a name'
}],
})(
<Input placeholder="ex: Lorem App"/>
)}
</Form.Item>
{/*description*/}
<Form.Item {...formItemLayout} label="Description">
{getFieldDecorator('description', {
rules: [{
required: false,
message: 'Please enter a description'
}],
})(
<TextArea placeholder="Enter the description..." rows={7}/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Categories">
{getFieldDecorator('appCategories', {
rules: [{
required: false,
message: 'Please select categories'
}],
})(
<Select
mode="multiple"
style={{width: '100%'}}
placeholder="Select a Category"
onChange={this.handleCategoryChange}
>
{
categories.map(category => {
return (
<Option
key={category.categoryName}>
{category.categoryName}
</Option>
)
})
}
</Select>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Price">
{getFieldDecorator('price', {
rules: [{
required: false
}],
})(
<Input prefix="$" placeholder="00.00"/>
)}
</Form.Item>
<Form.Item {...formItemLayout} label="Is Shared?">
{getFieldDecorator('isSharedWithAllTenants', {
rules: [{
required: false,
message: 'Please select'
}],
})(
<Switch checkedChildren={<Icon type="check"/>}
unCheckedChildren={<Icon type="close"/>} defaultChecked/>
)}
</Form.Item>
<Divider/>
<Form.Item {...formItemLayout} label="Tags">
{getFieldDecorator('tags', {
rules: [{
required: false,
message: 'Please select tags'
}],
})(
<Select
mode="tags"
style={{width: '100%'}}
placeholder="Tags"
>
{
tags.map(tag => {
return (
<Option
key={tag.tagName}>
{tag.tagName}
</Option>
)
})
}
</Select>
)}
</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.Item wrapperCol={{span: 12, offset: 5}}>
<Button type="primary" htmlType="submit">
Submit
</Button>
</Form.Item>
</div>
</Col>
<Col span={12} style={{paddingLeft: 20}}>
<Form.Item label="Application">
<div className="dropbox">
{getFieldDecorator('binaryFile', {
valuePropName: 'fileList',
getValueFromEvent: this.normFile,
required: false,
message: 'Please select tags'
})(
<Upload.Dragger
name="files"
beforeUpload={() => false}
multiple={false}
>
<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.</p>
</Upload.Dragger>,
)}
</div>
</Form.Item>
<Row>
<Col span={12}>
<Form.Item label="Icon">
{getFieldDecorator('icon', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
required: false,
message: 'Please select a icon'
})(
<Upload
name="logo"
onChange={this.handleIconChange}
beforeUpload={() => false}
>
{icons.length !== 1 && (
<Button>
<Icon type="upload"/> Click to upload
</Button>
)}
</Upload>,
)}
</Form.Item>
</Col>
</Row>
<Row style={{marginTop: 40}}>
<Col span={24}>
<Form.Item label="Screenshots">
{getFieldDecorator('screenshots', {
valuePropName: 'icon',
getValueFromEvent: this.normFile,
required: false,
message: 'Please select a icon'
})(
<Upload
name="screenshots"
onChange={this.handleScreenshotChange}
beforeUpload={() => false}
multiple
>
{screenshots.length < 3 && (
<Button>
<Icon type="upload"/> Click to upload
</Button>
)}
</Upload>,
)}
</Form.Item>
</Col>
</Row>
</Col>
</Row>
</Form>
</Card>
</Col>
</Row>
</div>
);
}
}
const AddNewAppForm = Form.create({name: 'add-new-app'})(AddNewAppFormComponent);
export default AddNewAppForm;

@ -37,7 +37,7 @@ class IconImage extends React.Component {
loading: false, loading: false,
})); }));
} }
} };
render() { render() {
const uploadButton = ( const uploadButton = (

@ -9,8 +9,6 @@ import Release from "./pages/dashboard/apps/release/Release";
import AddNewApp from "./pages/dashboard/add-new-app/AddNewApp"; import AddNewApp from "./pages/dashboard/add-new-app/AddNewApp";
import Mange from "./pages/dashboard/manage/Manage"; import Mange from "./pages/dashboard/manage/Manage";
import './index.css'; import './index.css';
import store from "./js/store/index";
import {Provider} from "react-redux";
const routes = [ const routes = [
@ -20,7 +18,7 @@ const routes = [
component: Login component: Login
}, },
{ {
path: '/publisher/apps', path: '/publisher/',
exact: false, exact: false,
component: Dashboard, component: Dashboard,
routes: [ routes: [
@ -30,21 +28,25 @@ const routes = [
exact: true exact: true
}, },
{ {
path: '/publisher/apps/new-app', path: '/publisher/apps/releases/:uuid',
exact: true,
component: Release
},
{
path: '/publisher/add-new-app/enterprise',
component: AddNewApp, component: AddNewApp,
exact: true exact: true
}, },
{ {
path: '/publisher/apps/releases/:uuid', path: '/publisher/add-new-app/public',
exact: true, component: AddNewApp,
component: Release exact: true
} },
] {
},{ path: '/publisher/add-new-app/web-clip',
path: '/publisher/manage', component: AddNewApp,
exact: false, exact: true
component: Dashboard, },
routes: [
{ {
path: '/publisher/manage', path: '/publisher/manage',
component: Mange, component: Mange,
@ -56,9 +58,7 @@ const routes = [
ReactDOM.render( ReactDOM.render(
<Provider store={store}> <App routes={routes}/>,
<App routes={routes}/>
</Provider>,
document.getElementById('root')); document.getElementById('root'));
// If you want your app to work offline and load faster, you can change // If you want your app to work offline and load faster, you can change

@ -1,14 +1,14 @@
import React from "react"; import React from "react";
import {Layout, Menu, Icon} from 'antd'; import {Layout, Menu, Icon} from 'antd';
const {Header, Content, Footer} = Layout;
import Logo from "../../../public/images/logo.svg"; import Logo from "../../../public/images/logo.svg";
import {BrowserRouter,Switch,Link, NavLink} from "react-router-dom"; import {Switch, Link} from "react-router-dom";
import RouteWithSubRoutes from "../../components/RouteWithSubRoutes" import RouteWithSubRoutes from "../../components/RouteWithSubRoutes"
import {Redirect} from 'react-router' import {Redirect} from 'react-router'
import "../../App.css"; import "../../App.css";
const {Header, Content, Footer} = Layout;
const {SubMenu} = Menu;
class Dashboard extends React.Component { class Dashboard extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
@ -32,8 +32,18 @@ class Dashboard extends React.Component {
style={{lineHeight: '64px'}} style={{lineHeight: '64px'}}
> >
<Menu.Item key="1"><Link to="/publisher/apps"><Icon type="appstore"/>Apps</Link></Menu.Item> <Menu.Item key="1"><Link to="/publisher/apps"><Icon type="appstore"/>Apps</Link></Menu.Item>
<Menu.Item key="3"><Link to="/publisher/apps/new-app"><Icon type="upload"/>Add New <SubMenu
App</Link></Menu.Item> title={
<span className="submenu-title-wrapper">
<Icon type="plus"/>
Add New App
</span>
}
>
<Menu.Item key="setting:1"><Link to="/publisher/add-new-app/public">Public APP</Link></Menu.Item>
<Menu.Item key="setting:2"><Link to="/publisher/add-new-app/enterprise">Enterprise APP</Link></Menu.Item>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web Clip</Link></Menu.Item>
</SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon <Menu.Item key="2"><Link to="/publisher/manage"><Icon
type="control"/>Manage</Link></Menu.Item> type="control"/>Manage</Link></Menu.Item>
</Menu> </Menu>
@ -41,7 +51,6 @@ class Dashboard extends React.Component {
</Layout> </Layout>
<Layout> <Layout>
<Content style={{padding: '0 0'}}> <Content style={{padding: '0 0'}}>
<BrowserRouter>
<Switch> <Switch>
<Redirect exact from="/publisher" to="/publisher/apps"/> <Redirect exact from="/publisher" to="/publisher/apps"/>
{this.state.routes.map((route) => ( {this.state.routes.map((route) => (
@ -49,7 +58,6 @@ class Dashboard extends React.Component {
))} ))}
</Switch> </Switch>
</BrowserRouter>
</Content> </Content>
<Footer style={{textAlign: 'center'}}> <Footer style={{textAlign: 'center'}}>

@ -19,29 +19,12 @@ import {
Upload, Upload,
Divider Divider
} from "antd"; } from "antd";
import Step1 from "./Step1"; import axios from "axios";
import Step2 from "./Step2"; import AddNewAppForm from "../../../components/new-app/AddNewAppForm"
import Step3 from "./Step3"; import config from "../../../../public/conf/config.json";
import styles from "./Style.less";
import IconImage from "./IconImg";
import UploadScreenshots from "./UploadScreenshots";
const Paragraph = Typography; const Paragraph = Typography;
const Dragger = Upload.Dragger; const Dragger = Upload.Dragger;
const routes = [
{
path: 'index',
breadcrumbName: 'publisher',
},
{
path: 'first',
breadcrumbName: 'dashboard',
},
{
path: 'second',
breadcrumbName: 'add new app',
},
];
const props = { const props = {
name: 'file', name: 'file',
@ -60,18 +43,17 @@ const props = {
}, },
}; };
const Step = Steps.Step; //
// const steps = [{
const steps = [{ // title: 'First',
title: 'First', // content: Step1
content: Step1 // }, {
}, { // title: 'Second',
title: 'Second', // content: Step2,
content: Step2, // }, {
}, { // title: 'Last',
title: 'Last', // content: Step3,
content: Step3, // }];
}];
const {Option} = Select; const {Option} = Select;
@ -87,95 +69,18 @@ const formItemLayout = {
}, },
}; };
class EditableTagGroup extends React.Component {
state = {
tags: [],
inputVisible: false,
inputValue: '',
};
handleClose = (removedTag) => {
const tags = this.state.tags.filter(tag => tag !== removedTag);
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 { class AddNewApp extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
current: 0, current: 0,
categories: []
}; };
} }
tags = []; componentDidMount() {
// this.getCategories();
addTag(key, value){
this.tags.push(<Option key={key}>{value}</Option>);
} }
next() { next() {
@ -188,17 +93,44 @@ class AddNewApp extends React.Component {
this.setState({current}); this.setState({current});
} }
getCategories = () => {
axios.get(
config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/categories",
{
headers: {'X-Platform': config.serverConfig.platform}
}).then(res => {
if (res.status === 200) {
let categories = JSON.parse(res.data.data);
this.setState({
categories: categories,
loading: false
});
}
}).catch((error) => {
if (error.response.status === 401) {
window.location.href = config.serverConfig.protocol + "://" + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + '/publisher/login';
} else {
message.warning('Something went wrong');
}
this.setState({
loading: false
});
});
};
handleCategoryChange = (value) => {
console.log(`selected ${value}`);
};
render() { render() {
const {current} = this.state; const {categories} = this.state;
const Content = steps[current].content;
this.addTag('1','Lorem');
this.addTag('2','Ipsum');
return ( return (
<div> <div>
<PageHeader <PageHeader
title="Add New App" title="Add New App"
breadcrumb={{routes}}
> >
<div className="wrap"> <div className="wrap">
<div className="content"> <div className="content">
@ -209,121 +141,7 @@ class AddNewApp extends React.Component {
</div> </div>
</PageHeader> </PageHeader>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 720}}>
<Row> <AddNewAppForm/>
<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>
</div> </div>

@ -33,11 +33,7 @@ class Apps extends React.Component {
render() { render() {
return ( return (
<div> <div>
<PageHeader
breadcrumb={{routes}}
/>
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
<ReleaseModal/>
<ListApps/> <ListApps/>
</div> </div>

Loading…
Cancel
Save