forked from community/device-mgt-core
Create Detailed App view component in APPM publisher See merge request entgra/carbon-device-mgt!121feature/appm-store/pbac
commit
0ef803c2c7
@ -0,0 +1,72 @@
|
|||||||
|
.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,122 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Row, Typography, Icon} from "antd";
|
||||||
|
import StarRatings from "react-star-ratings";
|
||||||
|
import "./DetailedRating.css";
|
||||||
|
import config from "../../../../public/conf/config.json";
|
||||||
|
import axios from "axios";
|
||||||
|
|
||||||
|
const { Text } = Typography;
|
||||||
|
|
||||||
|
|
||||||
|
class DetailedRating extends React.Component{
|
||||||
|
|
||||||
|
constructor(props){
|
||||||
|
super(props);
|
||||||
|
this.state={
|
||||||
|
detailedRating: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.getData(this.props.uuid);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidUpdate(nextProps) {
|
||||||
|
if (nextProps !== this.props) {
|
||||||
|
this.getData(this.props.uuid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getData = (uuid)=>{
|
||||||
|
const request = "method=get&content-type=application/json&payload={}&api-endpoint=/application-mgt-store/v1.0/reviews/"+uuid+"/rating";
|
||||||
|
|
||||||
|
return axios.post('https://' + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invokerUri, request
|
||||||
|
).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 = 'https://localhost:9443/store/login';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const detailedRating = this.state.detailedRating;
|
||||||
|
|
||||||
|
console.log(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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(ratingBarPercentages);
|
||||||
|
|
||||||
|
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 DetailedRating;
|
@ -0,0 +1,95 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {Drawer, Row, Col, Typography, Divider, Tag, Avatar, List} from 'antd';
|
||||||
|
import "../../../App.css";
|
||||||
|
import DetailedRating from "../detailed-rating/DetailedRating";
|
||||||
|
|
||||||
|
const {Text, Title, Paragraph} = Typography;
|
||||||
|
|
||||||
|
class AppDetailsDrawer extends React.Component {
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {app, visible, onClose} = this.props;
|
||||||
|
if (app == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
console.log(app);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
|
||||||
|
<Drawer
|
||||||
|
placement="right"
|
||||||
|
width={640}
|
||||||
|
closable={false}
|
||||||
|
onClose={onClose}
|
||||||
|
visible={visible}
|
||||||
|
>
|
||||||
|
<div style={{textAlign: "center"}}>
|
||||||
|
<img
|
||||||
|
style={{
|
||||||
|
marginBottom: 10,
|
||||||
|
width: 100,
|
||||||
|
borderRadius: "28%",
|
||||||
|
border: "1px solid #ddd"
|
||||||
|
}}
|
||||||
|
src={app.applicationReleases[0].iconPath}
|
||||||
|
/>
|
||||||
|
<Title level={2}>{app.name}</Title>
|
||||||
|
</div>
|
||||||
|
<Divider/>
|
||||||
|
<Paragraph type="secondary" ellipsis={{rows: 3, expandable: true}}>{app.description}</Paragraph>
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
<Text strong={true}>Categories</Text>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<span>
|
||||||
|
{app.appCategories.map(category => {
|
||||||
|
return (
|
||||||
|
<Tag color="blue" key={category} style={{paddingBottom: 5}}>
|
||||||
|
{category}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
<Text strong={true}>Tags</Text>
|
||||||
|
<br/>
|
||||||
|
<br/>
|
||||||
|
<span>
|
||||||
|
{app.tags.map(category => {
|
||||||
|
return (
|
||||||
|
<Tag color="gold" key={category} style={{paddingBottom: 5}}>
|
||||||
|
{category}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
<Text strong={true}>Releases</Text>
|
||||||
|
<br/>
|
||||||
|
<List
|
||||||
|
itemLayout="horizontal"
|
||||||
|
dataSource={app.applicationReleases}
|
||||||
|
renderItem={release => (
|
||||||
|
<List.Item>
|
||||||
|
<List.Item.Meta
|
||||||
|
title={<a href={"apps/releases/"+release.uuid}>{release.version}</a>}
|
||||||
|
description={
|
||||||
|
<div>
|
||||||
|
Status : <Tag>{release.currentStatus}</Tag> Release Type <Tag color="green">{release.releaseType}</Tag>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</List.Item>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
|
||||||
|
<DetailedRating uuid={app.applicationReleases[0].uuid}/>
|
||||||
|
</Drawer>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default AppDetailsDrawer;
|
@ -0,0 +1,180 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Avatar, Card, Col, Row, Table, Typography, Tag, Icon, message} from "antd";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
import {getApps} from "../../../js/actions";
|
||||||
|
import axios from "axios";
|
||||||
|
import config from "../../../../public/conf/config.json";
|
||||||
|
|
||||||
|
const {Title} = Typography;
|
||||||
|
|
||||||
|
// connecting state.apps with the component
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {apps: state.apps}
|
||||||
|
};
|
||||||
|
|
||||||
|
const columns = [
|
||||||
|
{
|
||||||
|
title: '',
|
||||||
|
dataIndex: 'name',
|
||||||
|
render: (name, row) => {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<Avatar shape="square" size="large"
|
||||||
|
style={{
|
||||||
|
marginRight: 20,
|
||||||
|
borderRadius: "28%",
|
||||||
|
border: "1px solid #ddd"
|
||||||
|
}}
|
||||||
|
src={row.applicationReleases[0].iconPath}
|
||||||
|
/>
|
||||||
|
{name}
|
||||||
|
</div>);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Categories',
|
||||||
|
dataIndex: 'appCategories',
|
||||||
|
render: appCategories => (
|
||||||
|
<span>
|
||||||
|
{appCategories.map(category => {
|
||||||
|
return (
|
||||||
|
<Tag color="blue" key={category}>
|
||||||
|
{category}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Platform',
|
||||||
|
dataIndex: 'deviceType',
|
||||||
|
render: platform => {
|
||||||
|
const defaultPlatformIcons = config.defaultPlatformIcons;
|
||||||
|
let icon = defaultPlatformIcons.default.icon;
|
||||||
|
let color = defaultPlatformIcons.default.color;
|
||||||
|
if (defaultPlatformIcons.hasOwnProperty(platform)) {
|
||||||
|
icon = defaultPlatformIcons[platform].icon;
|
||||||
|
color = defaultPlatformIcons[platform].color;
|
||||||
|
}
|
||||||
|
return (<span style={{fontSize: 20, color: color, textAlign: "center"}}><Icon type={icon}
|
||||||
|
theme="filled"/></span>)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Type',
|
||||||
|
dataIndex: 'type'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Subscription',
|
||||||
|
dataIndex: 'subType'
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
class ConnectedAppsTable extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
pagination: {
|
||||||
|
total: 100
|
||||||
|
},
|
||||||
|
apps: []
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.fetch();
|
||||||
|
}
|
||||||
|
|
||||||
|
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,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
fetch = (params = {}) => {
|
||||||
|
this.setState({loading: true});
|
||||||
|
|
||||||
|
const extraParams = {
|
||||||
|
offset: 10 * (params.page - 1),
|
||||||
|
limit: 10
|
||||||
|
};
|
||||||
|
// note: encode with '%26' not '&'
|
||||||
|
const encodedExtraParams = Object.keys(extraParams).map(key => key + '=' + extraParams[key]).join('%26');
|
||||||
|
const parameters = {
|
||||||
|
method: "post",
|
||||||
|
'content-type': "application/json",
|
||||||
|
payload: JSON.stringify({}),
|
||||||
|
'api-endpoint': "/application-mgt-publisher/v1.0/applications?" + encodedExtraParams
|
||||||
|
};
|
||||||
|
|
||||||
|
const request = Object.keys(parameters).map(key => key + '=' + parameters[key]).join('&');
|
||||||
|
console.log(request);
|
||||||
|
axios.post('https://' + config.serverConfig.hostname + ':' + config.serverConfig.httpsPort + config.serverConfig.invokerUri, request
|
||||||
|
).then(res => {
|
||||||
|
if (res.status === 200) {
|
||||||
|
let apps = [];
|
||||||
|
|
||||||
|
if (res.data.data.hasOwnProperty("applications")) {
|
||||||
|
apps = res.data.data.applications;
|
||||||
|
}
|
||||||
|
const pagination = {...this.state.pagination};
|
||||||
|
// Read total count from server
|
||||||
|
// pagination.total = data.totalCount;
|
||||||
|
pagination.total = 200;
|
||||||
|
this.setState({
|
||||||
|
loading: false,
|
||||||
|
apps: apps,
|
||||||
|
pagination,
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}).catch((error) => {
|
||||||
|
if (error.response.status === 401) {
|
||||||
|
message.error('You are not logged in');
|
||||||
|
window.location.href = 'https://localhost:9443/publisher/login';
|
||||||
|
} else {
|
||||||
|
message.error('Something went wrong... :(');
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setState({loading: false});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
console.log("rendered");
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Table
|
||||||
|
rowKey={record => record.id}
|
||||||
|
dataSource={this.state.apps}
|
||||||
|
columns={columns}
|
||||||
|
pagination={this.state.pagination}
|
||||||
|
onChange={this.handleTableChange}
|
||||||
|
onRow={(record, rowIndex) => {
|
||||||
|
return {
|
||||||
|
onClick: event => {
|
||||||
|
this.props.showDrawer(record);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const AppsTable = connect(mapStateToProps, {getApps})(ConnectedAppsTable);
|
||||||
|
|
||||||
|
export default AppsTable;
|
@ -0,0 +1,74 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Avatar, Card, Col, Row, Table, Typography, Input, Divider, Checkbox, Select, Button} from "antd";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {Title, Text} = Typography;
|
||||||
|
|
||||||
|
class Filters extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
|
||||||
|
<Card>
|
||||||
|
<Row>
|
||||||
|
<Col span={6}>
|
||||||
|
<Title level={4}>Filter</Title>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
<Text strong={true}>Category</Text>
|
||||||
|
<br/><br/>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
style={{width: '100%'}}
|
||||||
|
placeholder="All Categories"
|
||||||
|
>
|
||||||
|
<Option key={1}>IoT</Option>
|
||||||
|
<Option key={2}>EMM</Option>
|
||||||
|
</Select>
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
<Text strong={true}>Platform</Text>
|
||||||
|
<br/><br/>
|
||||||
|
<Checkbox>Android</Checkbox><br/>
|
||||||
|
<Checkbox>iOS</Checkbox><br/>
|
||||||
|
<Checkbox>Windows</Checkbox><br/>
|
||||||
|
<Checkbox>Default</Checkbox><br/>
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
<Text strong={true}>Tags</Text>
|
||||||
|
<br/><br/>
|
||||||
|
<Select
|
||||||
|
mode="multiple"
|
||||||
|
style={{width: '100%'}}
|
||||||
|
placeholder="All Tags"
|
||||||
|
>
|
||||||
|
<Option key={1}>test tag</Option>
|
||||||
|
</Select>
|
||||||
|
|
||||||
|
<Divider/>
|
||||||
|
<Text strong={true}>Type</Text>
|
||||||
|
<br/><br/>
|
||||||
|
<Checkbox>Enterprise</Checkbox><br/>
|
||||||
|
<Checkbox>Public</Checkbox><br/>
|
||||||
|
<Checkbox>Web APP</Checkbox><br/>
|
||||||
|
<Checkbox>Web Clip</Checkbox><br/>
|
||||||
|
<Divider/>
|
||||||
|
|
||||||
|
<Text strong={true}>Subscription</Text>
|
||||||
|
<br/><br/>
|
||||||
|
<Checkbox>Free</Checkbox><br/>
|
||||||
|
<Checkbox>Paid</Checkbox><br/>
|
||||||
|
<Divider/>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export default Filters;
|
@ -0,0 +1,76 @@
|
|||||||
|
import React from "react";
|
||||||
|
import {Avatar, Card, Col, Row, Table, Typography, Input, Divider, Checkbox, Select, Button} from "antd";
|
||||||
|
import {connect} from "react-redux";
|
||||||
|
import {getApps} from "../../../js/actions";
|
||||||
|
import AppsTable from "./AppsTable";
|
||||||
|
import Filters from "./Filters";
|
||||||
|
import AppDetailsDrawer from "./AppDetailsDrawer";
|
||||||
|
|
||||||
|
const {Option} = Select;
|
||||||
|
const {Title, Text} = Typography;
|
||||||
|
const Search = Input.Search;
|
||||||
|
// connecting state.apps with the component
|
||||||
|
const mapStateToProps = state => {
|
||||||
|
return {apps: state.apps}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class ConnectedListApps extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.state = {
|
||||||
|
isDrawerVisible: false,
|
||||||
|
selectedApp: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//handler to show app drawer
|
||||||
|
showDrawer = (app) => {
|
||||||
|
console.log(app);
|
||||||
|
this.setState({
|
||||||
|
isDrawerVisible: true,
|
||||||
|
selectedApp: app
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// handler to close the app drawer
|
||||||
|
closeDrawer = () => {
|
||||||
|
this.setState({
|
||||||
|
isDrawerVisible: false
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const {isDrawerVisible} = this.state;
|
||||||
|
return (
|
||||||
|
<Row gutter={28}>
|
||||||
|
<Col md={6}>
|
||||||
|
<Filters/>
|
||||||
|
</Col>
|
||||||
|
<Col md={18}>
|
||||||
|
<Card>
|
||||||
|
<Row>
|
||||||
|
<Col span={6}>
|
||||||
|
<Title level={4}>Apps</Title>
|
||||||
|
</Col>
|
||||||
|
<Col span={18} style={{textAlign: "right"}}>
|
||||||
|
<Search
|
||||||
|
placeholder="input search text"
|
||||||
|
onSearch={value => console.log(value)}
|
||||||
|
style={{width: 200}}
|
||||||
|
/>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<Divider dashed={true}/>
|
||||||
|
<AppsTable showDrawer={this.showDrawer} />
|
||||||
|
<AppDetailsDrawer visible={isDrawerVisible} onClose={this.closeDrawer} app={this.state.selectedApp}/>
|
||||||
|
</Card>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ListApps = connect(mapStateToProps, {getApps})(ConnectedListApps);
|
||||||
|
|
||||||
|
export default ListApps;
|
@ -0,0 +1,60 @@
|
|||||||
|
import React from "react";
|
||||||
|
import "antd/dist/antd.css";
|
||||||
|
import {PageHeader, Typography,Input, Button, Row, Col} from "antd";
|
||||||
|
import AppList from "../../../components/apps/AppList";
|
||||||
|
import ReleaseModal from "../../../components/apps/ReleaseModal";
|
||||||
|
|
||||||
|
const Search = Input.Search;
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: 'index',
|
||||||
|
breadcrumbName: 'Publisher',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'first',
|
||||||
|
breadcrumbName: 'Dashboard',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: 'second',
|
||||||
|
breadcrumbName: 'Apps',
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
|
class Apps extends React.Component {
|
||||||
|
routes;
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.routes = props.routes;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<PageHeader
|
||||||
|
breadcrumb={{routes}}
|
||||||
|
/>
|
||||||
|
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
|
||||||
|
<Row style={{padding:10}}>
|
||||||
|
<Col span={6} offset={18}>
|
||||||
|
<Search
|
||||||
|
placeholder="search"
|
||||||
|
onSearch={value => console.log(value)}
|
||||||
|
style={{ width: 200}}
|
||||||
|
/>
|
||||||
|
<Button style={{margin:5}}>Advanced Search</Button>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
<ReleaseModal/>
|
||||||
|
<AppList/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Apps;
|
Loading…
Reference in new issue