Add UI Improvements to APPM UI

The following changes are with this commit
- Add metadata to Add new app & edit app forms in Publisher
- Display metadata in both publisher and store views
- Fix typo in lifecycle component
- Update table when changing the name & categories in apps table in publisher
feature/appm-store/pbac
Jayasanka 5 years ago
parent c91e1c43e7
commit 6786ed0fab

@ -200,6 +200,7 @@ class AppDetailsDrawer extends React.Component {
window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/" + id, window.location.origin + config.serverConfig.invoker.uri + config.serverConfig.invoker.publisher + "/applications/" + id,
data data
).then(res => { ).then(res => {
this.props.onUpdateApp("name", name);
if (res.status === 200) { if (res.status === 200) {
notification["success"]({ notification["success"]({
message: 'Saved!', message: 'Saved!',
@ -282,6 +283,7 @@ class AppDetailsDrawer extends React.Component {
data data
).then(res => { ).then(res => {
if (res.status === 200) { if (res.status === 200) {
this.props.onUpdateApp("categories", temporaryCategories);
notification["success"]({ notification["success"]({
message: 'Saved!', message: 'Saved!',
description: 'App categories updated successfully!' description: 'App categories updated successfully!'

@ -29,27 +29,10 @@ class ListApps extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
isDrawerVisible: false,
selectedApp: null,
filters: {} filters: {}
} }
} }
//handler to show app drawer
showDrawer = (app) => {
this.setState({
isDrawerVisible: true,
selectedApp: app
});
};
// handler to close the app drawer
closeDrawer = () => {
this.setState({
isDrawerVisible: false
})
};
setFilters = (filters) => { setFilters = (filters) => {
this.setState({ this.setState({
filters filters
@ -71,7 +54,6 @@ class ListApps extends React.Component {
render() { render() {
const {isDrawerVisible, filters} = this.state; const {isDrawerVisible, filters} = this.state;
return ( return (
<Card> <Card>
<Row gutter={28}> <Row gutter={28}>
<Col md={6}> <Col md={6}>
@ -91,9 +73,7 @@ class ListApps extends React.Component {
</Col> </Col>
</Row> </Row>
<Divider dashed={true}/> <Divider dashed={true}/>
<AppsTable filters={filters} showDrawer={this.showDrawer}/> <AppsTable filters={filters}/>
<AppDetailsDrawer visible={isDrawerVisible} onClose={this.closeDrawer}
app={this.state.selectedApp}/>
</Col> </Col>
</Row> </Row>
</Card> </Card>

@ -17,11 +17,12 @@
*/ */
import React from "react"; import React from "react";
import {Avatar, Table, Tag, Icon, message, notification} from "antd"; import {Avatar, Table, Tag, Icon, message, notification, Col} from "antd";
import axios from "axios"; import axios from "axios";
import pSBC from 'shade-blend-color'; import pSBC from 'shade-blend-color';
import "./AppsTable.css"; import "./AppsTable.css";
import {withConfigContext} from "../../../../context/ConfigContext"; import {withConfigContext} from "../../../../context/ConfigContext";
import AppDetailsDrawer from "../AppDetailsDrawer/AppDetailsDrawer";
let config = null; let config = null;
@ -95,8 +96,11 @@ const columns = [
color = defaultPlatformIcons[platform].color; color = defaultPlatformIcons[platform].color;
theme = defaultPlatformIcons[platform].theme; theme = defaultPlatformIcons[platform].theme;
} }
return (<span style={{fontSize: 20, color: color, textAlign: "center"}}><Icon type={icon} return (
theme={theme}/></span>) <span style={{fontSize: 20, color: color, textAlign: "center"}}>
<Icon type={icon} theme={theme}/>
</span>
);
} }
}, },
{ {
@ -115,7 +119,10 @@ class AppsTable extends React.Component {
this.state = { this.state = {
pagination: {}, pagination: {},
apps: [], apps: [],
filters: {} filters: {},
isDrawerVisible: false,
selectedApp: null,
selectedAppIndex: -1
}; };
config = this.props.context; config = this.props.context;
} }
@ -139,6 +146,22 @@ class AppsTable extends React.Component {
} }
} }
//handler to show app drawer
showDrawer = (app, appIndex) => {
this.setState({
isDrawerVisible: true,
selectedApp: app,
selectedAppIndex: appIndex
});
};
// handler to close the app drawer
closeDrawer = () => {
this.setState({
isDrawerVisible: false
})
};
handleTableChange = (pagination, filters, sorter) => { handleTableChange = (pagination, filters, sorter) => {
const pager = {...this.state.pagination}; const pager = {...this.state.pagination};
pager.current = pagination.current; pager.current = pagination.current;
@ -189,9 +212,7 @@ class AppsTable extends React.Component {
apps: apps, apps: apps,
pagination, pagination,
}); });
} }
}).catch((error) => { }).catch((error) => {
if (error.hasOwnProperty("response") && error.response.status === 401) { if (error.hasOwnProperty("response") && error.response.status === 401) {
message.error('You are not logged in'); message.error('You are not logged in');
@ -209,7 +230,16 @@ class AppsTable extends React.Component {
}); });
}; };
onUpdateApp = (key, value) => {
const apps = [...this.state.apps];
apps[this.state.selectedAppIndex][key]= value;
this.setState({
apps
});
};
render() { render() {
const {isDrawerVisible} = this.state;
return ( return (
<div className="apps-table"> <div className="apps-table">
<Table <Table
@ -222,11 +252,15 @@ class AppsTable extends React.Component {
onRow={(record, rowIndex) => { onRow={(record, rowIndex) => {
return { return {
onClick: event => { onClick: event => {
this.props.showDrawer(record); this.showDrawer(record, rowIndex);
}, },
}; };
}} }}/>
/> <AppDetailsDrawer
visible={isDrawerVisible}
onClose={this.closeDrawer}
app={this.state.selectedApp}
onUpdateApp={this.onUpdateApp}/>
</div> </div>
); );

@ -17,7 +17,7 @@
*/ */
import React from "react"; import React from "react";
import {Divider, Row, Col, Typography, Button, Drawer, Icon, Tooltip} from "antd"; import {Divider, Row, Col, Typography, Button, Drawer, Icon, Tooltip, Empty} from "antd";
import StarRatings from "react-star-ratings"; import StarRatings from "react-star-ratings";
import Reviews from "./review/Reviews"; import Reviews from "./review/Reviews";
import "../../../App.css"; import "../../../App.css";
@ -50,6 +50,12 @@ class ReleaseView extends React.Component {
color = defaultPlatformIcons[platform].color; color = defaultPlatformIcons[platform].color;
theme = defaultPlatformIcons[platform].theme; theme = defaultPlatformIcons[platform].theme;
} }
let metaData = [];
try{
metaData = JSON.parse(release.metaData);
}catch (e) {
}
return ( return (
<div> <div>
@ -121,6 +127,21 @@ class ReleaseView extends React.Component {
{release.description} {release.description}
</Paragraph> </Paragraph>
<Divider/> <Divider/>
<Text>META DATA</Text>
<Row>
{
metaData.map((data, index)=>{
return (
<Col key={index} lg={8} md={6} xs={24} style={{marginTop:15}}>
<Text>{data.key}</Text><br/>
<Text type="secondary">{data.value}</Text>
</Col>
)
})
}
{(metaData.length===0) && (<Text type="secondary">No meta data available.</Text>)}
</Row>
<Divider/>
<Text>REVIEWS</Text> <Text>REVIEWS</Text>
<Row> <Row>
<Col lg={18}> <Col lg={18}>

@ -17,11 +17,12 @@
*/ */
import React from "react"; import React from "react";
import {Modal, Button, Icon, notification, Spin, Tooltip, Upload, Input, Switch, Form, Divider} from 'antd'; import {Modal, Button, Icon, notification, Spin, Tooltip, Upload, Input, Switch, Form, Divider, Row, Col} from 'antd';
import axios from "axios"; import axios from "axios";
import {withConfigContext} from "../../../../context/ConfigContext"; import {withConfigContext} from "../../../../context/ConfigContext";
const {TextArea} = Input; const {TextArea} = Input;
const InputGroup = Input.Group;
const formItemLayout = { const formItemLayout = {
labelCol: { labelCol: {
@ -45,6 +46,7 @@ class EditReleaseModal extends React.Component {
screenshots: [], screenshots: [],
loading: false, loading: false,
binaryFiles: [], binaryFiles: [],
metaData: [],
formConfig: { formConfig: {
specificElements: {} specificElements: {}
} }
@ -118,6 +120,13 @@ class EditReleaseModal extends React.Component {
const {release} = this.props; const {release} = this.props;
const {formConfig} = this.state; const {formConfig} = this.state;
const {specificElements} = formConfig; const {specificElements} = formConfig;
let metaData = [];
try{
metaData =JSON.parse(release.metaData);
}catch (e) {
}
this.props.form.setFields({ this.props.form.setFields({
releaseType: { releaseType: {
@ -160,6 +169,7 @@ class EditReleaseModal extends React.Component {
this.setState({ this.setState({
visible: true, visible: true,
metaData
}); });
}; };
@ -212,7 +222,7 @@ class EditReleaseModal extends React.Component {
description: releaseDescription, description: releaseDescription,
price: (price === undefined) ? 0 : parseInt(price), price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants, isSharedWithAllTenants,
metaData: "string", metaData: JSON.stringify(this.state.metaData),
releaseType: releaseType, releaseType: releaseType,
supportedOsVersions: "4.0-10.0" supportedOsVersions: "4.0-10.0"
}; };
@ -298,9 +308,14 @@ class EditReleaseModal extends React.Component {
}); });
}; };
addNewMetaData = () => {
this.setState({
metaData: this.state.metaData.concat({'key': '', 'value': ''})
})
};
render() { render() {
const {formConfig, icons, screenshots, loading, binaryFiles} = this.state; const {formConfig, icons, screenshots, loading, binaryFiles, metaData} = this.state;
const {getFieldDecorator} = this.props.form; const {getFieldDecorator} = this.props.form;
const {isAppUpdatable} = this.props; const {isAppUpdatable} = this.props;
@ -476,6 +491,66 @@ class EditReleaseModal extends React.Component {
/> />
)} )}
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', {
rules: [{
required: true,
message: 'Please fill empty fields'
}],
initialValue: false
})(
<div>
{
metaData.map((data, index) => {
return (
<InputGroup key={index}>
<Row gutter={8}>
<Col span={10}>
<Input
placeholder="key"
value={data.key}
onChange={(e) => {
metaData[index]['key'] = e.currentTarget.value;
this.setState({
metaData
})
}}/>
</Col>
<Col span={10}>
<Input
placeholder="value"
value={data.value}
onChange={(e) => {
metaData[index].value = e.currentTarget.value;
this.setState({
metaData
});
}}/>
</Col>
<Col span={3}>
<Button type="dashed"
shape="circle"
icon="minus"
onClick={() => {
metaData.splice(index, 1);
this.setState({
metaData
});
}}/>
</Col>
</Row>
</InputGroup>
)
}
)
}
<Button type="dashed" icon="plus" onClick={this.addNewMetaData}>
Add
</Button>
</div>
)}
</Form.Item> </Form.Item>
<Divider/> <Divider/>
<Form.Item style={{float: "right", marginLeft: 8}}> <Form.Item style={{float: "right", marginLeft: 8}}>

@ -200,7 +200,7 @@ class LifeCycle extends React.Component {
visible={this.state.isReasonModalVisible} visible={this.state.isReasonModalVisible}
onOk={this.addLifeCycle} onOk={this.addLifeCycle}
onCancel={this.closeReasonModal} onCancel={this.closeReasonModal}
okText="confirm" okText="Confirm"
> >
<Text> <Text>
You are going to change the lifecycle state from,<br/> You are going to change the lifecycle state from,<br/>

@ -69,9 +69,9 @@ class AddNewAppFormComponent extends React.Component {
isError: false isError: false
}); });
const {application} = this.state; const {application} = this.state;
const {price} = application;
const {data, release} = releaseData; const {data, release} = releaseData;
const {formConfig} = this.props; const {formConfig} = this.props;
const {price} = release;
application.subMethod = (price === 0) ? "FREE" : "PAID"; application.subMethod = (price === 0) ? "FREE" : "PAID";
//add release wrapper //add release wrapper

@ -320,22 +320,6 @@ class NewAppDetailsForm extends React.Component {
</Select> </Select>
)} )}
</Form.Item> </Form.Item>
{/* //todo implement add meta data */}
{/*<Form.Item {...formItemLayout} label="Meta Data">*/}
{/*<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 style={{float: "right"}}> <Form.Item style={{float: "right"}}>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">
Next Next

@ -32,6 +32,7 @@ const formItemLayout = {
}; };
const {Option} = Select; const {Option} = Select;
const {TextArea} = Input; const {TextArea} = Input;
const InputGroup = Input.Group;
function getBase64(file) { function getBase64(file) {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -57,7 +58,8 @@ class NewAppUploadForm extends React.Component {
previewImage: '', previewImage: '',
binaryFileHelperText: '', binaryFileHelperText: '',
iconHelperText: '', iconHelperText: '',
screenshotHelperText: '' screenshotHelperText: '',
metaData: []
} }
} }
@ -88,7 +90,7 @@ class NewAppUploadForm extends React.Component {
description: releaseDescription, description: releaseDescription,
price: (price === undefined) ? 0 : parseInt(price), price: (price === undefined) ? 0 : parseInt(price),
isSharedWithAllTenants, isSharedWithAllTenants,
metaData: "string", metaData: JSON.stringify(this.state.metaData),
releaseType: releaseType releaseType: releaseType
}; };
@ -182,6 +184,12 @@ class NewAppUploadForm extends React.Component {
}); });
}; };
addNewMetaData = () => {
this.setState({
metaData: this.state.metaData.concat({'key': '', 'value': ''})
})
};
render() { render() {
const {formConfig} = this.props; const {formConfig} = this.props;
const {getFieldDecorator} = this.props.form; const {getFieldDecorator} = this.props.form;
@ -194,7 +202,8 @@ class NewAppUploadForm extends React.Component {
previewVisible, previewVisible,
binaryFileHelperText, binaryFileHelperText,
iconHelperText, iconHelperText,
screenshotHelperText screenshotHelperText,
metaData
} = this.state; } = this.state;
const uploadButton = ( const uploadButton = (
<div> <div>
@ -390,6 +399,66 @@ class NewAppUploadForm extends React.Component {
/> />
)} )}
</Form.Item>
<Form.Item {...formItemLayout} label="Meta Data">
{getFieldDecorator('meta', {
rules: [{
required: true,
message: 'Please fill empty fields'
}],
initialValue: false
})(
<div>
{
metaData.map((data, index) => {
return (
<InputGroup key={index}>
<Row gutter={8}>
<Col span={5}>
<Input
placeholder="key"
value={data.key}
onChange={(e) => {
metaData[index]['key'] = e.currentTarget.value;
this.setState({
metaData
})
}}/>
</Col>
<Col span={8}>
<Input
placeholder="value"
value={data.value}
onChange={(e) => {
metaData[index].value = e.currentTarget.value;
this.setState({
metaData
});
}}/>
</Col>
<Col span={3}>
<Button type="dashed"
shape="circle"
icon="minus"
onClick={() => {
metaData.splice(index, 1);
this.setState({
metaData
});
}}/>
</Col>
</Row>
</InputGroup>
)
}
)
}
<Button type="dashed" icon="plus" onClick={this.addNewMetaData}>
Add
</Button>
</div>
)}
</Form.Item> </Form.Item>
<Form.Item style={{float: "right", marginLeft: 8}}> <Form.Item style={{float: "right", marginLeft: 8}}>
<Button type="primary" htmlType="submit"> <Button type="primary" htmlType="submit">

@ -32,17 +32,13 @@ class Dashboard extends React.Component {
constructor(props) { constructor(props) {
super(props); super(props);
this.state = { this.state = {
routes: props.routes routes: props.routes,
};
const config = this.props.context;
this.Logo = config.theme.logo;
}
//functions for show the drawer
state = {
visible: false, visible: false,
collapsed: false collapsed: false
}; };
this.config = this.props.context;
this.Logo = this.config.theme.logo;
}
showDrawer = () => { showDrawer = () => {
this.setState({ this.setState({
@ -67,43 +63,61 @@ class Dashboard extends React.Component {
</div> </div>
<div className="web-layout"> <div className="web-layout">
<Menu <Menu
theme="light" theme="light"
mode="horizontal" mode="horizontal"
defaultSelectedKeys={['1']} defaultSelectedKeys={['1']}
style={{lineHeight: '64px'}} style={{lineHeight: '64px'}}>
>
<Menu.Item key="1"><Link to="/publisher/apps"><Icon <Menu.Item key="1"><Link to="/publisher/apps"><Icon
type="appstore"/>Apps</Link></Menu.Item> type="appstore"/>Apps</Link></Menu.Item>
<SubMenu <SubMenu
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="plus"/> <Icon type="plus"/>
Add New App Add New App
</span> </span>
} }>
> <Menu.Item key="setting:1">
<Menu.Item key="setting:1"><Link to="/publisher/add-new-app/public">Public <Link to="/publisher/add-new-app/public">Public APP</Link>
APP</Link></Menu.Item> </Menu.Item>
<Menu.Item key="setting:2"><Link to="/publisher/add-new-app/enterprise">Enterprise <Menu.Item key="setting:2">
APP</Link></Menu.Item> <Link to="/publisher/add-new-app/enterprise">Enterprise APP</Link>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web </Menu.Item>
Clip</Link></Menu.Item> <Menu.Item key="setting:3">
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/custom-app">Custom <Link to="/publisher/add-new-app/web-clip">Web Clip</Link>
App</Link></Menu.Item> </Menu.Item>
<Menu.Item key="setting:4">
<Link to="/publisher/add-new-app/custom-app">Custom App</Link>
</Menu.Item>
</SubMenu>
<SubMenu
title={
<span className="submenu-title-wrapper">
<Icon type="control"/>Manage
</span>
}>
<Menu.Item key="manage">
<Link to="/publisher/manage">
<Icon type="setting"/> General
</Link>
</Menu.Item>
{this.config.androidEnterpriseToken != null && (
<Menu.Item key="manage-android-enterprise">
<Link to="/publisher/manage/android-enterprise">
<Icon type="android" theme="filled"/> Android Enterprise
</Link>
</Menu.Item>
)}
</SubMenu> </SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon
type="control"/>Manage</Link></Menu.Item>
<SubMenu className="profile" <SubMenu className="profile"
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="user"/> <Icon type="user"/>Profile
Profile
</span> </span>
} }>
>
<Logout/> <Logout/>
</SubMenu> </SubMenu>
</Menu> </Menu>
@ -118,56 +132,63 @@ class Dashboard extends React.Component {
</Button> </Button>
</div> </div>
<Drawer <Drawer
title={<Link to="/publisher/apps"><img alt="logo" src={this.Logo} style={{marginLeft: 30}} title={
width={"60%"}/></Link>} <Link to="/publisher/apps">
<img alt="logo"
src={this.Logo}
style={{marginLeft: 30}}
width={"60%"}/>
</Link>
}
placement="left" placement="left"
closable={false} closable={false}
onClose={this.onClose} onClose={this.onClose}
visible={this.state.visible} visible={this.state.visible}
getContainer={false} getContainer={false}
style={{position: 'absolute'}} style={{position: 'absolute'}}>
>
<Menu <Menu
theme="light" theme="light"
mode="inline" mode="inline"
defaultSelectedKeys={['1']} defaultSelectedKeys={['1']}
style={{lineHeight: '64px', width: 231}} style={{lineHeight: '64px', width: 231}}>
>
<Menu.Item key="1"><Link to="/publisher/apps"><Icon <Menu.Item key="1"><Link to="/publisher/apps"><Icon
type="appstore"/>Apps</Link></Menu.Item> type="appstore"/>Apps</Link></Menu.Item>
<SubMenu <SubMenu
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="plus"/> <Icon type="plus"/>Add New App
Add New App
</span> </span>
} }>
> <Menu.Item key="setting:1">
<Menu.Item key="setting:1"><Link to="/publisher/add-new-app/public">Public <Link to="/publisher/add-new-app/public">Public APP</Link>
APP</Link></Menu.Item> </Menu.Item>
<Menu.Item key="setting:2"><Link to="/publisher/add-new-app/enterprise">Enterprise <Menu.Item key="setting:2">
APP</Link></Menu.Item> <Link to="/publisher/add-new-app/enterprise">Enterprise APP</Link>
<Menu.Item key="setting:3"><Link to="/publisher/add-new-app/web-clip">Web </Menu.Item>
Clip</Link></Menu.Item> <Menu.Item key="setting:3">
<Menu.Item key="setting:4"><Link to="/publisher/add-new-app/custom-app">Custom <Link to="/publisher/add-new-app/web-clip">Web Clip</Link>
App</Link></Menu.Item> </Menu.Item>
<Menu.Item key="setting:4">
<Link to="/publisher/add-new-app/custom-app">Custom App</Link>
</Menu.Item>
</SubMenu> </SubMenu>
<Menu.Item key="2"><Link to="/publisher/manage"><Icon <Menu.Item key="2">
type="control"/>Manage</Link></Menu.Item> <Link to="/publisher/manage">
<Icon type="control"/>Manage
</Link>
</Menu.Item>
</Menu> </Menu>
</Drawer> </Drawer>
<Menu <Menu
mode="horizontal" mode="horizontal"
defaultSelectedKeys={['1']} defaultSelectedKeys={['1']}
style={{lineHeight: '63px', position: 'fixed', marginLeft: '80%'}} style={{lineHeight: '63px', position: 'fixed', marginLeft: '80%'}}>
>
<SubMenu <SubMenu
title={ title={
<span className="submenu-title-wrapper"> <span className="submenu-title-wrapper">
<Icon type="user"/> <Icon type="user"/>
</span> </span>
} }>
>
<Logout/> <Logout/>
</SubMenu> </SubMenu>
</Menu> </Menu>

@ -18,7 +18,7 @@
import React from "react"; import React from "react";
import '../../../../App.css'; import '../../../../App.css';
import {Typography, Row, Col, message, Card, notification} from "antd"; import {Typography, Row, Col, message, Card, notification, Skeleton} from "antd";
import axios from 'axios'; import axios from 'axios';
import ReleaseView from "../../../../components/apps/release/ReleaseView"; import ReleaseView from "../../../../components/apps/release/ReleaseView";
import LifeCycle from "../../../../components/apps/release/lifeCycle/LifeCycle"; import LifeCycle from "../../../../components/apps/release/lifeCycle/LifeCycle";
@ -132,9 +132,9 @@ class Release extends React.Component {
}; };
render() { render() {
const {app, release, currentLifecycleStatus, lifecycle} = this.state; const {app, release, currentLifecycleStatus, lifecycle, loading} = this.state;
if (release == null) { if (release == null && loading === false) {
return ( return (
<div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}> <div style={{background: '#f0f2f5', padding: 24, minHeight: 780}}>
<Title level={3}>No Apps Found</Title> <Title level={3}>No Apps Found</Title>
@ -149,23 +149,31 @@ class Release extends React.Component {
<Row style={{padding: 10}}> <Row style={{padding: 10}}>
<Col lg={16} md={24} style={{padding: 3}}> <Col lg={16} md={24} style={{padding: 3}}>
<Card> <Card>
<Skeleton loading={loading} avatar={{size: 'large'}} active paragraph={{rows: 18}}>
{(release !== null) && (
<ReleaseView <ReleaseView
app={app} app={app}
release={release} release={release}
currentLifecycleStatus={currentLifecycleStatus} currentLifecycleStatus={currentLifecycleStatus}
lifecycle={lifecycle} lifecycle={lifecycle}
updateRelease={this.updateRelease} updateRelease={this.updateRelease}
/> />)
}
</Skeleton>
</Card> </Card>
</Col> </Col>
<Col lg={8} md={24} style={{padding: 3}}> <Col lg={8} md={24} style={{padding: 3}}>
<Card lg={8} md={24}> <Card lg={8} md={24}>
<Skeleton loading={loading} active paragraph={{rows: 8}}>
{(release !== null) && (
<LifeCycle <LifeCycle
uuid={release.uuid} uuid={release.uuid}
currentStatus={release.currentStatus.toUpperCase()} currentStatus={release.currentStatus.toUpperCase()}
changeCurrentLifecycleStatus={this.changeCurrentLifecycleStatus} changeCurrentLifecycleStatus={this.changeCurrentLifecycleStatus}
lifecycle={lifecycle} lifecycle={lifecycle}
/> />)
}
</Skeleton>
</Card> </Card>
</Col> </Col>
</Row> </Row>

@ -98,6 +98,14 @@ class ReleaseView extends React.Component {
render() { render() {
const {app,deviceType} = this.props; const {app,deviceType} = this.props;
const release = app.applicationReleases[0]; const release = app.applicationReleases[0];
let metaData = [];
try{
metaData = JSON.parse(release.metaData);
}catch (e) {
}
return ( return (
<div> <div>
<AppInstallModal <AppInstallModal
@ -141,6 +149,21 @@ class ReleaseView extends React.Component {
{release.description} {release.description}
</Paragraph> </Paragraph>
<Divider/> <Divider/>
<Text>META DATA</Text>
<Row>
{
metaData.map((data, index)=>{
return (
<Col key={index} lg={8} md={6} xs={24} style={{marginTop:15}}>
<Text>{data.key}</Text><br/>
<Text type="secondary">{data.value}</Text>
</Col>
)
})
}
{(metaData.length===0) && (<Text type="secondary">No meta data available.</Text>)}
</Row>
<Divider/>
<CurrentUsersReview uuid={release.uuid}/> <CurrentUsersReview uuid={release.uuid}/>
<Divider dashed={true}/> <Divider dashed={true}/>
<Text>REVIEWS</Text> <Text>REVIEWS</Text>

Loading…
Cancel
Save